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.44 1998/07/26 04:30:48 scrappy 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"
54 #include "miscadmin.h"
55 #include "utils/acl.h"
56 #include "utils/syscache.h"
59 void DefineUser(CreateUserStmt *stmt);
60 void AlterUser(AlterUserStmt *stmt);
61 void RemoveUser(char *username);
63 extern const char **ps_status; /* from postgres.c */
66 * CHECK_IF_ABORTED() is used to avoid doing unnecessary
67 * processing within an aborted transaction block.
70 /* we have to use IF because of the 'break' */
71 #define CHECK_IF_ABORTED() \
74 if (IsAbortedTransactionBlockState()) \
76 elog(NOTICE, "(transaction aborted): %s", \
77 "all queries ignored until end of transaction block"); \
78 commandTag = "*ABORT STATE*"; \
84 * general utility function invoker
88 ProcessUtility(Node *parsetree,
91 char *commandTag = NULL;
96 userName = GetPgUserName();
98 switch (nodeTag(parsetree))
102 * ******************************** transactions ********************************
105 case T_TransactionStmt:
107 TransactionStmt *stmt = (TransactionStmt *) parsetree;
109 switch (stmt->command)
112 *ps_status = commandTag = "BEGIN";
114 BeginTransactionBlock();
118 *ps_status = commandTag = "END";
119 EndTransactionBlock();
123 *ps_status = commandTag = "ABORT";
124 UserAbortTransactionBlock();
131 * ******************************** portal manipulation ********************************
134 case T_ClosePortalStmt:
136 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
138 *ps_status = commandTag = "CLOSE";
141 PerformPortalClose(stmt->portalname, dest);
147 FetchStmt *stmt = (FetchStmt *) parsetree;
148 char *portalName = stmt->portalname;
152 *ps_status = commandTag = (stmt->ismove) ? "MOVE" : "FETCH";
155 forward = (bool) (stmt->direction == FORWARD);
158 * parser ensures that count is >= 0 and 'fetch ALL' -> 0
161 count = stmt->howMany;
162 PerformPortalFetch(portalName, forward, count, commandTag,
163 (stmt->ismove) ? None : dest); /* /dev/null for MOVE */
168 * ******************************** relation and attribute
169 * manipulation ********************************
173 *ps_status = commandTag = "CREATE";
176 DefineRelation((CreateStmt *) parsetree);
181 DestroyStmt *stmt = (DestroyStmt *) parsetree;
183 List *args = stmt->relNames;
186 *ps_status = commandTag = "DROP";
191 relname = strVal(lfirst(arg));
192 if (IsSystemRelationName(relname))
193 elog(ERROR, "class \"%s\" is a system catalog",
195 rel = heap_openr(relname);
196 if (RelationIsValid(rel))
198 if (stmt->sequence &&
199 rel->rd_rel->relkind != RELKIND_SEQUENCE)
200 elog(ERROR, "Use DROP TABLE to drop table '%s'",
202 if (!(stmt->sequence) &&
203 rel->rd_rel->relkind == RELKIND_SEQUENCE)
204 elog(ERROR, "Use DROP SEQUENCE to drop sequence '%s'",
209 if (!pg_ownercheck(userName, relname, RELNAME))
210 elog(ERROR, "you do not own class \"%s\"",
216 relname = strVal(lfirst(arg));
217 RemoveRelation(relname);
224 CopyStmt *stmt = (CopyStmt *) parsetree;
226 *ps_status = commandTag = "COPY";
229 DoCopy(stmt->relname,
232 (bool) (stmt->direction == FROM),
233 (bool) (stmt->filename == NULL),
236 * null filename means copy to/from stdout/stdin, rather
237 * than to/from a file.
246 AddAttrStmt *stmt = (AddAttrStmt *) parsetree;
248 *ps_status = commandTag = "ADD";
252 * owner checking done in PerformAddAttribute (now
255 PerformAddAttribute(stmt->relname,
258 (ColumnDef *) stmt->colDef);
267 RenameStmt *stmt = (RenameStmt *) parsetree;
269 *ps_status = commandTag = "RENAME";
272 relname = stmt->relname;
273 if (IsSystemRelationName(relname))
274 elog(ERROR, "class \"%s\" is a system catalog",
277 if (!pg_ownercheck(userName, relname, RELNAME))
278 elog(ERROR, "you do not own class \"%s\"",
283 * XXX using len == 3 to tell the difference
284 * between "rename rel to newrel" and
285 * "rename att in rel to newatt" will not
286 * work soon because "rename type/operator/rule"
287 * stuff is being added. - cim 10/24/90
289 * [another piece of amuzing but useless anecdote -- ay]
291 if (stmt->column == NULL)
296 * Note: we also rename the "type" tuple
297 * corresponding to the relation.
300 renamerel(relname, /* old name */
301 stmt->newname); /* new name */
302 TypeRename(relname, /* old name */
303 stmt->newname); /* new name */
311 renameatt(relname, /* relname */
312 stmt->column, /* old att name */
313 stmt->newname, /* new att name */
315 stmt->inh); /* recursive? */
320 case T_ChangeACLStmt:
322 ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
327 *ps_status = commandTag = "CHANGE";
332 modechg = stmt->modechg;
334 foreach(i, stmt->relNames)
336 relname = strVal(lfirst(i));
337 if (!pg_ownercheck(userName, relname, RELNAME))
338 elog(ERROR, "you do not own class \"%s\"",
342 foreach(i, stmt->relNames)
344 relname = strVal(lfirst(i));
345 ChangeAcl(relname, aip, modechg);
352 * ******************************** object creation /
353 * destruction ********************************
358 DefineStmt *stmt = (DefineStmt *) parsetree;
360 *ps_status = commandTag = "CREATE";
363 switch (stmt->defType)
366 DefineOperator(stmt->defname, /* operator name */
367 stmt->definition); /* rest */
370 DefineType(stmt->defname, stmt->definition);
373 DefineAggregate(stmt->defname, /* aggregate name */
374 stmt->definition); /* rest */
380 case T_ViewStmt: /* CREATE VIEW */
382 ViewStmt *stmt = (ViewStmt *) parsetree;
384 *ps_status = commandTag = "CREATE";
386 DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
390 case T_ProcedureStmt: /* CREATE FUNCTION */
391 *ps_status = commandTag = "CREATE";
393 CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */
396 case T_IndexStmt: /* CREATE INDEX */
398 IndexStmt *stmt = (IndexStmt *) parsetree;
400 *ps_status = commandTag = "CREATE";
402 DefineIndex(stmt->relname, /* relation name */
403 stmt->idxname, /* index name */
404 stmt->accessMethod, /* am name */
405 stmt->indexParams, /* parameters */
408 (Expr *) stmt->whereClause,
413 case T_RuleStmt: /* CREATE RULE */
415 RuleStmt *stmt = (RuleStmt *) parsetree;
419 relname = stmt->object->relname;
420 aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
421 if (aclcheck_result != ACLCHECK_OK)
422 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
424 *ps_status = commandTag = "CREATE";
426 DefineQueryRewrite(stmt);
430 case T_CreateSeqStmt:
431 *ps_status = commandTag = "CREATE";
434 DefineSequence((CreateSeqStmt *) parsetree);
439 ExtendStmt *stmt = (ExtendStmt *) parsetree;
441 *ps_status = commandTag = "EXTEND";
444 ExtendIndex(stmt->idxname, /* index name */
445 (Expr *) stmt->whereClause, /* where */
452 RemoveStmt *stmt = (RemoveStmt *) parsetree;
454 *ps_status = commandTag = "DROP";
457 switch (stmt->removeType)
460 relname = stmt->name;
461 if (IsSystemRelationName(relname))
462 elog(ERROR, "class \"%s\" is a system catalog index",
465 if (!pg_ownercheck(userName, relname, RELNAME))
466 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
468 RemoveIndex(relname);
472 char *rulename = stmt->name;
477 relationName = RewriteGetRuleEventRel(rulename);
478 aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
479 if (aclcheck_result != ACLCHECK_OK)
480 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
482 RemoveRewriteRule(rulename);
487 /* XXX moved to remove.c */
489 RemoveType(stmt->name);
493 char *viewName = stmt->name;
498 ruleName = MakeRetrieveViewRuleName(viewName);
499 relationName = RewriteGetRuleEventRel(ruleName);
500 if (!pg_ownercheck(userName, relationName, RELNAME))
501 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
504 RemoveView(viewName);
512 case T_RemoveAggrStmt:
514 RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
516 *ps_status = commandTag = "DROP";
518 RemoveAggregate(stmt->aggname, stmt->aggtype);
522 case T_RemoveFuncStmt:
524 RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
526 *ps_status = commandTag = "DROP";
528 RemoveFunction(stmt->funcname,
534 case T_RemoveOperStmt:
536 RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
537 char *type1 = (char *) NULL;
538 char *type2 = (char *) NULL;
540 *ps_status = commandTag = "DROP";
543 if (lfirst(stmt->args) != NULL)
544 type1 = strVal(lfirst(stmt->args));
545 if (lsecond(stmt->args) != NULL)
546 type2 = strVal(lsecond(stmt->args));
547 RemoveOperator(stmt->opname, type1, type2);
552 elog(ERROR, "CREATE VERSION is not currently implemented");
557 CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
559 *ps_status = commandTag = "CREATEDB";
562 createdb(stmt->dbname, stmt->dbpath, stmt->encoding);
564 createdb(stmt->dbname, stmt->dbpath);
569 case T_DestroydbStmt:
571 DestroydbStmt *stmt = (DestroydbStmt *) parsetree;
573 *ps_status = commandTag = "DESTROYDB";
575 destroydb(stmt->dbname);
579 /* Query-level asynchronous notification */
582 NotifyStmt *stmt = (NotifyStmt *) parsetree;
584 *ps_status = commandTag = "NOTIFY";
587 Async_Notify(stmt->relname);
593 ListenStmt *stmt = (ListenStmt *) parsetree;
595 *ps_status = commandTag = "LISTEN";
598 Async_Listen(stmt->relname, MyProcPid);
603 * ******************************** dynamic loader ********************************
608 LoadStmt *stmt = (LoadStmt *) parsetree;
612 *ps_status = commandTag = "LOAD";
615 filename = stmt->filename;
617 if ((fp = AllocateFile(filename, "r")) == NULL)
618 elog(ERROR, "LOAD: could not open file %s", filename);
626 ClusterStmt *stmt = (ClusterStmt *) parsetree;
628 *ps_status = commandTag = "CLUSTER";
631 cluster(stmt->relname, stmt->indexname);
636 *ps_status = commandTag = "VACUUM";
638 vacuum(((VacuumStmt *) parsetree)->vacrel,
639 ((VacuumStmt *) parsetree)->verbose,
640 ((VacuumStmt *) parsetree)->analyze,
641 ((VacuumStmt *) parsetree)->va_spec);
646 ExplainStmt *stmt = (ExplainStmt *) parsetree;
648 *ps_status = commandTag = "EXPLAIN";
651 ExplainQuery(stmt->query, stmt->verbose, dest);
656 * ******************************** Tioga-related statements *******************************
660 RecipeStmt *stmt = (RecipeStmt *) parsetree;
662 *ps_status = commandTag = "EXECUTE RECIPE";
669 * ******************************** set variable statements *******************************
671 case T_VariableSetStmt:
673 VariableSetStmt *n = (VariableSetStmt *) parsetree;
675 SetPGVariable(n->name, n->value);
676 *ps_status = commandTag = "SET VARIABLE";
680 case T_VariableShowStmt:
682 VariableShowStmt *n = (VariableShowStmt *) parsetree;
684 GetPGVariable(n->name);
685 *ps_status = commandTag = "SHOW VARIABLE";
689 case T_VariableResetStmt:
691 VariableResetStmt *n = (VariableResetStmt *) parsetree;
693 ResetPGVariable(n->name);
694 *ps_status = commandTag = "RESET VARIABLE";
699 * ******************************** TRIGGER statements *******************************
701 case T_CreateTrigStmt:
702 *ps_status = commandTag = "CREATE";
705 CreateTrigger((CreateTrigStmt *) parsetree);
709 *ps_status = commandTag = "DROP";
712 DropTrigger((DropTrigStmt *) parsetree);
716 * ************* PROCEDURAL LANGUAGE statements *****************
718 case T_CreatePLangStmt:
719 *ps_status = commandTag = "CREATE";
722 CreateProceduralLanguage((CreatePLangStmt *) parsetree);
725 case T_DropPLangStmt:
726 *ps_status = commandTag = "DROP";
729 DropProceduralLanguage((DropPLangStmt *) parsetree);
733 * ******************************** USER statements ****
736 case T_CreateUserStmt:
737 *ps_status = commandTag = "CREATE USER";
740 DefineUser((CreateUserStmt *) parsetree);
743 case T_AlterUserStmt:
744 *ps_status = commandTag = "ALTER USER";
747 AlterUser((AlterUserStmt *) parsetree);
751 *ps_status = commandTag = "DROP USER";
754 RemoveUser(((DropUserStmt *) parsetree)->user);
759 * ******************************** default ********************************
763 elog(ERROR, "ProcessUtility: command #%d unsupported",
769 * tell fe/be or whatever that we're done.
772 EndCommand(commandTag, dest);