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 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.88 2000/05/11 03:54:18 tgl Exp $
15 *-------------------------------------------------------------------------
19 #include "access/heapam.h"
20 #include "catalog/catalog.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, "current transaction is aborted, " \
60 "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 = "COMMIT");
102 EndTransactionBlock();
106 PS_SET_STATUS(commandTag = "ROLLBACK");
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");
140 forward = (bool) (stmt->direction == FORWARD);
143 * parser ensures that count is >= 0 and 'fetch ALL' -> 0
146 count = stmt->howMany;
147 PerformPortalFetch(portalName, forward, count, commandTag,
148 (stmt->ismove) ? None : dest); /* /dev/null for MOVE */
153 * ******************************** relation and attribute
154 * manipulation ********************************
158 PS_SET_STATUS(commandTag = "CREATE");
161 DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
166 DropStmt *stmt = (DropStmt *) parsetree;
167 List *args = stmt->relNames;
170 PS_SET_STATUS(commandTag = "DROP");
173 /* check as much as we can before we start dropping ... */
178 relname = strVal(lfirst(arg));
179 if (!allowSystemTableMods && IsSystemRelationName(relname))
180 elog(ERROR, "class \"%s\" is a system catalog",
182 rel = heap_openr(relname, AccessExclusiveLock);
183 if (stmt->sequence &&
184 rel->rd_rel->relkind != RELKIND_SEQUENCE)
185 elog(ERROR, "Use DROP TABLE to drop table '%s'",
187 if (!(stmt->sequence) &&
188 rel->rd_rel->relkind == RELKIND_SEQUENCE)
189 elog(ERROR, "Use DROP SEQUENCE to drop sequence '%s'",
191 /* close rel, but keep lock until end of xact */
192 heap_close(rel, NoLock);
194 if (!pg_ownercheck(userName, relname, RELNAME))
195 elog(ERROR, "you do not own class \"%s\"",
199 /* OK, terminate 'em all */
202 relname = strVal(lfirst(arg));
203 RemoveRelation(relname);
212 PS_SET_STATUS(commandTag = "TRUNCATE");
215 relname = ((TruncateStmt *) parsetree)->relName;
216 if (!allowSystemTableMods && IsSystemRelationName(relname))
217 elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
220 /* Grab exclusive lock in preparation for truncate... */
221 rel = heap_openr(relname, AccessExclusiveLock);
222 if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
223 elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence",
225 heap_close(rel, NoLock);
228 if (!pg_ownercheck(userName, relname, RELNAME))
229 elog(ERROR, "you do not own class \"%s\"", relname);
231 TruncateRelation(relname);
238 CommentStmt *statement;
240 statement = ((CommentStmt *) parsetree);
242 PS_SET_STATUS(commandTag = "COMMENT");
244 CommentObject(statement->objtype, statement->objname,
245 statement->objproperty, statement->objlist,
254 CopyStmt *stmt = (CopyStmt *) parsetree;
256 PS_SET_STATUS(commandTag = "COPY");
259 if (stmt->direction != FROM)
262 DoCopy(stmt->relname,
265 (bool) (stmt->direction == FROM),
266 (bool) (stmt->filename == NULL),
269 * null filename means copy to/from stdout/stdin, rather
270 * than to/from a file.
283 RenameStmt *stmt = (RenameStmt *) parsetree;
285 PS_SET_STATUS(commandTag = "ALTER");
288 relname = stmt->relname;
289 if (!allowSystemTableMods && IsSystemRelationName(relname))
290 elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
293 if (!pg_ownercheck(userName, relname, RELNAME))
294 elog(ERROR, "permission denied");
298 * XXX using len == 3 to tell the difference
299 * between "rename rel to newrel" and
300 * "rename att in rel to newatt" will not
301 * work soon because "rename type/operator/rule"
302 * stuff is being added. - cim 10/24/90
304 * [another piece of amuzing but useless anecdote -- ay]
306 if (stmt->column == NULL)
311 * Note: we also rename the "type" tuple
312 * corresponding to the relation.
315 renamerel(relname, /* old name */
316 stmt->newname); /* new name */
324 renameatt(relname, /* relname */
325 stmt->column, /* old att name */
326 stmt->newname, /* new att name */
328 stmt->inh); /* recursive? */
333 /* various Alter Table forms */
335 case T_AlterTableStmt:
337 AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
339 PS_SET_STATUS(commandTag = "ALTER");
343 * Some or all of these functions are recursive to cover
344 * inherited things, so permission checks are done there.
346 switch (stmt->subtype)
348 case 'A': /* ADD COLUMN */
349 AlterTableAddColumn(stmt->relname, stmt->inh, (ColumnDef *) stmt->def);
351 case 'T': /* ALTER COLUMN */
352 AlterTableAlterColumn(stmt->relname, stmt->inh, stmt->name, stmt->def);
354 case 'D': /* ALTER DROP */
355 AlterTableDropColumn(stmt->relname, stmt->inh, stmt->name, stmt->behavior);
357 case 'C': /* ADD CONSTRAINT */
358 AlterTableAddConstraint(stmt->relname, stmt->inh, stmt->def);
360 case 'X': /* DROP CONSTRAINT */
361 AlterTableDropConstraint(stmt->relname, stmt->inh, stmt->name, stmt->behavior);
364 elog(ERROR, "T_AlterTableStmt: unknown subtype");
371 case T_ChangeACLStmt:
373 ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
378 PS_SET_STATUS(commandTag = "CHANGE");
383 modechg = stmt->modechg;
384 foreach(i, stmt->relNames)
388 relname = strVal(lfirst(i));
389 rel = heap_openr(relname, AccessExclusiveLock);
390 if (rel && rel->rd_rel->relkind == RELKIND_INDEX)
391 elog(ERROR, "\"%s\" is an index relation",
393 /* close rel, but keep lock until end of xact */
394 heap_close(rel, NoLock);
396 if (!pg_ownercheck(userName, relname, RELNAME))
397 elog(ERROR, "you do not own class \"%s\"",
400 ChangeAcl(relname, aip, modechg);
406 * ******************************** object creation /
407 * destruction ********************************
412 DefineStmt *stmt = (DefineStmt *) parsetree;
414 PS_SET_STATUS(commandTag = "CREATE");
417 switch (stmt->defType)
420 DefineOperator(stmt->defname, /* operator name */
421 stmt->definition); /* rest */
424 DefineType(stmt->defname, stmt->definition);
427 DefineAggregate(stmt->defname, /* aggregate name */
428 stmt->definition); /* rest */
434 case T_ViewStmt: /* CREATE VIEW */
436 ViewStmt *stmt = (ViewStmt *) parsetree;
438 PS_SET_STATUS(commandTag = "CREATE");
440 DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
444 case T_ProcedureStmt: /* CREATE FUNCTION */
445 PS_SET_STATUS(commandTag = "CREATE");
447 CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */
450 case T_IndexStmt: /* CREATE INDEX */
452 IndexStmt *stmt = (IndexStmt *) parsetree;
454 PS_SET_STATUS(commandTag = "CREATE");
456 DefineIndex(stmt->relname, /* relation name */
457 stmt->idxname, /* index name */
458 stmt->accessMethod, /* am name */
459 stmt->indexParams, /* parameters */
463 (Expr *) stmt->whereClause,
468 case T_RuleStmt: /* CREATE RULE */
470 RuleStmt *stmt = (RuleStmt *) parsetree;
474 relname = stmt->object->relname;
475 aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
476 if (aclcheck_result != ACLCHECK_OK)
477 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
479 PS_SET_STATUS(commandTag = "CREATE");
481 DefineQueryRewrite(stmt);
485 case T_CreateSeqStmt:
486 PS_SET_STATUS(commandTag = "CREATE");
489 DefineSequence((CreateSeqStmt *) parsetree);
494 ExtendStmt *stmt = (ExtendStmt *) parsetree;
496 PS_SET_STATUS(commandTag = "EXTEND");
499 ExtendIndex(stmt->idxname, /* index name */
500 (Expr *) stmt->whereClause, /* where */
507 RemoveStmt *stmt = (RemoveStmt *) parsetree;
509 PS_SET_STATUS(commandTag = "DROP");
512 switch (stmt->removeType)
515 relname = stmt->name;
516 if (!allowSystemTableMods && IsSystemRelationName(relname))
517 elog(ERROR, "class \"%s\" is a system catalog index",
520 if (!pg_ownercheck(userName, relname, RELNAME))
521 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
523 RemoveIndex(relname);
527 char *rulename = stmt->name;
532 relationName = RewriteGetRuleEventRel(rulename);
533 aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
534 if (aclcheck_result != ACLCHECK_OK)
535 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
537 RemoveRewriteRule(rulename);
542 /* XXX moved to remove.c */
544 RemoveType(stmt->name);
548 char *viewName = stmt->name;
553 ruleName = MakeRetrieveViewRuleName(viewName);
554 relationName = RewriteGetRuleEventRel(ruleName);
555 if (!pg_ownercheck(userName, relationName, RELNAME))
556 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
559 RemoveView(viewName);
567 case T_RemoveAggrStmt:
569 RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
571 PS_SET_STATUS(commandTag = "DROP");
573 RemoveAggregate(stmt->aggname, stmt->aggtype);
577 case T_RemoveFuncStmt:
579 RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
581 PS_SET_STATUS(commandTag = "DROP");
583 RemoveFunction(stmt->funcname,
589 case T_RemoveOperStmt:
591 RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
592 char *type1 = (char *) NULL;
593 char *type2 = (char *) NULL;
595 PS_SET_STATUS(commandTag = "DROP");
598 if (lfirst(stmt->args) != NULL)
599 type1 = strVal(lfirst(stmt->args));
600 if (lsecond(stmt->args) != NULL)
601 type2 = strVal(lsecond(stmt->args));
602 RemoveOperator(stmt->opname, type1, type2);
607 elog(ERROR, "CREATE VERSION is not currently implemented");
612 CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
614 PS_SET_STATUS(commandTag = "CREATE DATABASE");
616 createdb(stmt->dbname, stmt->dbpath, stmt->encoding);
622 DropdbStmt *stmt = (DropdbStmt *) parsetree;
624 PS_SET_STATUS(commandTag = "DROP DATABASE");
626 dropdb(stmt->dbname);
630 /* Query-level asynchronous notification */
633 NotifyStmt *stmt = (NotifyStmt *) parsetree;
635 PS_SET_STATUS(commandTag = "NOTIFY");
638 Async_Notify(stmt->relname);
644 ListenStmt *stmt = (ListenStmt *) parsetree;
646 PS_SET_STATUS(commandTag = "LISTEN");
649 Async_Listen(stmt->relname, MyProcPid);
655 UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
657 PS_SET_STATUS(commandTag = "UNLISTEN");
660 Async_Unlisten(stmt->relname, MyProcPid);
665 * ******************************** dynamic loader ********************************
670 LoadStmt *stmt = (LoadStmt *) parsetree;
672 PS_SET_STATUS(commandTag = "LOAD");
675 closeAllVfds(); /* probably not necessary... */
676 load_file(stmt->filename);
682 ClusterStmt *stmt = (ClusterStmt *) parsetree;
684 PS_SET_STATUS(commandTag = "CLUSTER");
687 cluster(stmt->relname, stmt->indexname);
692 PS_SET_STATUS(commandTag = "VACUUM");
694 vacuum(((VacuumStmt *) parsetree)->vacrel,
695 ((VacuumStmt *) parsetree)->verbose,
696 ((VacuumStmt *) parsetree)->analyze,
697 ((VacuumStmt *) parsetree)->va_spec);
702 ExplainStmt *stmt = (ExplainStmt *) parsetree;
704 PS_SET_STATUS(commandTag = "EXPLAIN");
707 ExplainQuery(stmt->query, stmt->verbose, dest);
714 * ******************************** Tioga-related statements *******************************
718 RecipeStmt *stmt = (RecipeStmt *) parsetree;
720 PS_SET_STATUS(commandTag = "EXECUTE RECIPE");
728 * ******************************** set variable statements *******************************
730 case T_VariableSetStmt:
732 VariableSetStmt *n = (VariableSetStmt *) parsetree;
734 SetPGVariable(n->name, n->value);
735 PS_SET_STATUS(commandTag = "SET VARIABLE");
739 case T_VariableShowStmt:
741 VariableShowStmt *n = (VariableShowStmt *) parsetree;
743 GetPGVariable(n->name);
744 PS_SET_STATUS(commandTag = "SHOW VARIABLE");
748 case T_VariableResetStmt:
750 VariableResetStmt *n = (VariableResetStmt *) parsetree;
752 ResetPGVariable(n->name);
753 PS_SET_STATUS(commandTag = "RESET VARIABLE");
758 * ******************************** TRIGGER statements *******************************
760 case T_CreateTrigStmt:
761 PS_SET_STATUS(commandTag = "CREATE");
764 CreateTrigger((CreateTrigStmt *) parsetree);
768 PS_SET_STATUS(commandTag = "DROP");
771 DropTrigger((DropTrigStmt *) parsetree);
775 * ************* PROCEDURAL LANGUAGE statements *****************
777 case T_CreatePLangStmt:
778 PS_SET_STATUS(commandTag = "CREATE");
781 CreateProceduralLanguage((CreatePLangStmt *) parsetree);
784 case T_DropPLangStmt:
785 PS_SET_STATUS(commandTag = "DROP");
788 DropProceduralLanguage((DropPLangStmt *) parsetree);
792 * ******************************** USER statements ****
795 case T_CreateUserStmt:
796 PS_SET_STATUS(commandTag = "CREATE USER");
799 CreateUser((CreateUserStmt *) parsetree);
802 case T_AlterUserStmt:
803 PS_SET_STATUS(commandTag = "ALTER USER");
806 AlterUser((AlterUserStmt *) parsetree);
810 PS_SET_STATUS(commandTag = "DROP USER");
813 DropUser((DropUserStmt *) parsetree);
817 PS_SET_STATUS(commandTag = "LOCK TABLE");
820 LockTableCommand((LockStmt *) parsetree);
823 case T_ConstraintsSetStmt:
824 PS_SET_STATUS(commandTag = "SET CONSTRAINTS");
827 DeferredTriggerSetState((ConstraintsSetStmt *) parsetree);
830 case T_CreateGroupStmt:
831 PS_SET_STATUS(commandTag = "CREATE GROUP");
834 CreateGroup((CreateGroupStmt *) parsetree);
837 case T_AlterGroupStmt:
838 PS_SET_STATUS(commandTag = "ALTER GROUP");
841 AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
844 case T_DropGroupStmt:
845 PS_SET_STATUS(commandTag = "DROP GROUP");
848 DropGroup((DropGroupStmt *) parsetree);
853 ReindexStmt *stmt = (ReindexStmt *) parsetree;
855 PS_SET_STATUS(commandTag = "REINDEX");
858 switch (stmt->reindexType)
861 relname = (char *) stmt->name;
862 if (IsSystemRelationName(relname))
864 if (!allowSystemTableMods && IsSystemRelationName(relname))
865 elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -O -P options",
867 if (!IsIgnoringSystemIndexes())
868 elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -P -O options",
872 if (!pg_ownercheck(userName, relname, RELNAME))
873 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
875 ReindexIndex(relname, stmt->force);
878 relname = (char *) stmt->name;
879 if (IsSystemRelationName(relname))
881 if (!allowSystemTableMods && IsSystemRelationName(relname))
882 elog(ERROR, "\"%s\" is a system table. call REINDEX under standalone postgres with -O -P options",
884 if (!IsIgnoringSystemIndexes())
885 elog(ERROR, "\"%s\" is a system table. call REINDEX under standalone postgres with -P -O options",
890 if (!pg_ownercheck(userName, relname, RELNAME))
891 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
893 ReindexTable(relname, stmt->force);
896 relname = (char *) stmt->name;
897 if (!allowSystemTableMods)
898 elog(ERROR, "must be called under standalone postgres with -O -P options");
899 if (!IsIgnoringSystemIndexes())
900 elog(ERROR, "must be called under standalone postgres with -P -O options");
901 ReindexDatabase(relname, stmt->force, false);
909 * ******************************** default ********************************
913 elog(ERROR, "ProcessUtility: command #%d unsupported",
919 * tell fe/be or whatever that we're done.
922 EndCommand(commandTag, dest);