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-2002, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.192 2003/02/13 05:20:01 momjian Exp $
15 *-------------------------------------------------------------------------
19 #include "access/heapam.h"
20 #include "catalog/catalog.h"
21 #include "catalog/namespace.h"
22 #include "catalog/pg_shadow.h"
23 #include "commands/async.h"
24 #include "commands/cluster.h"
25 #include "commands/comment.h"
26 #include "commands/copy.h"
27 #include "commands/conversioncmds.h"
28 #include "commands/dbcommands.h"
29 #include "commands/defrem.h"
30 #include "commands/explain.h"
31 #include "commands/lockcmds.h"
32 #include "commands/portalcmds.h"
33 #include "commands/prepare.h"
34 #include "commands/proclang.h"
35 #include "commands/schemacmds.h"
36 #include "commands/sequence.h"
37 #include "commands/tablecmds.h"
38 #include "commands/trigger.h"
39 #include "commands/typecmds.h"
40 #include "commands/user.h"
41 #include "commands/vacuum.h"
42 #include "commands/view.h"
43 #include "miscadmin.h"
44 #include "nodes/makefuncs.h"
45 #include "parser/parse_clause.h"
46 #include "parser/parse_expr.h"
47 #include "parser/parse_type.h"
48 #include "rewrite/rewriteDefine.h"
49 #include "rewrite/rewriteRemove.h"
50 #include "tcop/utility.h"
51 #include "utils/acl.h"
52 #include "utils/guc.h"
53 #include "utils/lsyscache.h"
54 #include "utils/syscache.h"
55 #include "access/xlog.h"
58 * Error-checking support for DROP commands
69 static struct kindstrings kindstringarray[] = {
70 {RELKIND_RELATION, "a", "table", "TABLE"},
71 {RELKIND_SEQUENCE, "a", "sequence", "SEQUENCE"},
72 {RELKIND_VIEW, "a", "view", "VIEW"},
73 {RELKIND_INDEX, "an", "index", "INDEX"},
74 {RELKIND_COMPOSITE_TYPE, "a", "type", "TYPE"},
75 {'\0', "a", "???", "???"}
80 DropErrorMsg(char *relname, char wrongkind, char rightkind)
82 struct kindstrings *rentry;
83 struct kindstrings *wentry;
85 for (rentry = kindstringarray; rentry->kind != '\0'; rentry++)
86 if (rentry->kind == rightkind)
88 Assert(rentry->kind != '\0');
90 for (wentry = kindstringarray; wentry->kind != '\0'; wentry++)
91 if (wentry->kind == wrongkind)
93 /* wrongkind could be something we don't have in our table... */
94 if (wentry->kind != '\0')
95 elog(ERROR, "\"%s\" is not %s %s. Use DROP %s to remove %s %s",
96 relname, rentry->indef_article, rentry->name,
97 wentry->command, wentry->indef_article, wentry->name);
99 elog(ERROR, "\"%s\" is not %s %s",
100 relname, rentry->indef_article, rentry->name);
104 CheckDropPermissions(RangeVar *rel, char rightkind)
106 struct kindstrings *rentry;
109 Form_pg_class classform;
111 for (rentry = kindstringarray; rentry->kind != '\0'; rentry++)
112 if (rentry->kind == rightkind)
114 Assert(rentry->kind != '\0');
116 relOid = RangeVarGetRelid(rel, true);
117 if (!OidIsValid(relOid))
118 elog(ERROR, "%s \"%s\" does not exist", rentry->name, rel->relname);
119 tuple = SearchSysCache(RELOID,
120 ObjectIdGetDatum(relOid),
122 if (!HeapTupleIsValid(tuple))
123 elog(ERROR, "%s \"%s\" does not exist", rentry->name, rel->relname);
125 classform = (Form_pg_class) GETSTRUCT(tuple);
127 if (classform->relkind != rightkind)
128 DropErrorMsg(rel->relname, classform->relkind, rightkind);
130 /* Allow DROP to either table owner or schema owner */
131 if (!pg_class_ownercheck(relOid, GetUserId()) &&
132 !pg_namespace_ownercheck(classform->relnamespace, GetUserId()))
133 aclcheck_error(ACLCHECK_NOT_OWNER, rel->relname);
135 if (!allowSystemTableMods && IsSystemClass(classform))
136 elog(ERROR, "%s \"%s\" is a system %s",
137 rentry->name, rel->relname, rentry->name);
139 ReleaseSysCache(tuple);
143 CheckOwnership(RangeVar *rel, bool noCatalogs)
148 relOid = RangeVarGetRelid(rel, false);
149 tuple = SearchSysCache(RELOID,
150 ObjectIdGetDatum(relOid),
152 if (!HeapTupleIsValid(tuple))
153 elog(ERROR, "Relation \"%s\" does not exist", rel->relname);
155 if (!pg_class_ownercheck(relOid, GetUserId()))
156 aclcheck_error(ACLCHECK_NOT_OWNER, rel->relname);
160 if (!allowSystemTableMods &&
161 IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
162 elog(ERROR, "relation \"%s\" is a system catalog",
166 ReleaseSysCache(tuple);
171 check_xact_readonly(Node *parsetree)
177 * Note: Commands that need to do more complicated checking are
181 switch (nodeTag(parsetree))
183 case T_AlterDatabaseSetStmt:
184 case T_AlterDomainStmt:
185 case T_AlterGroupStmt:
186 case T_AlterTableStmt:
188 case T_AlterUserStmt:
189 case T_AlterUserSetStmt:
192 case T_CreateCastStmt:
193 case T_CreateConversionStmt:
195 case T_CreateDomainStmt:
196 case T_CreateFunctionStmt:
197 case T_CreateGroupStmt:
199 case T_CreatePLangStmt:
200 case T_CreateOpClassStmt:
202 case T_CreateSchemaStmt:
203 case T_CreateSeqStmt:
205 case T_CreateTrigStmt:
206 case T_CompositeTypeStmt:
207 case T_CreateUserStmt:
209 case T_RemoveAggrStmt:
213 case T_RemoveFuncStmt:
214 case T_DropGroupStmt:
215 case T_DropPLangStmt:
216 case T_RemoveOperStmt:
217 case T_RemoveOpClassStmt:
218 case T_DropPropertyStmt:
222 elog(ERROR, "transaction is read-only");
232 * general utility function invoker
234 * parsetree: the parse tree for the utility statement
235 * dest: where to send results
236 * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
237 * in which to store a command completion status string.
239 * completionTag is only set nonempty if we want to return a nondefault
240 * status (currently, only used for MOVE/FETCH).
242 * completionTag may be NULL if caller doesn't want a status string.
245 ProcessUtility(Node *parsetree,
249 check_xact_readonly(parsetree);
252 completionTag[0] = '\0';
254 switch (nodeTag(parsetree))
257 * ******************************** transactions ********************************
259 case T_TransactionStmt:
261 TransactionStmt *stmt = (TransactionStmt *) parsetree;
265 case TRANS_STMT_BEGIN:
266 BeginTransactionBlock();
270 * START TRANSACTION, as defined by SQL99:
271 * Identical to BEGIN, except that it takes a few
272 * additional options.
274 case TRANS_STMT_START:
276 BeginTransactionBlock();
282 foreach(head, stmt->options)
284 DefElem *item = (DefElem *) lfirst(head);
286 if (strcmp(item->defname, "transaction_isolation")==0)
287 SetPGVariable("transaction_isolation",
288 makeList1(item->arg), false);
289 else if (strcmp(item->defname, "transaction_read_only")==0)
290 SetPGVariable("transaction_read_only",
291 makeList1(item->arg), false);
297 case TRANS_STMT_COMMIT:
298 EndTransactionBlock();
301 case TRANS_STMT_ROLLBACK:
302 UserAbortTransactionBlock();
309 * ************************* portal manipulation ***************************
311 case T_ClosePortalStmt:
313 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
315 PerformPortalClose(stmt->portalname, dest);
321 FetchStmt *stmt = (FetchStmt *) parsetree;
323 PerformPortalFetch(stmt->portalname,
324 stmt->direction == FETCH_FORWARD,
326 (stmt->ismove) ? None : dest,
332 * relation and attribute manipulation
334 case T_CreateSchemaStmt:
335 CreateSchemaCommand((CreateSchemaStmt *) parsetree);
342 relOid = DefineRelation((CreateStmt *) parsetree,
346 * Let AlterTableCreateToastTable decide if this one needs
347 * a secondary relation too.
349 CommandCounterIncrement();
350 AlterTableCreateToastTable(relOid, true);
356 DropStmt *stmt = (DropStmt *) parsetree;
359 foreach(arg, stmt->objects)
361 List *names = (List *) lfirst(arg);
364 switch (stmt->removeType)
367 rel = makeRangeVarFromNameList(names);
368 CheckDropPermissions(rel, RELKIND_RELATION);
369 RemoveRelation(rel, stmt->behavior);
373 rel = makeRangeVarFromNameList(names);
374 CheckDropPermissions(rel, RELKIND_SEQUENCE);
375 RemoveRelation(rel, stmt->behavior);
379 rel = makeRangeVarFromNameList(names);
380 CheckDropPermissions(rel, RELKIND_VIEW);
381 RemoveView(rel, stmt->behavior);
385 rel = makeRangeVarFromNameList(names);
386 CheckDropPermissions(rel, RELKIND_INDEX);
387 RemoveIndex(rel, stmt->behavior);
391 /* RemoveType does its own permissions checks */
392 RemoveType(names, stmt->behavior);
398 * RemoveDomain does its own permissions
401 RemoveDomain(names, stmt->behavior);
404 case DROP_CONVERSION:
405 DropConversionCommand(names, stmt->behavior);
411 * RemoveSchema does its own permissions
414 RemoveSchema(names, stmt->behavior);
419 * We used to need to do CommandCounterIncrement()
420 * here, but now it's done inside performDeletion().
428 TruncateStmt *stmt = (TruncateStmt *) parsetree;
430 TruncateRelation(stmt->relation);
435 CommentObject((CommentStmt *) parsetree);
439 DoCopy((CopyStmt *) parsetree);
443 PrepareQuery((PrepareStmt *) parsetree);
447 ExecuteQuery((ExecuteStmt *) parsetree, dest);
450 case T_DeallocateStmt:
451 DeallocateQuery((DeallocateStmt *) parsetree);
459 RenameStmt *stmt = (RenameStmt *) parsetree;
462 CheckOwnership(stmt->relation, true);
464 relid = RangeVarGetRelid(stmt->relation, false);
466 switch (stmt->renameType)
471 * RENAME TABLE requires that we (still) hold
472 * CREATE rights on the containing namespace,
473 * as well as ownership of the table.
475 Oid namespaceId = get_rel_namespace(relid);
478 aclresult = pg_namespace_aclcheck(namespaceId,
481 if (aclresult != ACLCHECK_OK)
482 aclcheck_error(aclresult,
483 get_namespace_name(namespaceId));
485 renamerel(relid, stmt->newname);
490 stmt->oldname, /* old att name */
491 stmt->newname, /* new att name */
492 interpretInhOption(stmt->relation->inhOpt), /* recursive? */
493 false); /* recursing already? */
497 stmt->oldname, /* old att name */
498 stmt->newname); /* new att name */
501 elog(ERROR, "ProcessUtility: Invalid type for RENAME: %d",
505 elog(ERROR, "ProcessUtility: Invalid type for RENAME: %d",
511 /* various Alter Table forms */
513 case T_AlterTableStmt:
515 AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
518 relid = RangeVarGetRelid(stmt->relation, false);
521 * Some or all of these functions are recursive to cover
522 * inherited things, so permission checks are done there.
524 switch (stmt->subtype)
526 case 'A': /* ADD COLUMN */
529 * Recursively add column to table and, if
530 * requested, to descendants
532 AlterTableAddColumn(relid,
533 interpretInhOption(stmt->relation->inhOpt),
534 (ColumnDef *) stmt->def);
536 case 'T': /* ALTER COLUMN DEFAULT */
539 * Recursively alter column default for table and,
540 * if requested, for descendants
542 AlterTableAlterColumnDefault(relid,
543 interpretInhOption(stmt->relation->inhOpt),
547 case 'N': /* ALTER COLUMN DROP NOT NULL */
548 AlterTableAlterColumnDropNotNull(relid,
549 interpretInhOption(stmt->relation->inhOpt),
552 case 'n': /* ALTER COLUMN SET NOT NULL */
553 AlterTableAlterColumnSetNotNull(relid,
554 interpretInhOption(stmt->relation->inhOpt),
557 case 'S': /* ALTER COLUMN STATISTICS */
558 case 'M': /* ALTER COLUMN STORAGE */
561 * Recursively alter column statistics for table
562 * and, if requested, for descendants
564 AlterTableAlterColumnFlags(relid,
565 interpretInhOption(stmt->relation->inhOpt),
570 case 'D': /* DROP COLUMN */
573 * Recursively drop column from table and, if
574 * requested, from descendants
576 AlterTableDropColumn(relid,
577 interpretInhOption(stmt->relation->inhOpt),
582 case 'C': /* ADD CONSTRAINT */
585 * Recursively add constraint to table and, if
586 * requested, to descendants
588 AlterTableAddConstraint(relid,
589 interpretInhOption(stmt->relation->inhOpt),
592 case 'X': /* DROP CONSTRAINT */
595 * Recursively drop constraint from table and, if
596 * requested, from descendants
598 AlterTableDropConstraint(relid,
599 interpretInhOption(stmt->relation->inhOpt),
603 case 'E': /* CREATE TOAST TABLE */
604 AlterTableCreateToastTable(relid, false);
606 case 'U': /* ALTER OWNER */
607 /* check that we are the superuser */
609 elog(ERROR, "ALTER TABLE: permission denied");
610 /* get_usesysid raises an error if no such user */
611 AlterTableOwner(relid,
612 get_usesysid(stmt->name));
614 case 'o': /* ADD OIDS */
615 AlterTableAlterOids(relid,
616 interpretInhOption(stmt->relation->inhOpt),
620 elog(ERROR, "ProcessUtility: Invalid type for AlterTableStmt: %d",
627 case T_AlterDomainStmt:
629 AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree;
632 * Some or all of these functions are recursive to cover
633 * inherited things, so permission checks are done there.
635 switch (stmt->subtype)
637 case 'T': /* ALTER COLUMN DEFAULT */
640 * Recursively alter column default for table and,
641 * if requested, for descendants
643 AlterDomainDefault(stmt->typename,
646 case 'N': /* ALTER COLUMN DROP NOT NULL */
647 AlterDomainNotNull(stmt->typename,
650 case 'O': /* ALTER COLUMN SET NOT NULL */
651 AlterDomainNotNull(stmt->typename,
654 case 'C': /* ADD CONSTRAINT */
655 AlterDomainAddConstraint(stmt->typename,
658 case 'X': /* DROP CONSTRAINT */
659 AlterDomainDropConstraint(stmt->typename,
663 case 'U': /* OWNER TO */
664 /* check that we are the superuser */
666 elog(ERROR, "ALTER DOMAIN: permission denied");
667 /* get_usesysid raises an error if no such user */
668 AlterTypeOwner(stmt->typename,
669 get_usesysid(stmt->name));
672 elog(ERROR, "ProcessUtility: Invalid type for AlterDomainStmt: %d",
681 ExecuteGrantStmt((GrantStmt *) parsetree);
685 * ******************************** object creation /
686 * destruction ********************************
691 DefineStmt *stmt = (DefineStmt *) parsetree;
695 case DEFINE_STMT_AGGREGATE:
696 DefineAggregate(stmt->defnames, stmt->definition);
698 case DEFINE_STMT_OPERATOR:
699 DefineOperator(stmt->defnames, stmt->definition);
701 case DEFINE_STMT_TYPE:
702 DefineType(stmt->defnames, stmt->definition);
708 case T_CompositeTypeStmt: /* CREATE TYPE (composite) */
710 CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
712 DefineCompositeType(stmt->typevar, stmt->coldeflist);
716 case T_ViewStmt: /* CREATE VIEW */
718 ViewStmt *stmt = (ViewStmt *) parsetree;
720 DefineView(stmt->view, stmt->query, stmt->replace);
724 case T_CreateFunctionStmt: /* CREATE FUNCTION */
725 CreateFunction((CreateFunctionStmt *) parsetree);
728 case T_IndexStmt: /* CREATE INDEX */
730 IndexStmt *stmt = (IndexStmt *) parsetree;
732 CheckOwnership(stmt->relation, true);
734 DefineIndex(stmt->relation, /* relation */
735 stmt->idxname, /* index name */
736 stmt->accessMethod, /* am name */
737 stmt->indexParams, /* parameters */
741 (Expr *) stmt->whereClause,
746 case T_RuleStmt: /* CREATE RULE */
747 DefineQueryRewrite((RuleStmt *) parsetree);
750 case T_CreateSeqStmt:
751 DefineSequence((CreateSeqStmt *) parsetree);
754 case T_RemoveAggrStmt:
755 RemoveAggregate((RemoveAggrStmt *) parsetree);
758 case T_RemoveFuncStmt:
759 RemoveFunction((RemoveFuncStmt *) parsetree);
762 case T_RemoveOperStmt:
763 RemoveOperator((RemoveOperStmt *) parsetree);
767 createdb((CreatedbStmt *) parsetree);
770 case T_AlterDatabaseSetStmt:
771 AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree);
776 DropdbStmt *stmt = (DropdbStmt *) parsetree;
778 dropdb(stmt->dbname);
782 /* Query-level asynchronous notification */
785 NotifyStmt *stmt = (NotifyStmt *) parsetree;
787 Async_Notify(stmt->relation->relname);
793 ListenStmt *stmt = (ListenStmt *) parsetree;
795 Async_Listen(stmt->relation->relname, MyProcPid);
801 UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
803 Async_Unlisten(stmt->relation->relname, MyProcPid);
809 LoadStmt *stmt = (LoadStmt *) parsetree;
811 closeAllVfds(); /* probably not necessary... */
812 load_file(stmt->filename);
817 cluster((ClusterStmt *) parsetree);
821 vacuum((VacuumStmt *) parsetree);
825 ExplainQuery((ExplainStmt *) parsetree, dest);
828 case T_VariableSetStmt:
830 VariableSetStmt *n = (VariableSetStmt *) parsetree;
833 * Special cases for special SQL syntax that
834 * effectively sets more than one variable per
837 if (strcmp(n->name, "TRANSACTION")==0)
841 foreach(head, n->args)
843 DefElem *item = (DefElem *) lfirst(head);
845 if (strcmp(item->defname, "transaction_isolation")==0)
846 SetPGVariable("transaction_isolation",
847 makeList1(item->arg), n->is_local);
848 else if (strcmp(item->defname, "transaction_read_only")==0)
849 SetPGVariable("transaction_read_only",
850 makeList1(item->arg), n->is_local);
853 else if (strcmp(n->name, "SESSION CHARACTERISTICS")==0)
857 foreach(head, n->args)
859 DefElem *item = (DefElem *) lfirst(head);
861 if (strcmp(item->defname, "transaction_isolation")==0)
862 SetPGVariable("default_transaction_isolation",
863 makeList1(item->arg), n->is_local);
864 else if (strcmp(item->defname, "transaction_read_only")==0)
865 SetPGVariable("default_transaction_read_only",
866 makeList1(item->arg), n->is_local);
870 SetPGVariable(n->name, n->args, n->is_local);
874 case T_VariableShowStmt:
876 VariableShowStmt *n = (VariableShowStmt *) parsetree;
878 GetPGVariable(n->name);
882 case T_VariableResetStmt:
884 VariableResetStmt *n = (VariableResetStmt *) parsetree;
886 ResetPGVariable(n->name);
890 case T_CreateTrigStmt:
891 CreateTrigger((CreateTrigStmt *) parsetree, false);
894 case T_DropPropertyStmt:
896 DropPropertyStmt *stmt = (DropPropertyStmt *) parsetree;
899 relId = RangeVarGetRelid(stmt->relation, false);
901 switch (stmt->removeType)
904 /* RemoveRewriteRule checks permissions */
905 RemoveRewriteRule(relId, stmt->property,
909 /* DropTrigger checks permissions */
910 DropTrigger(relId, stmt->property,
917 case T_CreatePLangStmt:
918 CreateProceduralLanguage((CreatePLangStmt *) parsetree);
921 case T_DropPLangStmt:
922 DropProceduralLanguage((DropPLangStmt *) parsetree);
926 * ******************************** DOMAIN statements ****
928 case T_CreateDomainStmt:
929 DefineDomain((CreateDomainStmt *) parsetree);
933 * ******************************** USER statements ****
935 case T_CreateUserStmt:
936 CreateUser((CreateUserStmt *) parsetree);
939 case T_AlterUserStmt:
940 AlterUser((AlterUserStmt *) parsetree);
943 case T_AlterUserSetStmt:
944 AlterUserSet((AlterUserSetStmt *) parsetree);
948 DropUser((DropUserStmt *) parsetree);
952 LockTableCommand((LockStmt *) parsetree);
955 case T_ConstraintsSetStmt:
956 DeferredTriggerSetState((ConstraintsSetStmt *) parsetree);
959 case T_CreateGroupStmt:
960 CreateGroup((CreateGroupStmt *) parsetree);
963 case T_AlterGroupStmt:
964 AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
967 case T_DropGroupStmt:
968 DropGroup((DropGroupStmt *) parsetree);
971 case T_CheckPointStmt:
973 elog(ERROR, "CHECKPOINT: permission denied");
974 CreateCheckPoint(false, false);
979 ReindexStmt *stmt = (ReindexStmt *) parsetree;
984 CheckOwnership(stmt->relation, false);
985 ReindexIndex(stmt->relation, stmt->force);
988 CheckOwnership(stmt->relation, false);
989 ReindexTable(stmt->relation, stmt->force);
991 case REINDEX_DATABASE:
992 ReindexDatabase(stmt->name, stmt->force, false);
999 case T_CreateConversionStmt:
1000 CreateConversionCommand((CreateConversionStmt *) parsetree);
1003 case T_CreateCastStmt:
1004 CreateCast((CreateCastStmt *) parsetree);
1007 case T_DropCastStmt:
1008 DropCast((DropCastStmt *) parsetree);
1011 case T_CreateOpClassStmt:
1012 DefineOpClass((CreateOpClassStmt *) parsetree);
1015 case T_RemoveOpClassStmt:
1016 RemoveOpClass((RemoveOpClassStmt *) parsetree);
1020 elog(ERROR, "ProcessUtility: command #%d unsupported",
1021 nodeTag(parsetree));