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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * command.c
  4.  *   random postgres portal and utility support 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/command.c,v 1.47.2.1 1999/08/02 05:56:57 scrappy Exp $
  11.  *
  12.  * NOTES
  13.  *   The PortalExecutorHeapMemory crap needs to be eliminated
  14.  *   by designing a better executor / portal processing memory
  15.  *   interface.
  16.  *
  17.  *   The PerformAddAttribute() code, like most of the relation
  18.  *   manipulating code in the commands/ directory, should go
  19.  *   someplace closer to the lib/catalog code.
  20.  *
  21.  *-------------------------------------------------------------------------
  22.  */
  23. #include "postgres.h"
  24. #include "access/heapam.h"
  25. #include "catalog/catalog.h"
  26. #include "catalog/catname.h"
  27. #include "catalog/indexing.h"
  28. #include "catalog/pg_type.h"
  29. #include "commands/command.h"
  30. #include "executor/execdefs.h"
  31. #include "executor/executor.h"
  32. #include "miscadmin.h"
  33. #include "optimizer/prep.h"
  34. #include "utils/acl.h"
  35. #include "utils/builtins.h"
  36. #include "utils/syscache.h"
  37. #include "utils/temprel.h"
  38. /* ----------------
  39.  * PortalExecutorHeapMemory stuff
  40.  *
  41.  * This is where the XXXSuperDuperHacky code was. -cim 3/15/90
  42.  * ----------------
  43.  */
  44. MemoryContext PortalExecutorHeapMemory = NULL;
  45. /* --------------------------------
  46.  * PortalCleanup
  47.  * --------------------------------
  48.  */
  49. void
  50. PortalCleanup(Portal portal)
  51. {
  52. MemoryContext context;
  53. /* ----------------
  54.  * sanity checks
  55.  * ----------------
  56.  */
  57. AssertArg(PortalIsValid(portal));
  58. AssertArg(portal->cleanup == PortalCleanup);
  59. /* ----------------
  60.  * set proper portal-executor context before calling ExecMain.
  61.  * ----------------
  62.  */
  63. context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
  64. PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
  65. /* ----------------
  66.  * tell the executor to shutdown the query
  67.  * ----------------
  68.  */
  69. ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
  70. /* ----------------
  71.  * switch back to previous context
  72.  * ----------------
  73.  */
  74. MemoryContextSwitchTo(context);
  75. PortalExecutorHeapMemory = (MemoryContext) NULL;
  76. }
  77. /* --------------------------------
  78.  * PerformPortalFetch
  79.  * --------------------------------
  80.  */
  81. void
  82. PerformPortalFetch(char *name,
  83.    bool forward,
  84.    int count,
  85.    char *tag,
  86.    CommandDest dest)
  87. {
  88. Portal portal;
  89. int feature;
  90. QueryDesc  *queryDesc;
  91. MemoryContext context;
  92. Const limcount;
  93. /* ----------------
  94.  * sanity checks
  95.  * ----------------
  96.  */
  97. if (name == NULL)
  98. {
  99. elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
  100. return;
  101. }
  102. /* ----------------
  103.  * Create a const node from the given count value
  104.  * ----------------
  105.  */
  106. memset(&limcount, 0, sizeof(limcount));
  107. limcount.type = T_Const;
  108. limcount.consttype = INT4OID;
  109. limcount.constlen = sizeof(int4);
  110. limcount.constvalue = (Datum) count;
  111. limcount.constisnull = FALSE;
  112. limcount.constbyval = TRUE;
  113. limcount.constisset = FALSE;
  114. limcount.constiscast = FALSE;
  115. /* ----------------
  116.  * get the portal from the portal name
  117.  * ----------------
  118.  */
  119. portal = GetPortalByName(name);
  120. if (!PortalIsValid(portal))
  121. {
  122. elog(NOTICE, "PerformPortalFetch: portal "%s" not found",
  123.  name);
  124. return;
  125. }
  126. /* ----------------
  127.  * switch into the portal context
  128.  * ----------------
  129.  */
  130. context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
  131. AssertState(context == (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
  132. /* ----------------
  133.  * setup "feature" to tell the executor what direction and
  134.  * how many tuples to fetch.
  135.  * ----------------
  136.  */
  137. if (forward)
  138. feature = EXEC_FOR;
  139. else
  140. feature = EXEC_BACK;
  141. /* ----------------
  142.  * tell the destination to prepare to recieve some tuples
  143.  * ----------------
  144.  */
  145. queryDesc = PortalGetQueryDesc(portal);
  146. if (dest == None) /* MOVE */
  147. {
  148. QueryDesc  *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc));
  149. memcpy(qdesc, queryDesc, sizeof(QueryDesc));
  150. qdesc->dest = dest;
  151. queryDesc = qdesc;
  152. }
  153. BeginCommand(name,
  154.  queryDesc->operation,
  155.  portal->attinfo, /* QueryDescGetTypeInfo(queryDesc),
  156.  * */
  157.  false, /* portal fetches don't end up in
  158.  * relations */
  159.  false, /* this is a portal fetch, not a "retrieve
  160.  * portal" */
  161.  tag,
  162.  dest);
  163. /* ----------------
  164.  * execute the portal fetch operation
  165.  * ----------------
  166.  */
  167. PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
  168. ExecutorRun(queryDesc, PortalGetState(portal), feature,
  169. (Node *) NULL, (Node *) &limcount);
  170. if (dest == None) /* MOVE */
  171. pfree(queryDesc);
  172. /* ----------------
  173.  * Note: the "end-of-command" tag is returned by higher-level
  174.  *  utility code
  175.  *
  176.  * Return blank portal for now.
  177.  * Otherwise, this named portal will be cleaned.
  178.  * Note: portals will only be supported within a BEGIN...END
  179.  * block in the near future.  Later, someone will fix it to
  180.  * do what is possible across transaction boundries.
  181.  * ----------------
  182.  */
  183. MemoryContextSwitchTo(
  184.  (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
  185. }
  186. /* --------------------------------
  187.  * PerformPortalClose
  188.  * --------------------------------
  189.  */
  190. void
  191. PerformPortalClose(char *name, CommandDest dest)
  192. {
  193. Portal portal;
  194. /* ----------------
  195.  * sanity checks
  196.  * ----------------
  197.  */
  198. if (name == NULL)
  199. {
  200. elog(NOTICE, "PerformPortalClose: blank portal unsupported");
  201. return;
  202. }
  203. /* ----------------
  204.  * get the portal from the portal name
  205.  * ----------------
  206.  */
  207. portal = GetPortalByName(name);
  208. if (!PortalIsValid(portal))
  209. {
  210. elog(NOTICE, "PerformPortalClose: portal "%s" not found",
  211.  name);
  212. return;
  213. }
  214. /* ----------------
  215.  * Note: PortalCleanup is called as a side-effect
  216.  * ----------------
  217.  */
  218. PortalDestroy(&portal);
  219. }
  220. /* ----------------
  221.  * PerformAddAttribute
  222.  *
  223.  * adds an additional attribute to a relation
  224.  *
  225.  * Adds attribute field(s) to a relation. Each new attribute
  226.  * is given attnums in sequential order and is added to the
  227.  * ATTRIBUTE relation.  If the AMI fails, defunct tuples will
  228.  * remain in the ATTRIBUTE relation for later vacuuming.
  229.  * Later, there may be some reserved attribute names???
  230.  *
  231.  * (If needed, can instead use elog to handle exceptions.)
  232.  *
  233.  * Note:
  234.  * Initial idea of ordering the tuple attributes so that all
  235.  * the variable length domains occured last was scratched.  Doing
  236.  * so would not speed access too much (in general) and would create
  237.  * many complications in formtuple, amgetattr, and addattribute.
  238.  *
  239.  * scan attribute catalog for name conflict (within rel)
  240.  * scan type catalog for absence of data type (if not arg)
  241.  * create attnum magically???
  242.  * create attribute tuple
  243.  * insert attribute in attribute catalog
  244.  * modify reldesc
  245.  * create new relation tuple
  246.  * insert new relation in relation catalog
  247.  * delete original relation from relation catalog
  248.  * ----------------
  249.  */
  250. void
  251. PerformAddAttribute(char *relationName,
  252. char *userName,
  253. bool inherits,
  254. ColumnDef *colDef)
  255. {
  256. Relation rel,
  257. attrdesc;
  258. HeapTuple reltup;
  259. HeapTuple attributeTuple;
  260. Form_pg_attribute attribute;
  261. FormData_pg_attribute attributeD;
  262. int i;
  263. int minattnum,
  264. maxatts;
  265. HeapTuple tup;
  266. Relation idescs[Num_pg_attr_indices];
  267. Relation ridescs[Num_pg_class_indices];
  268. bool hasindex;
  269. /*
  270.  * permissions checking.  this would normally be done in utility.c,
  271.  * but this particular routine is recursive.
  272.  *
  273.  * normally, only the owner of a class can change its schema.
  274.  */
  275. if (!allowSystemTableMods && IsSystemRelationName(relationName))
  276. elog(ERROR, "PerformAddAttribute: class "%s" is a system catalog",
  277.  relationName);
  278. #ifndef NO_SECURITY
  279. if (!pg_ownercheck(userName, relationName, RELNAME))
  280. elog(ERROR, "PerformAddAttribute: you do not own class "%s"",
  281.  relationName);
  282. #endif
  283. /*
  284.  * we can't add a not null attribute
  285.  */
  286. if (colDef->is_not_null)
  287. elog(ERROR, "Can't add a NOT NULL attribute to an existing relation");
  288. if (colDef->defval)
  289. elog(ERROR, "ADD ATTRIBUTE: DEFAULT not yet implemented");
  290. /*
  291.  * if the first element in the 'schema' list is a "*" then we are
  292.  * supposed to add this attribute to all classes that inherit from
  293.  * 'relationName' (as well as to 'relationName').
  294.  *
  295.  * any permissions or problems with duplicate attributes will cause the
  296.  * whole transaction to abort, which is what we want -- all or
  297.  * nothing.
  298.  */
  299. if (colDef != NULL)
  300. {
  301. if (inherits)
  302. {
  303. Oid myrelid,
  304. childrelid;
  305. List    *child,
  306.    *children;
  307. rel = heap_openr(relationName);
  308. if (!RelationIsValid(rel))
  309. {
  310. elog(ERROR, "PerformAddAttribute: unknown relation: "%s"",
  311.  relationName);
  312. }
  313. myrelid = RelationGetRelid(rel);
  314. heap_close(rel);
  315. /* this routine is actually in the planner */
  316. children = find_all_inheritors(lconsi(myrelid, NIL), NIL);
  317. /*
  318.  * find_all_inheritors does the recursive search of the
  319.  * inheritance hierarchy, so all we have to do is process all
  320.  * of the relids in the list that it returns.
  321.  */
  322. foreach(child, children)
  323. {
  324. childrelid = lfirsti(child);
  325. if (childrelid == myrelid)
  326. continue;
  327. rel = heap_open(childrelid);
  328. if (!RelationIsValid(rel))
  329. {
  330. elog(ERROR, "PerformAddAttribute: can't find catalog entry for inheriting class with oid %u",
  331.  childrelid);
  332. }
  333. PerformAddAttribute((rel->rd_rel->relname).data,
  334. userName, false, colDef);
  335. heap_close(rel);
  336. }
  337. }
  338. }
  339. rel = heap_openr(RelationRelationName);
  340. reltup = SearchSysCacheTupleCopy(RELNAME,
  341.  PointerGetDatum(relationName),
  342.  0, 0, 0);
  343. if (!HeapTupleIsValid(reltup))
  344. {
  345. heap_close(rel);
  346. elog(ERROR, "PerformAddAttribute: relation "%s" not found",
  347.  relationName);
  348. }
  349. /*
  350.  * XXX is the following check sufficient?
  351.  */
  352. if (((Form_pg_class) GETSTRUCT(reltup))->relkind == RELKIND_INDEX)
  353. {
  354. elog(ERROR, "PerformAddAttribute: index relation "%s" not changed",
  355.  relationName);
  356. return;
  357. }
  358. minattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts;
  359. maxatts = minattnum + 1;
  360. if (maxatts > MaxHeapAttributeNumber)
  361. {
  362. pfree(reltup);
  363. heap_close(rel);
  364. elog(ERROR, "PerformAddAttribute: relations limited to %d attributes",
  365.  MaxHeapAttributeNumber);
  366. }
  367. attrdesc = heap_openr(AttributeRelationName);
  368. Assert(attrdesc);
  369. Assert(RelationGetForm(attrdesc));
  370. /*
  371.  * Open all (if any) pg_attribute indices
  372.  */
  373. hasindex = RelationGetForm(attrdesc)->relhasindex;
  374. if (hasindex)
  375. CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
  376. attributeD.attrelid = reltup->t_data->t_oid;
  377. attributeTuple = heap_addheader(Natts_pg_attribute,
  378. sizeof attributeD,
  379. (char *) &attributeD);
  380. attribute = (Form_pg_attribute) GETSTRUCT(attributeTuple);
  381. i = 1 + minattnum;
  382. {
  383. HeapTuple typeTuple;
  384. Form_pg_type tform;
  385. char    *typename;
  386. int attnelems;
  387. tup = SearchSysCacheTuple(ATTNAME,
  388.   ObjectIdGetDatum(reltup->t_data->t_oid),
  389.   PointerGetDatum(colDef->colname),
  390.   0, 0);
  391. if (HeapTupleIsValid(tup))
  392. {
  393. heap_close(attrdesc);
  394. heap_close(rel);
  395. elog(ERROR, "PerformAddAttribute: attribute "%s" already exists in class "%s"",
  396.  colDef->colname, relationName);
  397. }
  398. /*
  399.  * check to see if it is an array attribute.
  400.  */
  401. typename = colDef->typename->name;
  402. if (colDef->typename->arrayBounds)
  403. {
  404. attnelems = length(colDef->typename->arrayBounds);
  405. typename = makeArrayTypeName(colDef->typename->name);
  406. }
  407. else
  408. attnelems = 0;
  409. typeTuple = SearchSysCacheTuple(TYPNAME,
  410. PointerGetDatum(typename),
  411. 0, 0, 0);
  412. tform = (Form_pg_type) GETSTRUCT(typeTuple);
  413. if (!HeapTupleIsValid(typeTuple))
  414. elog(ERROR, "Add: type "%s" nonexistent", typename);
  415. namestrcpy(&(attribute->attname), colDef->colname);
  416. attribute->atttypid = typeTuple->t_data->t_oid;
  417. attribute->attlen = tform->typlen;
  418. attribute->attdisbursion = 0;
  419. attribute->attcacheoff = -1;
  420. attribute->atttypmod = colDef->typename->typmod;
  421. attribute->attnum = i;
  422. attribute->attbyval = tform->typbyval;
  423. attribute->attnelems = attnelems;
  424. attribute->attisset = (bool) (tform->typtype == 'c');
  425. attribute->attalign = tform->typalign;
  426. attribute->attnotnull = false;
  427. attribute->atthasdef = (colDef->defval != NULL);
  428. heap_insert(attrdesc, attributeTuple);
  429. if (hasindex)
  430. CatalogIndexInsert(idescs,
  431.    Num_pg_attr_indices,
  432.    attrdesc,
  433.    attributeTuple);
  434. }
  435. if (hasindex)
  436. CatalogCloseIndices(Num_pg_attr_indices, idescs);
  437. heap_close(attrdesc);
  438. ((Form_pg_class) GETSTRUCT(reltup))->relnatts = maxatts;
  439. heap_replace(rel, &reltup->t_self, reltup, NULL);
  440. {
  441. HeapTuple temptup;
  442. if ((temptup = get_temp_rel_by_name(relationName)) != NULL)
  443. ((Form_pg_class) GETSTRUCT(temptup))->relnatts = maxatts;
  444. }
  445. /* keep catalog indices current */
  446. CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
  447. CatalogIndexInsert(ridescs, Num_pg_class_indices, rel, reltup);
  448. CatalogCloseIndices(Num_pg_class_indices, ridescs);
  449. pfree(reltup);
  450. heap_close(rel);
  451. }
  452. void
  453. LockTableCommand(LockStmt *lockstmt)
  454. {
  455. Relation rel;
  456. int aclresult;
  457. rel = heap_openr(lockstmt->relname);
  458. if (rel == NULL)
  459. elog(ERROR, "LOCK TABLE: relation %s can't be openned", lockstmt->relname);
  460. if (lockstmt->mode == AccessShareLock)
  461. aclresult = pg_aclcheck(lockstmt->relname, GetPgUserName(), ACL_RD);
  462. else
  463. aclresult = pg_aclcheck(lockstmt->relname, GetPgUserName(), ACL_WR);
  464. if (aclresult != ACLCHECK_OK)
  465. elog(ERROR, "LOCK TABLE: permission denied");
  466. LockRelation(rel, lockstmt->mode);
  467. }