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