1 /*-------------------------------------------------------------------------
4 * Contains functions which control the execution of the POSTGRES utility
5 * commands. At one time acted as an interface between the Lisp and C
8 * Copyright (c) 1994, Regents of the University of California
12 * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.77 2000/01/13 18:26:10 petere Exp $
14 *-------------------------------------------------------------------------
18 #include "access/heapam.h"
19 #include "catalog/catalog.h"
20 #include "catalog/pg_type.h"
21 #include "commands/async.h"
22 #include "commands/cluster.h"
23 #include "commands/command.h"
24 #include "commands/comment.h"
25 #include "commands/copy.h"
26 #include "commands/creatinh.h"
27 #include "commands/dbcommands.h"
28 #include "commands/defrem.h"
29 #include "commands/explain.h"
30 #include "commands/proclang.h"
31 #include "commands/rename.h"
32 #include "commands/sequence.h"
33 #include "commands/trigger.h"
34 #include "commands/user.h"
35 #include "commands/vacuum.h"
36 #include "commands/variable.h"
37 #include "commands/view.h"
38 #include "miscadmin.h"
39 #include "parser/parse.h"
40 #include "rewrite/rewriteDefine.h"
41 #include "rewrite/rewriteRemove.h"
42 #include "tcop/utility.h"
43 #include "utils/acl.h"
44 #include "utils/ps_status.h"
45 #include "utils/syscache.h"
49 * CHECK_IF_ABORTED() is used to avoid doing unnecessary
50 * processing within an aborted transaction block.
53 /* we have to use IF because of the 'break' */
54 #define CHECK_IF_ABORTED() \
57 if (IsAbortedTransactionBlockState()) \
59 elog(NOTICE, "(transaction aborted): %s", \
60 "all queries ignored until end of transaction block"); \
61 commandTag = "*ABORT STATE*"; \
67 * general utility function invoker
71 ProcessUtility(Node *parsetree,
74 char *commandTag = NULL;
79 userName = GetPgUserName();
81 switch (nodeTag(parsetree))
85 * ******************************** transactions ********************************
88 case T_TransactionStmt:
90 TransactionStmt *stmt = (TransactionStmt *) parsetree;
92 switch (stmt->command)
95 PS_SET_STATUS(commandTag = "BEGIN");
97 BeginTransactionBlock();
101 PS_SET_STATUS(commandTag = "END");
102 EndTransactionBlock();
106 PS_SET_STATUS(commandTag = "ABORT");
107 UserAbortTransactionBlock();
114 * ******************************** portal manipulation ********************************
117 case T_ClosePortalStmt:
119 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
121 PS_SET_STATUS(commandTag = "CLOSE");
124 PerformPortalClose(stmt->portalname, dest);
130 FetchStmt *stmt = (FetchStmt *) parsetree;
131 char *portalName = stmt->portalname;
135 PS_SET_STATUS(commandTag = (stmt->ismove) ? "MOVE" : "FETCH");
138 forward = (bool) (stmt->direction == FORWARD);
141 * parser ensures that count is >= 0 and 'fetch ALL' -> 0
144 count = stmt->howMany;
145 PerformPortalFetch(portalName, forward, count, commandTag,
146 (stmt->ismove) ? None : dest); /* /dev/null for MOVE */
151 * ******************************** relation and attribute
152 * manipulation ********************************
156 PS_SET_STATUS(commandTag = "CREATE");
159 DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
164 DropStmt *stmt = (DropStmt *) parsetree;
165 List *args = stmt->relNames;
168 PS_SET_STATUS(commandTag = "DROP");
171 /* check as much as we can before we start dropping ... */
176 relname = strVal(lfirst(arg));
177 if (!allowSystemTableMods && IsSystemRelationName(relname))
178 elog(ERROR, "class \"%s\" is a system catalog",
180 rel = heap_openr(relname, AccessExclusiveLock);
181 if (stmt->sequence &&
182 rel->rd_rel->relkind != RELKIND_SEQUENCE)
183 elog(ERROR, "Use DROP TABLE to drop table '%s'",
185 if (!(stmt->sequence) &&
186 rel->rd_rel->relkind == RELKIND_SEQUENCE)
187 elog(ERROR, "Use DROP SEQUENCE to drop sequence '%s'",
189 /* close rel, but keep lock until end of xact */
190 heap_close(rel, NoLock);
192 if (!pg_ownercheck(userName, relname, RELNAME))
193 elog(ERROR, "you do not own class \"%s\"",
197 /* OK, terminate 'em all */
200 relname = strVal(lfirst(arg));
201 RemoveRelation(relname);
210 PS_SET_STATUS(commandTag = "TRUNCATE");
213 relname = ((TruncateStmt *) parsetree)->relName;
214 if (!allowSystemTableMods && IsSystemRelationName(relname))
215 elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
218 /* Grab exclusive lock in preparation for truncate... */
219 rel = heap_openr(relname, AccessExclusiveLock);
220 if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
221 elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence",
223 heap_close(rel, NoLock);
226 if (!pg_ownercheck(userName, relname, RELNAME))
227 elog(ERROR, "you do not own class \"%s\"", relname);
229 TruncateRelation(relname);
236 CommentStmt *statement;
238 statement = ((CommentStmt *) parsetree);
240 PS_SET_STATUS(commandTag = "COMMENT");
242 CommentObject(statement->objtype, statement->objname,
243 statement->objproperty, statement->objlist,
252 CopyStmt *stmt = (CopyStmt *) parsetree;
254 PS_SET_STATUS(commandTag = "COPY");
257 DoCopy(stmt->relname,
260 (bool) (stmt->direction == FROM),
261 (bool) (stmt->filename == NULL),
264 * null filename means copy to/from stdout/stdin, rather
265 * than to/from a file.
271 * specify 022 umask while writing files with COPY.
279 AddAttrStmt *stmt = (AddAttrStmt *) parsetree;
281 PS_SET_STATUS(commandTag = "ADD");
285 * owner checking done in PerformAddAttribute (now
288 PerformAddAttribute(stmt->relname,
291 (ColumnDef *) stmt->colDef);
300 RenameStmt *stmt = (RenameStmt *) parsetree;
302 PS_SET_STATUS(commandTag = "RENAME");
305 relname = stmt->relname;
306 if (!allowSystemTableMods && IsSystemRelationName(relname))
307 elog(ERROR, "class \"%s\" is a system catalog",
310 if (!pg_ownercheck(userName, relname, RELNAME))
311 elog(ERROR, "you do not own class \"%s\"",
316 * XXX using len == 3 to tell the difference
317 * between "rename rel to newrel" and
318 * "rename att in rel to newatt" will not
319 * work soon because "rename type/operator/rule"
320 * stuff is being added. - cim 10/24/90
322 * [another piece of amuzing but useless anecdote -- ay]
324 if (stmt->column == NULL)
329 * Note: we also rename the "type" tuple
330 * corresponding to the relation.
333 renamerel(relname, /* old name */
334 stmt->newname); /* new name */
335 TypeRename(relname, /* old name */
336 stmt->newname); /* new name */
344 renameatt(relname, /* relname */
345 stmt->column, /* old att name */
346 stmt->newname, /* new att name */
348 stmt->inh); /* recursive? */
353 case T_ChangeACLStmt:
355 ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
360 PS_SET_STATUS(commandTag = "CHANGE");
365 modechg = stmt->modechg;
367 foreach(i, stmt->relNames)
369 relname = strVal(lfirst(i));
370 if (!pg_ownercheck(userName, relname, RELNAME))
371 elog(ERROR, "you do not own class \"%s\"",
375 foreach(i, stmt->relNames)
377 relname = strVal(lfirst(i));
378 ChangeAcl(relname, aip, modechg);
385 * ******************************** object creation /
386 * destruction ********************************
391 DefineStmt *stmt = (DefineStmt *) parsetree;
393 PS_SET_STATUS(commandTag = "CREATE");
396 switch (stmt->defType)
399 DefineOperator(stmt->defname, /* operator name */
400 stmt->definition); /* rest */
403 DefineType(stmt->defname, stmt->definition);
406 DefineAggregate(stmt->defname, /* aggregate name */
407 stmt->definition); /* rest */
413 case T_ViewStmt: /* CREATE VIEW */
415 ViewStmt *stmt = (ViewStmt *) parsetree;
417 PS_SET_STATUS(commandTag = "CREATE");
419 DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
423 case T_ProcedureStmt: /* CREATE FUNCTION */
424 PS_SET_STATUS(commandTag = "CREATE");
426 CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */
429 case T_IndexStmt: /* CREATE INDEX */
431 IndexStmt *stmt = (IndexStmt *) parsetree;
433 PS_SET_STATUS(commandTag = "CREATE");
435 DefineIndex(stmt->relname, /* relation name */
436 stmt->idxname, /* index name */
437 stmt->accessMethod, /* am name */
438 stmt->indexParams, /* parameters */
442 (Expr *) stmt->whereClause,
447 case T_RuleStmt: /* CREATE RULE */
449 RuleStmt *stmt = (RuleStmt *) parsetree;
453 relname = stmt->object->relname;
454 aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
455 if (aclcheck_result != ACLCHECK_OK)
456 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
458 PS_SET_STATUS(commandTag = "CREATE");
460 DefineQueryRewrite(stmt);
464 case T_CreateSeqStmt:
465 PS_SET_STATUS(commandTag = "CREATE");
468 DefineSequence((CreateSeqStmt *) parsetree);
473 ExtendStmt *stmt = (ExtendStmt *) parsetree;
475 PS_SET_STATUS(commandTag = "EXTEND");
478 ExtendIndex(stmt->idxname, /* index name */
479 (Expr *) stmt->whereClause, /* where */
486 RemoveStmt *stmt = (RemoveStmt *) parsetree;
488 PS_SET_STATUS(commandTag = "DROP");
491 switch (stmt->removeType)
494 relname = stmt->name;
495 if (!allowSystemTableMods && IsSystemRelationName(relname))
496 elog(ERROR, "class \"%s\" is a system catalog index",
499 if (!pg_ownercheck(userName, relname, RELNAME))
500 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
502 RemoveIndex(relname);
506 char *rulename = stmt->name;
511 relationName = RewriteGetRuleEventRel(rulename);
512 aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
513 if (aclcheck_result != ACLCHECK_OK)
514 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
516 RemoveRewriteRule(rulename);
521 /* XXX moved to remove.c */
523 RemoveType(stmt->name);
527 char *viewName = stmt->name;
532 ruleName = MakeRetrieveViewRuleName(viewName);
533 relationName = RewriteGetRuleEventRel(ruleName);
534 if (!pg_ownercheck(userName, relationName, RELNAME))
535 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
538 RemoveView(viewName);
546 case T_RemoveAggrStmt:
548 RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
550 PS_SET_STATUS(commandTag = "DROP");
552 RemoveAggregate(stmt->aggname, stmt->aggtype);
556 case T_RemoveFuncStmt:
558 RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
560 PS_SET_STATUS(commandTag = "DROP");
562 RemoveFunction(stmt->funcname,
568 case T_RemoveOperStmt:
570 RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
571 char *type1 = (char *) NULL;
572 char *type2 = (char *) NULL;
574 PS_SET_STATUS(commandTag = "DROP");
577 if (lfirst(stmt->args) != NULL)
578 type1 = strVal(lfirst(stmt->args));
579 if (lsecond(stmt->args) != NULL)
580 type2 = strVal(lsecond(stmt->args));
581 RemoveOperator(stmt->opname, type1, type2);
586 elog(ERROR, "CREATE VERSION is not currently implemented");
591 CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
593 PS_SET_STATUS(commandTag = "CREATE DATABASE");
595 createdb(stmt->dbname, stmt->dbpath, stmt->encoding);
601 DropdbStmt *stmt = (DropdbStmt *) parsetree;
603 PS_SET_STATUS(commandTag = "DROP DATABASE");
605 dropdb(stmt->dbname);
609 /* Query-level asynchronous notification */
612 NotifyStmt *stmt = (NotifyStmt *) parsetree;
614 PS_SET_STATUS(commandTag = "NOTIFY");
617 Async_Notify(stmt->relname);
623 ListenStmt *stmt = (ListenStmt *) parsetree;
625 PS_SET_STATUS(commandTag = "LISTEN");
628 Async_Listen(stmt->relname, MyProcPid);
634 UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
636 PS_SET_STATUS(commandTag = "UNLISTEN");
639 Async_Unlisten(stmt->relname, MyProcPid);
644 * ******************************** dynamic loader ********************************
649 LoadStmt *stmt = (LoadStmt *) parsetree;
651 PS_SET_STATUS(commandTag = "LOAD");
654 closeAllVfds(); /* probably not necessary... */
655 load_file(stmt->filename);
661 ClusterStmt *stmt = (ClusterStmt *) parsetree;
663 PS_SET_STATUS(commandTag = "CLUSTER");
666 cluster(stmt->relname, stmt->indexname);
671 PS_SET_STATUS(commandTag = "VACUUM");
673 vacuum(((VacuumStmt *) parsetree)->vacrel,
674 ((VacuumStmt *) parsetree)->verbose,
675 ((VacuumStmt *) parsetree)->analyze,
676 ((VacuumStmt *) parsetree)->va_spec);
681 ExplainStmt *stmt = (ExplainStmt *) parsetree;
683 PS_SET_STATUS(commandTag = "EXPLAIN");
686 ExplainQuery(stmt->query, stmt->verbose, dest);
693 * ******************************** Tioga-related statements *******************************
697 RecipeStmt *stmt = (RecipeStmt *) parsetree;
699 PS_SET_STATUS(commandTag = "EXECUTE RECIPE");
707 * ******************************** set variable statements *******************************
709 case T_VariableSetStmt:
711 VariableSetStmt *n = (VariableSetStmt *) parsetree;
713 SetPGVariable(n->name, n->value);
714 PS_SET_STATUS(commandTag = "SET VARIABLE");
718 case T_VariableShowStmt:
720 VariableShowStmt *n = (VariableShowStmt *) parsetree;
722 GetPGVariable(n->name);
723 PS_SET_STATUS(commandTag = "SHOW VARIABLE");
727 case T_VariableResetStmt:
729 VariableResetStmt *n = (VariableResetStmt *) parsetree;
731 ResetPGVariable(n->name);
732 PS_SET_STATUS(commandTag = "RESET VARIABLE");
737 * ******************************** TRIGGER statements *******************************
739 case T_CreateTrigStmt:
740 PS_SET_STATUS(commandTag = "CREATE");
743 CreateTrigger((CreateTrigStmt *) parsetree);
747 PS_SET_STATUS(commandTag = "DROP");
750 DropTrigger((DropTrigStmt *) parsetree);
754 * ************* PROCEDURAL LANGUAGE statements *****************
756 case T_CreatePLangStmt:
757 PS_SET_STATUS(commandTag = "CREATE");
760 CreateProceduralLanguage((CreatePLangStmt *) parsetree);
763 case T_DropPLangStmt:
764 PS_SET_STATUS(commandTag = "DROP");
767 DropProceduralLanguage((DropPLangStmt *) parsetree);
771 * ******************************** USER statements ****
774 case T_CreateUserStmt:
775 PS_SET_STATUS(commandTag = "CREATE USER");
778 DefineUser((CreateUserStmt *) parsetree, dest);
781 case T_AlterUserStmt:
782 PS_SET_STATUS(commandTag = "ALTER USER");
785 AlterUser((AlterUserStmt *) parsetree, dest);
789 PS_SET_STATUS(commandTag = "DROP USER");
792 RemoveUser(((DropUserStmt *) parsetree)->user, dest);
796 PS_SET_STATUS(commandTag = "LOCK TABLE");
799 LockTableCommand((LockStmt *) parsetree);
802 case T_ConstraintsSetStmt:
803 PS_SET_STATUS(commandTag = "SET CONSTRAINTS");
806 DeferredTriggerSetState((ConstraintsSetStmt *) parsetree);
809 case T_CreateGroupStmt:
810 PS_SET_STATUS(commandTag = "CREATE GROUP");
813 CreateGroup((CreateGroupStmt *) parsetree, dest);
816 case T_AlterGroupStmt:
817 PS_SET_STATUS(commandTag = "ALTER GROUP");
820 AlterGroup((AlterGroupStmt *) parsetree, dest);
823 case T_DropGroupStmt:
824 PS_SET_STATUS(commandTag = "DROP GROUP");
827 DropGroup((DropGroupStmt *) parsetree, dest);
831 * ******************************** default ********************************
835 elog(ERROR, "ProcessUtility: command #%d unsupported",
841 * tell fe/be or whatever that we're done.
844 EndCommand(commandTag, dest);