|
|
1.1 root 1: # include <pv.h>
2: # include <ingres.h>
3: # include <access.h>
4: # include <aux.h>
5: # include <catalog.h>
6: # include <symbol.h>
7: # include <lock.h>
8: # include <func.h>
9: # include <sccs.h>
10: # include <errors.h>
11:
12: SCCSID(@(#)create.c 8.6 2/8/85)
13:
14: extern short tTdbu[];
15: extern int create();
16: extern int null_fn();
17:
18: struct fn_def CreateFn =
19: {
20: "CREATE",
21: create,
22: null_fn,
23: null_fn,
24: NULL,
25: 0,
26: tTdbu,
27: 100,
28: 'Z',
29: 0
30: };
31:
32: /*
33: ** CREATE -- create new relation
34: **
35: ** This module creates a brand new relation in the current
36: ** directory (database). The relation is always created as
37: ** a paged heap. It may not redefine an existing relation,
38: ** or rename a system catalog.
39: **
40: ** Trace Flags:
41: ** 31
42: */
43:
44:
45: struct domain
46: {
47: char *name;
48: char frmt;
49: char frml;
50: };
51:
52: /*
53: ** CREATE -- create new relation
54: **
55: ** This routine is the driver for the create module.
56: **
57: ** Parameters:
58: ** pc -- parameter count
59: ** pv -- parameter vector:
60: ** 0 -- relation status (relstat) -- stored into
61: ** the 'relstat' field in the relation
62: ** relation, and used to determine the
63: ** caller. Interesting bits are:
64: **
65: ** S_INDEX -- means called by the index
66: ** processor. If set, the 'relindxd'
67: ** field will also be set to -1
68: ** (SECINDEX) to indicate that this
69: ** relation is a secondary index.
70: ** S_CATALOG -- this is a system catalog.
71: ** If set, this create was called
72: ** from creatdb, and the physical
73: ** file is not created. Also, the
74: ** expiration date is set infinite.
75: ** S_VIEW -- this is a view. Create has
76: ** been called by the 'define'
77: ** statement, rather than the
78: ** 'create' statement. The physical
79: ** file is not created.
80: **
81: ** 1 -- relation name.
82: ** 2 -- attname1
83: ** 3 -- format1
84: ** 4, etc -- attname, format pairs.
85: **
86: ** Returns:
87: ** zero -- successful create.
88: ** else -- failure somewhere.
89: **
90: ** Side Effects:
91: ** A relation is created (this is a side effect?). This
92: ** means entries in the 'relation' and 'attribute' cata-
93: ** logs, and (probably) a physical file somewhere, with
94: ** one page already in it.
95: **
96: ** Trace Flags:
97: ** 31
98: */
99:
100: create(pc, pv)
101: int pc;
102: PARM pv[];
103: {
104: register PARM *pp;
105: register int i;
106: int bad;
107: struct domain domain[MAXDOM];
108: struct domain *dom;
109: char *relname, tempname[MAXNAME+3];
110: struct tup_id tid;
111: struct relation rel, key;
112: struct attribute att;
113: DESC desr;
114: extern char *Usercode;
115: extern DESC Reldes, Attdes;
116: extern int errno;
117: register int relstat;
118: long temptid;
119: long npages;
120: int fdes;
121: bool internal;
122:
123: # ifdef xZTR1
124: if (tTf(31, -1))
125: {
126: printf("creating %s\n", pv[1].pv_val.pv_str);
127: }
128: # endif
129: pp = pv;
130: relstat = oatoi(pp[0].pv_val.pv_str);
131: /*
132: ** If this database has query modification, then default
133: ** to denial on all user relations.
134: ** (Since views cannot be protected, this doesn't apply to them)
135: */
136: if ((Admin.adhdr.adflags & A_QRYMOD) && ((relstat & (S_VIEW || S_CATALOG)) == 0))
137: relstat |= (S_PROTALL | S_PROTRET);
138: relname = (++pp)->pv_val.pv_str;
139: internal = bequal(relname, "_SYS", 4);
140: ingresname(relname, Usercode, rel.relid);
141: bmove(rel.relid, att.attrelid, MAXNAME + 2);
142: opencatalog("relation", OR_WRITE);
143:
144: /* check for duplicate relation name */
145: if ((relstat & S_CATALOG) == 0)
146: {
147: if (openr(&desr, OR_RELTID, relname) == 0)
148: {
149: if (bequal(desr.reldum.relowner, rel.relowner, 2))
150: {
151: return (error(DUPRELNAME, relname, 0)); /* bad relname */
152: }
153: if (desr.reldum.relstat & S_CATALOG)
154: {
155: return (error(SYSRELNAME, relname, 0)); /* attempt to rename system catalog */
156: }
157: }
158: }
159: opencatalog("attribute", OR_WRITE);
160:
161: /* initialize structures for system catalogs */
162: initstructs(&att, &rel);
163: rel.relstat = relstat;
164: if ((relstat & S_CATALOG) != 0)
165: rel.relsave = 0;
166: else if ((relstat & S_INDEX) != 0)
167: rel.relindxd = SECINDEX;
168:
169: # ifdef xZTR3
170: if (tTf(31, 2))
171: {
172: printf("\nrel->relprim = %D\n", rel.relprim);
173: printup(&Reldes, &rel);
174: }
175: # endif
176:
177: /* check attributes */
178: pp++;
179: for (i = pc - 2; i > 0; i -= 2)
180: {
181: bad = chk_att(&rel, pp[0].pv_val.pv_str, pp[1].pv_val.pv_str, domain, internal);
182: if (bad != 0)
183: {
184: return (error(bad, relname, pp[0].pv_val.pv_str, pp[1].pv_val.pv_str, 0));
185: }
186: pp += 2;
187: }
188:
189: /*
190: ** Create files if appropriate. Concurrency control for
191: ** the create depends on the actual file. To prevent
192: ** to users with the same usercode from creating the
193: ** same relation at the same time, their is check
194: ** on the existence of the file. The important events are
195: ** (1) if a tuple exists in the relation relation then
196: ** the relation really exists. (2) if the file exists then
197: ** the relation is being created but will not exist for
198: ** use until the relation relation tuple is present.
199: ** For VIEWS, the file is used for concurrency control
200: ** during the create but is removed afterwards.
201: */
202: if ((relstat & S_CATALOG) == 0)
203: {
204: /* for non system named temporary relations
205: ** set a critical section lock while checking the
206: ** existence of a file. If it exists, error return(DUPRELNAME)
207: ** else create file.
208: */
209: temptid = 0;
210: if (Lockrel && (!bequal(rel.relid,"_SYS",4)))
211: {
212: temptid = -1;
213: setcsl(temptid); /* set critical section lock */
214: if ((fdes = open(rel.relid,O_RDONLY)) >= 0)
215: {
216: /* file already exists */
217: close(fdes);
218: unlcs(temptid); /* release critical section lock */
219: return (error(DUPRELNAME, relname, 0));
220: }
221: errno = 0; /* file doesn't exist */
222: }
223: ingresname(rel.relid, rel.relowner, tempname);
224: desr.relfp = creat(tempname, FILEMODE);
225: if (temptid != 0)
226: unlcs(temptid); /* release critical section lock */
227: if (desr.relfp < 0)
228: syserr("create: creat %s", rel.relid);
229: desr.reltid.ltid = -1L; /* init reltid to unused */
230: if ((relstat & S_VIEW) == 0)
231: {
232: npages = 1;
233: if (i = formatpg(&desr, npages))
234: syserr("create: formatpg %d", i);
235: }
236:
237: close(desr.relfp);
238: }
239:
240: /* insert attributes into attribute relation */
241: pp = pv + 2;
242: dom = domain;
243: for (i = pc - 2; i > 0; i -= 2)
244: {
245: ins_att(&Attdes, &att, dom++);
246: pp += 2;
247: }
248:
249: /*
250: ** Flush the attributes. This is necessary for recovery reasons.
251: ** If for some reason the relation relation is flushed and the
252: ** machine crashes before the attributes are flushed, then recovery
253: ** will not detect the error.
254: ** The call below cannot be a "noclose" without major changes to
255: ** creatdb.
256: */
257: if (i = pageflush(0))
258: syserr("create:flush att %d", i);
259:
260: if (i = insert(&Reldes, &tid, &rel, FALSE))
261: syserr("create: insert(rel, %.14s) %d", rel.relid, i);
262:
263: if (relstat & S_VIEW)
264: unlink(tempname);
265: return (0);
266: }
267:
268:
269:
270: /*
271: ** CHK_ATT -- check attribute for validity
272: **
273: ** The attribute is checked to see if
274: ** * it's name is ok (within MAXNAME bytes)
275: ** * it is not a duplicate name
276: ** * the format specified is legal
277: ** * there are not a ridiculous number of attributes
278: ** (ridiculous being defined as anything over MAXDOM - 1)
279: ** * the tuple is not too wide to fit on one page
280: **
281: ** Parameters:
282: ** rel -- relation relation tuple for this relation.
283: ** attname -- tentative name of attribute.
284: ** format -- tentative format for attribute.
285: ** domain -- a 'struct domain' used to determine dupli-
286: ** cation, and to store the resulting name and
287: ** format in.
288: **
289: ** Returns:
290: ** zero -- OK
291: ** 5104 -- bad attribute name.
292: ** 5105 -- duplicate attribute name.
293: ** 5106 -- bad attribute format.
294: ** 5107 -- too many attributes.
295: ** 5108 -- tuple too wide.
296: **
297: ** Side Effects:
298: ** 'rel' has the relatts and relwid fields updated to
299: ** reflect the new attribute.
300: **
301: ** Trace Flags:
302: ** 31
303: */
304:
305: chk_att(rel, attname, format, domain, internal)
306: struct relation *rel;
307: char *attname, *format;
308: struct domain domain[];
309: bool internal;
310: {
311: register int i;
312: register struct relation *r;
313:
314: r = rel;
315:
316: # ifdef xZTR3
317: if (tTf(31, 1))
318: printf("chk_att %s %s\n", attname, format);
319: # endif
320:
321: if (sequal(attname, "tid"))
322: return (BADATTRNAME); /* bad attribute name */
323: if ((i = dup_att(attname, r->relatts, domain)) < 0)
324: return (DUPATTRNAME); /* duplicate attribute */
325: if (formck(format, &domain[i], internal))
326: return (BADATTRFORMAT); /* bad attribute format */
327: r->relatts++;
328: r->relwid += domain[i].frml & I1MASK;
329: if (r->relatts >= MAXDOM)
330: return (TOOMANYDOMS); /* too many attributes */
331: if (r->relwid > MAXTUP && (r->relstat & S_VIEW) == 0)
332: return (RELTOOWIDE); /* tuple too wide */
333: return (0);
334: }
335:
336:
337:
338:
339: /*
340: ** INS_ATT -- insert attribute into attribute relation
341: **
342: ** Parameters:
343: ** des -- relation descriptor for the attribute catalog.
344: ** att -- attribute tuple, preinitialized with all sorts
345: ** of good stuff (everything except 'attname',
346: ** 'attfrmt', and 'attfrml'; 'attid' and 'attoff'
347: ** must be initialized to zero before this routine
348: ** is called the first time.
349: ** dom -- 'struct domain' -- the information needed about
350: ** each domain.
351: **
352: ** Returns:
353: ** none
354: **
355: ** Side Effects:
356: ** The 'att' tuple is updated in the obvious ways.
357: ** A tuple is added to the 'attribute' catalog.
358: **
359: ** Trace Flags:
360: ** none currently
361: */
362:
363: ins_att(des, att, dom)
364: DESC *des;
365: struct attribute *att;
366: struct domain *dom;
367: {
368: register int i;
369: struct tup_id tid;
370: register struct domain *d;
371:
372: d = dom;
373:
374: pmove(d->name, att->attname, MAXNAME, ' ');
375: att->attfrmt = d->frmt;
376: att->attfrml = d->frml;
377: att->attid++;
378: if (insert(des, &tid, att, FALSE))
379: syserr("ins_att: insert(att, %s)", d->name);
380: att->attoff += att->attfrml & I1MASK;
381: }
382:
383:
384:
385:
386: /*
387: ** DUP_ATT -- check for duplicate attribute
388: **
389: ** The attribute named 'name' is inserted into the 'attalias'
390: ** vector at position 'count'. 'Count' should be the count
391: ** of existing entries in 'attalias'. 'Attalias' is checked
392: ** to see that 'name' is not already present.
393: **
394: ** Parameters:
395: ** name -- the name of the attribute.
396: ** count -- the count of attributes so far.
397: ** domain -- 'struct domain' -- the list of domains
398: ** so far, names and types.
399: **
400: ** Returns:
401: ** -1 -- attribute name is a duplicate.
402: ** else -- index in 'domain' for this attribute (also
403: ** the attid).
404: **
405: ** Side Effects:
406: ** The 'domain' vector is extended.
407: **
408: ** Trace Flags:
409: ** none
410: */
411:
412: dup_att(name, count, domain)
413: char *name;
414: int count;
415: struct domain domain[];
416: {
417: register struct domain *d;
418: register int lim;
419: register int i;
420:
421: lim = count;
422: d = domain;
423:
424: for (i = 0; i < lim; i++)
425: if (sequal(name, d++->name))
426: return (-1);
427: if (count < MAXDOM)
428: d->name = name;
429: return (i);
430: }
431:
432:
433:
434:
435: /*
436: ** INITSTRUCTS -- initialize relation and attribute tuples
437: **
438: ** Structures containing images of 'relation' relation and
439: ** 'attribute' relation tuples are initialized with all the
440: ** information initially needed to do the create. Frankly,
441: ** the only interesting part is the the expiration date
442: ** computation; longconst(9, 14976) is exactly the number
443: ** of seconds in one week.
444: **
445: ** Parameters:
446: ** att -- attribute relation tuple.
447: ** rel -- relation relation tuple.
448: **
449: ** Returns:
450: ** none
451: **
452: ** Side Effects:
453: ** 'att' and 'rel' are initialized.
454: **
455: ** Requires:
456: ** time -- to get the current date.
457: **
458: ** Called By:
459: ** create
460: **
461: ** Trace Flags:
462: ** none
463: **
464: ** Diagnostics:
465: ** none
466: **
467: ** Syserrs:
468: ** none
469: **
470: ** History:
471: ** 2/27/78 (eric) -- documented.
472: */
473:
474: initstructs(att, rel)
475: register struct attribute *att;
476: register struct relation *rel;
477: {
478: /* setup expiration date (today + one week) */
479: time(&rel->relstamp);
480: rel->relsave = rel->relstamp + 604800L;
481: rel->relfree = 0;
482: rel->reltups = 0;
483: rel->relatts = 0;
484: rel->relwid = 0;
485: rel->relprim = 1;
486: rel->relspec = M_HEAP;
487: rel->relindxd = 0;
488: rel->reldim = 0;
489: att->attxtra = 0;
490: att->attid = 0;
491: att->attoff = 0;
492: }
493:
494:
495:
496: /*
497: ** CHECK ATTRIBUTE FORMAT AND CONVERT
498: **
499: ** The string 'a' is checked for a valid attribute format
500: ** and is converted to internal form.
501: **
502: ** zero is returned if the format is good; one is returned
503: ** if it is bad. If it is bad, the conversion into a is not
504: ** made.
505: **
506: ** A format of CHAR can be length zero only if this
507: ** create was generated internally.
508: */
509:
510: formck(a, dom, internal)
511: char *a;
512: struct domain *dom;
513: bool internal;
514: {
515: int len;
516: register int i;
517: char c;
518: register char *p;
519: register struct domain *d;
520:
521: p = a;
522: c = *p++;
523: d = dom;
524:
525: len = atoi(p);
526: i = len;
527:
528: switch (c)
529: {
530:
531: case INT:
532: if (i == 1 || i == 2 || i == 4)
533: {
534: d->frmt = INT;
535: d->frml = i;
536: return (0);
537: }
538: return (1);
539:
540: case FLOAT:
541: if (i == 4 || i == 8)
542: {
543: d->frmt = FLOAT;
544: d->frml = i;
545: return (0);
546: }
547: return (1);
548:
549: /* note: should disallow c0 from user (but needed internally) */
550: case CHAR:
551: if (i > MAXFIELD || i < 0 || (i == 0 && !internal))
552: return (1);
553: d->frmt = CHAR;
554: d->frml = i;
555: return (0);
556: }
557: return (1);
558:
559: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.