creatinh.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:13k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * creatinh.c
  4.  *   POSTGRES create/destroy relation with inheritance utility code.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/commands/creatinh.c,v 1.41.2.1 1999/08/02 05:56:58 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "access/heapam.h"
  16. #include "catalog/catname.h"
  17. #include "catalog/heap.h"
  18. #include "catalog/pg_inherits.h"
  19. #include "catalog/pg_ipl.h"
  20. #include "catalog/pg_type.h"
  21. #include "commands/creatinh.h"
  22. #include "utils/syscache.h"
  23. /* ----------------
  24.  * local stuff
  25.  * ----------------
  26.  */
  27. static int checkAttrExists(char *attributeName,
  28. char *attributeType, List *schema);
  29. static List *MergeAttributes(List *schema, List *supers, List **supconstr);
  30. static void StoreCatalogInheritance(Oid relationId, List *supers);
  31. /* ----------------------------------------------------------------
  32.  * DefineRelation
  33.  * Creates a new relation.
  34.  * ----------------------------------------------------------------
  35.  */
  36. void
  37. DefineRelation(CreateStmt *stmt, char relkind)
  38. {
  39. char    *relname = palloc(NAMEDATALEN);
  40. List    *schema = stmt->tableElts;
  41. int numberOfAttributes;
  42. Oid relationId;
  43. List    *inheritList = NULL;
  44. TupleDesc descriptor;
  45. List    *constraints;
  46. if (strlen(stmt->relname) >= NAMEDATALEN)
  47. elog(ERROR, "the relation name %s is >= %d characters long", stmt->relname,
  48.  NAMEDATALEN);
  49. StrNCpy(relname, stmt->relname, NAMEDATALEN); /* make full length for
  50.  * copy */
  51. /* ----------------
  52.  * Handle parameters
  53.  * XXX parameter handling missing below.
  54.  * ----------------
  55.  */
  56. inheritList = stmt->inhRelnames;
  57. /* ----------------
  58.  * generate relation schema, including inherited attributes.
  59.  * ----------------
  60.  */
  61. schema = MergeAttributes(schema, inheritList, &constraints);
  62. constraints = nconc(constraints, stmt->constraints);
  63. numberOfAttributes = length(schema);
  64. if (numberOfAttributes <= 0)
  65. {
  66. elog(ERROR, "DefineRelation: %s",
  67.  "please inherit from a relation or define an attribute");
  68. }
  69. /* ----------------
  70.  * create a relation descriptor from the relation schema
  71.  * and create the relation.
  72.  * ----------------
  73.  */
  74. descriptor = BuildDescForRelation(schema, relname);
  75. if (constraints != NIL)
  76. {
  77. List    *entry;
  78. int nconstr = length(constraints),
  79. ncheck = 0,
  80. i;
  81. ConstrCheck *check = (ConstrCheck *) palloc(nconstr * sizeof(ConstrCheck));
  82. foreach(entry, constraints)
  83. {
  84. Constraint *cdef = (Constraint *) lfirst(entry);
  85. if (cdef->contype == CONSTR_CHECK)
  86. {
  87. if (cdef->name != NULL)
  88. {
  89. for (i = 0; i < ncheck; i++)
  90. {
  91. if (strcmp(check[i].ccname, cdef->name) == 0)
  92. elog(ERROR,
  93.  "DefineRelation: name (%s) of CHECK constraint duplicated",
  94.  cdef->name);
  95. }
  96. check[ncheck].ccname = cdef->name;
  97. }
  98. else
  99. {
  100. check[ncheck].ccname = (char *) palloc(NAMEDATALEN);
  101. snprintf(check[ncheck].ccname, NAMEDATALEN, "$%d", ncheck + 1);
  102. }
  103. check[ncheck].ccbin = NULL;
  104. check[ncheck].ccsrc = (char *) cdef->def;
  105. ncheck++;
  106. }
  107. }
  108. if (ncheck > 0)
  109. {
  110. if (ncheck < nconstr)
  111. check = (ConstrCheck *) repalloc(check, ncheck * sizeof(ConstrCheck));
  112. if (descriptor->constr == NULL)
  113. {
  114. descriptor->constr = (TupleConstr *) palloc(sizeof(TupleConstr));
  115. descriptor->constr->num_defval = 0;
  116. descriptor->constr->has_not_null = false;
  117. }
  118. descriptor->constr->num_check = ncheck;
  119. descriptor->constr->check = check;
  120. }
  121. }
  122. relationId = heap_create_with_catalog(relname, descriptor,
  123.   relkind, stmt->istemp);
  124. StoreCatalogInheritance(relationId, inheritList);
  125. }
  126. /*
  127.  * RemoveRelation
  128.  * Deletes a new relation.
  129.  *
  130.  * Exceptions:
  131.  * BadArg if name is invalid.
  132.  *
  133.  * Note:
  134.  * If the relation has indices defined on it, then the index relations
  135.  * themselves will be destroyed, too.
  136.  */
  137. void
  138. RemoveRelation(char *name)
  139. {
  140. AssertArg(name);
  141. heap_destroy_with_catalog(name);
  142. }
  143. /*
  144.  * MergeAttributes
  145.  * Returns new schema given initial schema and supers.
  146.  *
  147.  *
  148.  * 'schema' is the column/attribute definition for the table. (It's a list
  149.  * of ColumnDef's.) It is destructively changed.
  150.  * 'inheritList' is the list of inherited relations (a list of Value(str)'s).
  151.  *
  152.  * Notes:
  153.  *   The order in which the attributes are inherited is very important.
  154.  *   Intuitively, the inherited attributes should come first. If a table
  155.  *   inherits from multiple parents, the order of those attributes are
  156.  *   according to the order of the parents specified in CREATE TABLE.
  157.  *
  158.  *   Here's an example:
  159.  *
  160.  * create table person (name text, age int4, location point);
  161.  * create table emp (salary int4, manager text) inherits(person);
  162.  * create table student (gpa float8) inherits (person);
  163.  * create table stud_emp (percent int4) inherits (emp, student);
  164.  *
  165.  *   the order of the attributes of stud_emp is as follow:
  166.  *
  167.  *
  168.  * person {1:name, 2:age, 3:location}
  169.  * /  
  170.  *    {6:gpa} student   emp {4:salary, 5:manager}
  171.  *  /
  172.  *    stud_emp {7:percent}
  173.  */
  174. static List *
  175. MergeAttributes(List *schema, List *supers, List **supconstr)
  176. {
  177. List    *entry;
  178. List    *inhSchema = NIL;
  179. List    *constraints = NIL;
  180. /*
  181.  * Validates that there are no duplications. Validity checking of
  182.  * types occurs later.
  183.  */
  184. foreach(entry, schema)
  185. {
  186. List    *rest;
  187. ColumnDef  *coldef = lfirst(entry);
  188. foreach(rest, lnext(entry))
  189. {
  190. /*
  191.  * check for duplicated relation names
  192.  */
  193. ColumnDef  *restdef = lfirst(rest);
  194. if (!strcmp(coldef->colname, restdef->colname))
  195. {
  196. elog(ERROR, "attribute '%s' duplicated",
  197.  coldef->colname);
  198. }
  199. }
  200. }
  201. foreach(entry, supers)
  202. {
  203. List    *rest;
  204. foreach(rest, lnext(entry))
  205. {
  206. if (!strcmp(strVal(lfirst(entry)), strVal(lfirst(rest))))
  207. {
  208. elog(ERROR, "relation '%s' duplicated",
  209.  strVal(lfirst(entry)));
  210. }
  211. }
  212. }
  213. /*
  214.  * merge the inherited attributes into the schema
  215.  */
  216. foreach(entry, supers)
  217. {
  218. char    *name = strVal(lfirst(entry));
  219. Relation relation;
  220. List    *partialResult = NIL;
  221. AttrNumber attrno;
  222. TupleDesc tupleDesc;
  223. TupleConstr *constr;
  224. relation = heap_openr(name);
  225. if (relation == NULL)
  226. {
  227. elog(ERROR,
  228.  "MergeAttr: Can't inherit from non-existent superclass '%s'", name);
  229. }
  230. if (relation->rd_rel->relkind == 'S')
  231. elog(ERROR, "MergeAttr: Can't inherit from sequence superclass '%s'", name);
  232. tupleDesc = RelationGetDescr(relation);
  233. constr = tupleDesc->constr;
  234. for (attrno = relation->rd_rel->relnatts - 1; attrno >= 0; attrno--)
  235. {
  236. Form_pg_attribute attribute = tupleDesc->attrs[attrno];
  237. char    *attributeName;
  238. char    *attributeType;
  239. HeapTuple tuple;
  240. ColumnDef  *def;
  241. TypeName   *typename;
  242. /*
  243.  * form name, type and constraints
  244.  */
  245. attributeName = (attribute->attname).data;
  246. tuple = SearchSysCacheTuple(TYPOID,
  247.    ObjectIdGetDatum(attribute->atttypid),
  248. 0, 0, 0);
  249. Assert(HeapTupleIsValid(tuple));
  250. attributeType = (((Form_pg_type) GETSTRUCT(tuple))->typname).data;
  251. /*
  252.  * check validity
  253.  *
  254.  */
  255. if (checkAttrExists(attributeName, attributeType, inhSchema) ||
  256. checkAttrExists(attributeName, attributeType, schema))
  257. {
  258. /*
  259.  * this entry already exists
  260.  */
  261. continue;
  262. }
  263. /*
  264.  * add an entry to the schema
  265.  */
  266. def = makeNode(ColumnDef);
  267. typename = makeNode(TypeName);
  268. def->colname = pstrdup(attributeName);
  269. typename->name = pstrdup(attributeType);
  270. typename->typmod = attribute->atttypmod;
  271. def->typename = typename;
  272. def->is_not_null = attribute->attnotnull;
  273. def->defval = NULL;
  274. if (attribute->atthasdef)
  275. {
  276. AttrDefault *attrdef = constr->defval;
  277. int i;
  278. Assert(constr != NULL && constr->num_defval > 0);
  279. for (i = 0; i < constr->num_defval; i++)
  280. {
  281. if (attrdef[i].adnum != attrno + 1)
  282. continue;
  283. def->defval = pstrdup(attrdef[i].adsrc);
  284. break;
  285. }
  286. Assert(def->defval != NULL);
  287. }
  288. partialResult = lcons(def, partialResult);
  289. }
  290. if (constr && constr->num_check > 0)
  291. {
  292. ConstrCheck *check = constr->check;
  293. int i;
  294. for (i = 0; i < constr->num_check; i++)
  295. {
  296. Constraint *cdef = (Constraint *) makeNode(Constraint);
  297. cdef->contype = CONSTR_CHECK;
  298. if (check[i].ccname[0] == '$')
  299. cdef->name = NULL;
  300. else
  301. cdef->name = pstrdup(check[i].ccname);
  302. cdef->def = (void *) pstrdup(check[i].ccsrc);
  303. constraints = lappend(constraints, cdef);
  304. }
  305. }
  306. /*
  307.  * iteration cleanup and result collection
  308.  */
  309. heap_close(relation);
  310. /*
  311.  * wants the inherited schema to appear in the order they are
  312.  * specified in CREATE TABLE
  313.  */
  314. inhSchema = nconc(inhSchema, partialResult);
  315. }
  316. /*
  317.  * put the inherited schema before our the schema for this table
  318.  */
  319. schema = nconc(inhSchema, schema);
  320. *supconstr = constraints;
  321. return schema;
  322. }
  323. /*
  324.  * StoreCatalogInheritance
  325.  * Updates the system catalogs with proper inheritance information.
  326.  */
  327. static void
  328. StoreCatalogInheritance(Oid relationId, List *supers)
  329. {
  330. Relation relation;
  331. TupleDesc desc;
  332. int16 seqNumber;
  333. List    *entry;
  334. List    *idList;
  335. HeapTuple tuple;
  336. /* ----------------
  337.  * sanity checks
  338.  * ----------------
  339.  */
  340. AssertArg(OidIsValid(relationId));
  341. if (supers == NIL)
  342. return;
  343. /* ----------------
  344.  * Catalog INHERITS information.
  345.  * ----------------
  346.  */
  347. relation = heap_openr(InheritsRelationName);
  348. desc = RelationGetDescr(relation);
  349. seqNumber = 1;
  350. idList = NIL;
  351. foreach(entry, supers)
  352. {
  353. Datum datum[Natts_pg_inherits];
  354. char nullarr[Natts_pg_inherits];
  355. tuple = SearchSysCacheTuple(RELNAME,
  356.   PointerGetDatum(strVal(lfirst(entry))),
  357. 0, 0, 0);
  358. AssertArg(HeapTupleIsValid(tuple));
  359. /*
  360.  * build idList for use below
  361.  */
  362. idList = lappendi(idList, tuple->t_data->t_oid);
  363. datum[0] = ObjectIdGetDatum(relationId); /* inhrel */
  364. datum[1] = ObjectIdGetDatum(tuple->t_data->t_oid); /* inhparent */
  365. datum[2] = Int16GetDatum(seqNumber); /* inhseqno */
  366. nullarr[0] = ' ';
  367. nullarr[1] = ' ';
  368. nullarr[2] = ' ';
  369. tuple = heap_formtuple(desc, datum, nullarr);
  370. heap_insert(relation, tuple);
  371. pfree(tuple);
  372. seqNumber += 1;
  373. }
  374. heap_close(relation);
  375. /* ----------------
  376.  * Catalog IPL information.
  377.  *
  378.  * Algorithm:
  379.  * 0. list superclasses (by Oid) in order given (see idList).
  380.  * 1. append after each relationId, its superclasses, recursively.
  381.  * 3. remove all but last of duplicates.
  382.  * 4. store result.
  383.  * ----------------
  384.  */
  385. /* ----------------
  386.  * 1.
  387.  * ----------------
  388.  */
  389. foreach(entry, idList)
  390. {
  391. HeapTuple tuple;
  392. Oid id;
  393. int16 number;
  394. List    *next;
  395. List    *current;
  396. id = (Oid) lfirsti(entry);
  397. current = entry;
  398. next = lnext(entry);
  399. for (number = 1;; number += 1)
  400. {
  401. tuple = SearchSysCacheTuple(INHRELID,
  402. ObjectIdGetDatum(id),
  403. Int16GetDatum(number),
  404. 0, 0);
  405. if (!HeapTupleIsValid(tuple))
  406. break;
  407. lnext(current) = lconsi(((Form_pg_inherits)
  408.  GETSTRUCT(tuple))->inhparent,
  409. NIL);
  410. current = lnext(current);
  411. }
  412. lnext(current) = next;
  413. }
  414. /* ----------------
  415.  * 2.
  416.  * ----------------
  417.  */
  418. foreach(entry, idList)
  419. {
  420. Oid name;
  421. List    *rest;
  422. bool found = false;
  423. again:
  424. name = lfirsti(entry);
  425. foreach(rest, lnext(entry))
  426. {
  427. if (name == lfirsti(rest))
  428. {
  429. found = true;
  430. break;
  431. }
  432. }
  433. if (found)
  434. {
  435. /*
  436.  * entry list must be of length >= 2 or else no match
  437.  *
  438.  * so, remove this entry.
  439.  */
  440. lfirst(entry) = lfirst(lnext(entry));
  441. lnext(entry) = lnext(lnext(entry));
  442. found = false;
  443. goto again;
  444. }
  445. }
  446. /* ----------------
  447.  * 3.
  448.  * ----------------
  449.  */
  450. relation = heap_openr(InheritancePrecidenceListRelationName);
  451. desc = RelationGetDescr(relation);
  452. seqNumber = 1;
  453. foreach(entry, idList)
  454. {
  455. Datum datum[Natts_pg_ipl];
  456. char nullarr[Natts_pg_ipl];
  457. datum[0] = ObjectIdGetDatum(relationId); /* iplrel */
  458. datum[1] = ObjectIdGetDatum(lfirsti(entry));
  459. /* iplinherits */
  460. datum[2] = Int16GetDatum(seqNumber); /* iplseqno */
  461. nullarr[0] = ' ';
  462. nullarr[1] = ' ';
  463. nullarr[2] = ' ';
  464. tuple = heap_formtuple(desc, datum, nullarr);
  465. heap_insert(relation, tuple);
  466. pfree(tuple);
  467. seqNumber += 1;
  468. }
  469. heap_close(relation);
  470. }
  471. /*
  472.  * returns 1 if attribute already exists in schema, 0 otherwise.
  473.  */
  474. static int
  475. checkAttrExists(char *attributeName, char *attributeType, List *schema)
  476. {
  477. List    *s;
  478. foreach(s, schema)
  479. {
  480. ColumnDef  *def = lfirst(s);
  481. if (!strcmp(attributeName, def->colname))
  482. {
  483. /*
  484.  * attribute exists. Make sure the types are the same.
  485.  */
  486. if (strcmp(attributeType, def->typename->name) != 0)
  487. {
  488. elog(ERROR, "%s and %s conflict for %s",
  489.  attributeType, def->typename->name, attributeName);
  490. }
  491. return 1;
  492. }
  493. }
  494. return 0;
  495. }