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: }