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.50 1998/09/25 13:47:27 thomas Exp $
14 *-------------------------------------------------------------------------
17 #include "access/xact.h"
18 #include "access/heapam.h"
19 #include "catalog/catalog.h"
20 #include "catalog/pg_type.h"
22 #include "commands/async.h"
23 #include "commands/cluster.h"
24 #include "commands/command.h"
25 #include "commands/copy.h"
26 #include "commands/creatinh.h"
27 #include "commands/dbcommands.h"
28 #include "commands/sequence.h"
29 #include "commands/defrem.h"
30 #include "commands/rename.h"
31 #include "commands/view.h"
32 #include "commands/version.h"
33 #include "commands/vacuum.h"
34 #include "commands/recipe.h"
35 #include "commands/explain.h"
36 #include "commands/trigger.h"
37 #include "commands/proclang.h"
38 #include "commands/variable.h"
40 #include "nodes/parsenodes.h"
41 #include "../backend/parser/parse.h"
42 #include "utils/builtins.h"
43 #include "utils/acl.h"
44 #include "utils/palloc.h"
45 #include "rewrite/rewriteRemove.h"
46 #include "rewrite/rewriteDefine.h"
47 #include "tcop/tcopdebug.h"
48 #include "tcop/dest.h"
49 #include "tcop/utility.h"
50 #include "fmgr.h" /* For load_file() */
51 #include "storage/fd.h"
52 #include "utils/ps_status.h"
55 #include "miscadmin.h"
56 #include "utils/acl.h"
57 #include "utils/syscache.h"
60 void DefineUser(CreateUserStmt *stmt);
61 void AlterUser(AlterUserStmt *stmt);
62 void RemoveUser(char *username);
65 * CHECK_IF_ABORTED() is used to avoid doing unnecessary
66 * processing within an aborted transaction block.
69 /* we have to use IF because of the 'break' */
70 #define CHECK_IF_ABORTED() \
73 if (IsAbortedTransactionBlockState()) \
75 elog(NOTICE, "(transaction aborted): %s", \
76 "all queries ignored until end of transaction block"); \
77 commandTag = "*ABORT STATE*"; \
83 * general utility function invoker
87 ProcessUtility(Node *parsetree,
90 char *commandTag = NULL;
95 userName = GetPgUserName();
97 switch (nodeTag(parsetree))
101 * ******************************** transactions ********************************
104 case T_TransactionStmt:
106 TransactionStmt *stmt = (TransactionStmt *) parsetree;
108 switch (stmt->command)
111 PS_SET_STATUS(commandTag = "BEGIN");
113 BeginTransactionBlock();
117 PS_SET_STATUS(commandTag = "END");
118 EndTransactionBlock();
122 PS_SET_STATUS(commandTag = "ABORT");
123 UserAbortTransactionBlock();
130 * ******************************** portal manipulation ********************************
133 case T_ClosePortalStmt:
135 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
137 PS_SET_STATUS(commandTag = "CLOSE");
140 PerformPortalClose(stmt->portalname, dest);
146 FetchStmt *stmt = (FetchStmt *) parsetree;
147 char *portalName = stmt->portalname;
151 PS_SET_STATUS(commandTag = (stmt->ismove) ? "MOVE" : "FETCH");
154 forward = (bool) (stmt->direction == FORWARD);
157 * parser ensures that count is >= 0 and 'fetch ALL' -> 0
160 count = stmt->howMany;
161 PerformPortalFetch(portalName, forward, count, commandTag,
162 (stmt->ismove) ? None : dest); /* /dev/null for MOVE */
167 * ******************************** relation and attribute
168 * manipulation ********************************
172 PS_SET_STATUS(commandTag = "CREATE");
175 DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
180 DestroyStmt *stmt = (DestroyStmt *) parsetree;
182 List *args = stmt->relNames;
185 PS_SET_STATUS(commandTag = "DROP");
190 relname = strVal(lfirst(arg));
191 if (IsSystemRelationName(relname))
192 elog(ERROR, "class \"%s\" is a system catalog",
194 rel = heap_openr(relname);
195 if (RelationIsValid(rel))
197 if (stmt->sequence &&
198 rel->rd_rel->relkind != RELKIND_SEQUENCE)
199 elog(ERROR, "Use DROP TABLE to drop table '%s'",
201 if (!(stmt->sequence) &&
202 rel->rd_rel->relkind == RELKIND_SEQUENCE)
203 elog(ERROR, "Use DROP SEQUENCE to drop sequence '%s'",
208 if (!pg_ownercheck(userName, relname, RELNAME))
209 elog(ERROR, "you do not own class \"%s\"",
215 relname = strVal(lfirst(arg));
216 RemoveRelation(relname);
223 CopyStmt *stmt = (CopyStmt *) parsetree;
225 PS_SET_STATUS(commandTag = "COPY");
228 DoCopy(stmt->relname,
231 (bool) (stmt->direction == FROM),
232 (bool) (stmt->filename == NULL),
235 * null filename means copy to/from stdout/stdin, rather
236 * than to/from a file.
245 AddAttrStmt *stmt = (AddAttrStmt *) parsetree;
247 PS_SET_STATUS(commandTag = "ADD");
251 * owner checking done in PerformAddAttribute (now
254 PerformAddAttribute(stmt->relname,
257 (ColumnDef *) stmt->colDef);
266 RenameStmt *stmt = (RenameStmt *) parsetree;
268 PS_SET_STATUS(commandTag = "RENAME");
271 relname = stmt->relname;
272 if (IsSystemRelationName(relname))
273 elog(ERROR, "class \"%s\" is a system catalog",
276 if (!pg_ownercheck(userName, relname, RELNAME))
277 elog(ERROR, "you do not own class \"%s\"",
282 * XXX using len == 3 to tell the difference
283 * between "rename rel to newrel" and
284 * "rename att in rel to newatt" will not
285 * work soon because "rename type/operator/rule"
286 * stuff is being added. - cim 10/24/90
288 * [another piece of amuzing but useless anecdote -- ay]
290 if (stmt->column == NULL)
295 * Note: we also rename the "type" tuple
296 * corresponding to the relation.
299 renamerel(relname, /* old name */
300 stmt->newname); /* new name */
301 TypeRename(relname, /* old name */
302 stmt->newname); /* new name */
310 renameatt(relname, /* relname */
311 stmt->column, /* old att name */
312 stmt->newname, /* new att name */
314 stmt->inh); /* recursive? */
319 case T_ChangeACLStmt:
321 ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
326 PS_SET_STATUS(commandTag = "CHANGE");
331 modechg = stmt->modechg;
333 foreach(i, stmt->relNames)
335 relname = strVal(lfirst(i));
336 if (!pg_ownercheck(userName, relname, RELNAME))
337 elog(ERROR, "you do not own class \"%s\"",
341 foreach(i, stmt->relNames)
343 relname = strVal(lfirst(i));
344 ChangeAcl(relname, aip, modechg);
351 * ******************************** object creation /
352 * destruction ********************************
357 DefineStmt *stmt = (DefineStmt *) parsetree;
359 PS_SET_STATUS(commandTag = "CREATE");
362 switch (stmt->defType)
365 DefineOperator(stmt->defname, /* operator name */
366 stmt->definition); /* rest */
369 DefineType(stmt->defname, stmt->definition);
372 DefineAggregate(stmt->defname, /* aggregate name */
373 stmt->definition); /* rest */
379 case T_ViewStmt: /* CREATE VIEW */
381 ViewStmt *stmt = (ViewStmt *) parsetree;
383 PS_SET_STATUS(commandTag = "CREATE");
385 DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
389 case T_ProcedureStmt: /* CREATE FUNCTION */
390 PS_SET_STATUS(commandTag = "CREATE");
392 CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */
395 case T_IndexStmt: /* CREATE INDEX */
397 IndexStmt *stmt = (IndexStmt *) parsetree;
399 PS_SET_STATUS(commandTag = "CREATE");
401 DefineIndex(stmt->relname, /* relation name */
402 stmt->idxname, /* index name */
403 stmt->accessMethod, /* am name */
404 stmt->indexParams, /* parameters */
407 (Expr *) stmt->whereClause,
412 case T_RuleStmt: /* CREATE RULE */
414 RuleStmt *stmt = (RuleStmt *) parsetree;
418 relname = stmt->object->relname;
419 aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
420 if (aclcheck_result != ACLCHECK_OK)
421 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
423 PS_SET_STATUS(commandTag = "CREATE");
425 DefineQueryRewrite(stmt);
429 case T_CreateSeqStmt:
430 PS_SET_STATUS(commandTag = "CREATE");
433 DefineSequence((CreateSeqStmt *) parsetree);
438 ExtendStmt *stmt = (ExtendStmt *) parsetree;
440 PS_SET_STATUS(commandTag = "EXTEND");
443 ExtendIndex(stmt->idxname, /* index name */
444 (Expr *) stmt->whereClause, /* where */
451 RemoveStmt *stmt = (RemoveStmt *) parsetree;
453 PS_SET_STATUS(commandTag = "DROP");
456 switch (stmt->removeType)
459 relname = stmt->name;
460 if (IsSystemRelationName(relname))
461 elog(ERROR, "class \"%s\" is a system catalog index",
464 if (!pg_ownercheck(userName, relname, RELNAME))
465 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
467 RemoveIndex(relname);
471 char *rulename = stmt->name;
476 relationName = RewriteGetRuleEventRel(rulename);
477 aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
478 if (aclcheck_result != ACLCHECK_OK)
479 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
481 RemoveRewriteRule(rulename);
486 /* XXX moved to remove.c */
488 RemoveType(stmt->name);
492 char *viewName = stmt->name;
497 ruleName = MakeRetrieveViewRuleName(viewName);
498 relationName = RewriteGetRuleEventRel(ruleName);
499 if (!pg_ownercheck(userName, relationName, RELNAME))
500 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
503 RemoveView(viewName);
511 case T_RemoveAggrStmt:
513 RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
515 PS_SET_STATUS(commandTag = "DROP");
517 RemoveAggregate(stmt->aggname, stmt->aggtype);
521 case T_RemoveFuncStmt:
523 RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
525 PS_SET_STATUS(commandTag = "DROP");
527 RemoveFunction(stmt->funcname,
533 case T_RemoveOperStmt:
535 RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
536 char *type1 = (char *) NULL;
537 char *type2 = (char *) NULL;
539 PS_SET_STATUS(commandTag = "DROP");
542 if (lfirst(stmt->args) != NULL)
543 type1 = strVal(lfirst(stmt->args));
544 if (lsecond(stmt->args) != NULL)
545 type2 = strVal(lsecond(stmt->args));
546 RemoveOperator(stmt->opname, type1, type2);
551 elog(ERROR, "CREATE VERSION is not currently implemented");
556 CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
558 PS_SET_STATUS(commandTag = "CREATEDB");
560 createdb(stmt->dbname, stmt->dbpath, stmt->encoding);
564 case T_DestroydbStmt:
566 DestroydbStmt *stmt = (DestroydbStmt *) parsetree;
568 PS_SET_STATUS(commandTag = "DESTROYDB");
570 destroydb(stmt->dbname);
574 /* Query-level asynchronous notification */
577 NotifyStmt *stmt = (NotifyStmt *) parsetree;
579 PS_SET_STATUS(commandTag = "NOTIFY");
582 Async_Notify(stmt->relname);
588 ListenStmt *stmt = (ListenStmt *) parsetree;
590 PS_SET_STATUS(commandTag = "LISTEN");
593 Async_Listen(stmt->relname, MyProcPid);
599 UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
601 PS_SET_STATUS(commandTag = "UNLISTEN");
604 Async_Unlisten(stmt->relname, MyProcPid);
609 * ******************************** dynamic loader ********************************
614 LoadStmt *stmt = (LoadStmt *) parsetree;
618 PS_SET_STATUS(commandTag = "LOAD");
621 filename = stmt->filename;
623 if ((fp = AllocateFile(filename, "r")) == NULL)
624 elog(ERROR, "LOAD: could not open file '%s'", filename);
632 ClusterStmt *stmt = (ClusterStmt *) parsetree;
634 PS_SET_STATUS(commandTag = "CLUSTER");
637 cluster(stmt->relname, stmt->indexname);
642 PS_SET_STATUS(commandTag = "VACUUM");
644 vacuum(((VacuumStmt *) parsetree)->vacrel,
645 ((VacuumStmt *) parsetree)->verbose,
646 ((VacuumStmt *) parsetree)->analyze,
647 ((VacuumStmt *) parsetree)->va_spec);
652 ExplainStmt *stmt = (ExplainStmt *) parsetree;
654 PS_SET_STATUS(commandTag = "EXPLAIN");
657 ExplainQuery(stmt->query, stmt->verbose, dest);
662 * ******************************** Tioga-related statements *******************************
666 RecipeStmt *stmt = (RecipeStmt *) parsetree;
668 PS_SET_STATUS(commandTag = "EXECUTE RECIPE");
675 * ******************************** set variable statements *******************************
677 case T_VariableSetStmt:
679 VariableSetStmt *n = (VariableSetStmt *) parsetree;
681 SetPGVariable(n->name, n->value);
682 PS_SET_STATUS(commandTag = "SET VARIABLE");
686 case T_VariableShowStmt:
688 VariableShowStmt *n = (VariableShowStmt *) parsetree;
690 GetPGVariable(n->name);
691 PS_SET_STATUS(commandTag = "SHOW VARIABLE");
695 case T_VariableResetStmt:
697 VariableResetStmt *n = (VariableResetStmt *) parsetree;
699 ResetPGVariable(n->name);
700 PS_SET_STATUS(commandTag = "RESET VARIABLE");
705 * ******************************** TRIGGER statements *******************************
707 case T_CreateTrigStmt:
708 PS_SET_STATUS(commandTag = "CREATE");
711 CreateTrigger((CreateTrigStmt *) parsetree);
715 PS_SET_STATUS(commandTag = "DROP");
718 DropTrigger((DropTrigStmt *) parsetree);
722 * ************* PROCEDURAL LANGUAGE statements *****************
724 case T_CreatePLangStmt:
725 PS_SET_STATUS(commandTag = "CREATE");
728 CreateProceduralLanguage((CreatePLangStmt *) parsetree);
731 case T_DropPLangStmt:
732 PS_SET_STATUS(commandTag = "DROP");
735 DropProceduralLanguage((DropPLangStmt *) parsetree);
739 * ******************************** USER statements ****
742 case T_CreateUserStmt:
743 PS_SET_STATUS(commandTag = "CREATE USER");
746 DefineUser((CreateUserStmt *) parsetree);
749 case T_AlterUserStmt:
750 PS_SET_STATUS(commandTag = "ALTER USER");
753 AlterUser((AlterUserStmt *) parsetree);
757 PS_SET_STATUS(commandTag = "DROP USER");
760 RemoveUser(((DropUserStmt *) parsetree)->user);
765 * ******************************** default ********************************
769 elog(ERROR, "ProcessUtility: command #%d unsupported",
775 * tell fe/be or whatever that we're done.
778 EndCommand(commandTag, dest);