1 /*-------------------------------------------------------------------------
4 * random postgres portal and utility support code
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.55 1999/10/03 23:55:27 tgl Exp $
13 * The PortalExecutorHeapMemory crap needs to be eliminated
14 * by designing a better executor / portal processing memory
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.
21 *-------------------------------------------------------------------------
25 #include "access/heapam.h"
26 #include "catalog/catalog.h"
27 #include "catalog/catname.h"
28 #include "catalog/indexing.h"
29 #include "catalog/pg_type.h"
30 #include "commands/command.h"
31 #include "executor/execdefs.h"
32 #include "executor/executor.h"
33 #include "miscadmin.h"
34 #include "optimizer/prep.h"
35 #include "utils/acl.h"
36 #include "utils/builtins.h"
37 #include "utils/syscache.h"
38 #include "utils/temprel.h"
41 * PortalExecutorHeapMemory stuff
43 * This is where the XXXSuperDuperHacky code was. -cim 3/15/90
46 MemoryContext PortalExecutorHeapMemory = NULL;
48 /* --------------------------------
50 * --------------------------------
53 PortalCleanup(Portal portal)
55 MemoryContext context;
61 AssertArg(PortalIsValid(portal));
62 AssertArg(portal->cleanup == PortalCleanup);
65 * set proper portal-executor context before calling ExecMain.
68 context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
69 PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
72 * tell the executor to shutdown the query
75 ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
78 * switch back to previous context
81 MemoryContextSwitchTo(context);
82 PortalExecutorHeapMemory = (MemoryContext) NULL;
85 /* --------------------------------
87 * --------------------------------
90 PerformPortalFetch(char *name,
99 MemoryContext context;
108 elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
113 * Create a const node from the given count value
116 memset(&limcount, 0, sizeof(limcount));
117 limcount.type = T_Const;
118 limcount.consttype = INT4OID;
119 limcount.constlen = sizeof(int4);
120 limcount.constvalue = (Datum) count;
121 limcount.constisnull = FALSE;
122 limcount.constbyval = TRUE;
123 limcount.constisset = FALSE;
124 limcount.constiscast = FALSE;
128 * get the portal from the portal name
131 portal = GetPortalByName(name);
132 if (!PortalIsValid(portal))
134 elog(NOTICE, "PerformPortalFetch: portal \"%s\" not found",
140 * switch into the portal context
143 context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
145 AssertState(context == (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
148 * setup "feature" to tell the executor what direction and
149 * how many tuples to fetch.
158 * tell the destination to prepare to recieve some tuples
161 queryDesc = PortalGetQueryDesc(portal);
163 if (dest == None) /* MOVE */
165 QueryDesc *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc));
167 memcpy(qdesc, queryDesc, sizeof(QueryDesc));
173 queryDesc->operation,
174 portal->attinfo, /* QueryDescGetTypeInfo(queryDesc),
176 false, /* portal fetches don't end up in
178 false, /* this is a portal fetch, not a "retrieve
184 * execute the portal fetch operation
187 PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
189 ExecutorRun(queryDesc, PortalGetState(portal), feature,
190 (Node *) NULL, (Node *) &limcount);
192 if (dest == None) /* MOVE */
196 * Note: the "end-of-command" tag is returned by higher-level
199 * Return blank portal for now.
200 * Otherwise, this named portal will be cleaned.
201 * Note: portals will only be supported within a BEGIN...END
202 * block in the near future. Later, someone will fix it to
203 * do what is possible across transaction boundries.
206 MemoryContextSwitchTo(
207 (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
210 /* --------------------------------
212 * --------------------------------
215 PerformPortalClose(char *name, CommandDest dest)
225 elog(NOTICE, "PerformPortalClose: blank portal unsupported");
230 * get the portal from the portal name
233 portal = GetPortalByName(name);
234 if (!PortalIsValid(portal))
236 elog(NOTICE, "PerformPortalClose: portal \"%s\" not found",
242 * Note: PortalCleanup is called as a side-effect
245 PortalDestroy(&portal);
249 * PerformAddAttribute
251 * adds an additional attribute to a relation
253 * Adds attribute field(s) to a relation. Each new attribute
254 * is given attnums in sequential order and is added to the
255 * ATTRIBUTE relation. If the AMI fails, defunct tuples will
256 * remain in the ATTRIBUTE relation for later vacuuming.
257 * Later, there may be some reserved attribute names???
259 * (If needed, can instead use elog to handle exceptions.)
262 * Initial idea of ordering the tuple attributes so that all
263 * the variable length domains occured last was scratched. Doing
264 * so would not speed access too much (in general) and would create
265 * many complications in formtuple, amgetattr, and addattribute.
267 * scan attribute catalog for name conflict (within rel)
268 * scan type catalog for absence of data type (if not arg)
269 * create attnum magically???
270 * create attribute tuple
271 * insert attribute in attribute catalog
273 * create new relation tuple
274 * insert new relation in relation catalog
275 * delete original relation from relation catalog
279 PerformAddAttribute(char *relationName,
288 HeapTuple attributeTuple;
289 Form_pg_attribute attribute;
290 FormData_pg_attribute attributeD;
295 Relation idescs[Num_pg_attr_indices];
296 Relation ridescs[Num_pg_class_indices];
300 * permissions checking. this would normally be done in utility.c,
301 * but this particular routine is recursive.
303 * normally, only the owner of a class can change its schema.
305 if (!allowSystemTableMods && IsSystemRelationName(relationName))
306 elog(ERROR, "PerformAddAttribute: class \"%s\" is a system catalog",
309 if (!pg_ownercheck(userName, relationName, RELNAME))
310 elog(ERROR, "PerformAddAttribute: you do not own class \"%s\"",
315 * Grab an exclusive lock on the target table, which we will NOT release
316 * until end of transaction.
318 rel = heap_openr(relationName, AccessExclusiveLock);
319 myrelid = RelationGetRelid(rel);
320 heap_close(rel, NoLock); /* close rel but keep lock! */
323 * we can't add a not null attribute
325 if (colDef->is_not_null)
326 elog(ERROR, "Can't add a NOT NULL attribute to an existing relation");
327 if (colDef->raw_default || colDef->cooked_default)
328 elog(ERROR, "ADD ATTRIBUTE: DEFAULT not yet implemented");
331 * if the first element in the 'schema' list is a "*" then we are
332 * supposed to add this attribute to all classes that inherit from
333 * 'relationName' (as well as to 'relationName').
335 * any permissions or problems with duplicate attributes will cause the
336 * whole transaction to abort, which is what we want -- all or
347 /* this routine is actually in the planner */
348 children = find_all_inheritors(lconsi(myrelid, NIL), NIL);
351 * find_all_inheritors does the recursive search of the
352 * inheritance hierarchy, so all we have to do is process all
353 * of the relids in the list that it returns.
355 foreach(child, children)
357 childrelid = lfirsti(child);
358 if (childrelid == myrelid)
360 rel = heap_open(childrelid, AccessExclusiveLock);
361 PerformAddAttribute((rel->rd_rel->relname).data,
362 userName, false, colDef);
363 heap_close(rel, AccessExclusiveLock);
368 rel = heap_openr(RelationRelationName, RowExclusiveLock);
370 reltup = SearchSysCacheTupleCopy(RELNAME,
371 PointerGetDatum(relationName),
374 if (!HeapTupleIsValid(reltup))
375 elog(ERROR, "PerformAddAttribute: relation \"%s\" not found",
379 * XXX is the following check sufficient?
381 if (((Form_pg_class) GETSTRUCT(reltup))->relkind == RELKIND_INDEX)
383 elog(ERROR, "PerformAddAttribute: index relation \"%s\" not changed",
387 minattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts;
388 maxatts = minattnum + 1;
389 if (maxatts > MaxHeapAttributeNumber)
390 elog(ERROR, "PerformAddAttribute: relations limited to %d attributes",
391 MaxHeapAttributeNumber);
393 attrdesc = heap_openr(AttributeRelationName, RowExclusiveLock);
396 * Open all (if any) pg_attribute indices
398 hasindex = RelationGetForm(attrdesc)->relhasindex;
400 CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
402 attributeD.attrelid = reltup->t_data->t_oid;
404 attributeTuple = heap_addheader(Natts_pg_attribute,
406 (char *) &attributeD);
408 attribute = (Form_pg_attribute) GETSTRUCT(attributeTuple);
418 tup = SearchSysCacheTuple(ATTNAME,
419 ObjectIdGetDatum(reltup->t_data->t_oid),
420 PointerGetDatum(colDef->colname),
423 if (HeapTupleIsValid(tup))
424 elog(ERROR, "PerformAddAttribute: attribute \"%s\" already exists in class \"%s\"",
425 colDef->colname, relationName);
428 * check to see if it is an array attribute.
431 typename = colDef->typename->name;
433 if (colDef->typename->arrayBounds)
435 attnelems = length(colDef->typename->arrayBounds);
436 typename = makeArrayTypeName(colDef->typename->name);
441 typeTuple = SearchSysCacheTuple(TYPNAME,
442 PointerGetDatum(typename),
444 tform = (Form_pg_type) GETSTRUCT(typeTuple);
446 if (!HeapTupleIsValid(typeTuple))
447 elog(ERROR, "Add: type \"%s\" nonexistent", typename);
448 namestrcpy(&(attribute->attname), colDef->colname);
449 attribute->atttypid = typeTuple->t_data->t_oid;
450 attribute->attlen = tform->typlen;
451 attribute->attdisbursion = 0;
452 attribute->attcacheoff = -1;
453 attribute->atttypmod = colDef->typename->typmod;
454 attribute->attnum = i;
455 attribute->attbyval = tform->typbyval;
456 attribute->attnelems = attnelems;
457 attribute->attisset = (bool) (tform->typtype == 'c');
458 attribute->attalign = tform->typalign;
459 attribute->attnotnull = false;
460 attribute->atthasdef = (colDef->raw_default != NULL ||
461 colDef->cooked_default != NULL);
463 heap_insert(attrdesc, attributeTuple);
465 CatalogIndexInsert(idescs,
472 CatalogCloseIndices(Num_pg_attr_indices, idescs);
474 heap_close(attrdesc, RowExclusiveLock);
476 ((Form_pg_class) GETSTRUCT(reltup))->relnatts = maxatts;
477 heap_replace(rel, &reltup->t_self, reltup, NULL);
479 /* keep catalog indices current */
480 CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
481 CatalogIndexInsert(ridescs, Num_pg_class_indices, rel, reltup);
482 CatalogCloseIndices(Num_pg_class_indices, ridescs);
485 heap_close(rel, RowExclusiveLock);
489 LockTableCommand(LockStmt *lockstmt)
494 rel = heap_openr(lockstmt->relname, NoLock);
495 if (! RelationIsValid(rel))
496 elog(ERROR, "Relation '%s' does not exist", lockstmt->relname);
498 if (lockstmt->mode == AccessShareLock)
499 aclresult = pg_aclcheck(lockstmt->relname, GetPgUserName(), ACL_RD);
501 aclresult = pg_aclcheck(lockstmt->relname, GetPgUserName(), ACL_WR);
503 if (aclresult != ACLCHECK_OK)
504 elog(ERROR, "LOCK TABLE: permission denied");
506 LockRelation(rel, lockstmt->mode);
508 heap_close(rel, NoLock); /* close rel, keep lock */