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.36 1998/01/05 18:43:09 momjian 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);
64 * CHECK_IF_ABORTED() is used to avoid doing unnecessary
65 * processing within an aborted transaction block.
68 #define CHECK_IF_ABORTED() \
69 if (IsAbortedTransactionBlockState()) { \
70 elog(NOTICE, "(transaction aborted): %s", \
71 "queries ignored until END"); \
72 commandTag = "*ABORT STATE*"; \
77 * general utility function invoker
81 ProcessUtility(Node * parsetree,
84 char *commandTag = NULL;
89 userName = GetPgUserName();
91 switch (nodeTag(parsetree))
95 * ******************************** transactions ********************************
98 case T_TransactionStmt:
100 TransactionStmt *stmt = (TransactionStmt *) parsetree;
102 switch (stmt->command)
105 commandTag = "BEGIN";
107 BeginTransactionBlock();
112 EndTransactionBlock();
116 commandTag = "ABORT";
117 UserAbortTransactionBlock();
124 * ******************************** portal manipulation ********************************
127 case T_ClosePortalStmt:
129 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
131 commandTag = "CLOSE";
134 PerformPortalClose(stmt->portalname, dest);
140 FetchStmt *stmt = (FetchStmt *) parsetree;
141 char *portalName = stmt->portalname;
145 commandTag = (stmt->ismove) ? "MOVE" : "FETCH";
148 forward = (bool) (stmt->direction == FORWARD);
151 * parser ensures that count is >= 0 and 'fetch ALL' -> 0
154 count = stmt->howMany;
155 PerformPortalFetch(portalName, forward, count, commandTag,
156 (stmt->ismove) ? None : dest); /* /dev/null for MOVE */
161 * ******************************** relation and attribute
162 * manipulation ********************************
166 commandTag = "CREATE";
169 DefineRelation((CreateStmt *) parsetree);
174 DestroyStmt *stmt = (DestroyStmt *) parsetree;
176 List *args = stmt->relNames;
184 relname = strVal(lfirst(arg));
185 if (IsSystemRelationName(relname))
186 elog(ERROR, "class \"%s\" is a system catalog",
188 rel = heap_openr(relname);
189 if (RelationIsValid(rel))
191 if (stmt->sequence &&
192 rel->rd_rel->relkind != RELKIND_SEQUENCE)
193 elog(ERROR, "Use DROP TABLE to drop table '%s'",
195 if (!(stmt->sequence) &&
196 rel->rd_rel->relkind == RELKIND_SEQUENCE)
197 elog(ERROR, "Use DROP SEQUENCE to drop sequence '%s'",
202 if (!pg_ownercheck(userName, relname, RELNAME))
203 elog(ERROR, "you do not own class \"%s\"",
209 relname = strVal(lfirst(arg));
210 RemoveRelation(relname);
217 CopyStmt *stmt = (CopyStmt *) parsetree;
222 DoCopy(stmt->relname,
225 (bool) (stmt->direction == FROM),
226 (bool) (stmt->filename == NULL),
229 * null filename means copy to/from stdout/stdin, rather
230 * than to/from a file.
239 AddAttrStmt *stmt = (AddAttrStmt *) parsetree;
245 * owner checking done in PerformAddAttribute (now recursive)
247 PerformAddAttribute(stmt->relname,
250 (ColumnDef *)stmt->colDef);
259 RenameStmt *stmt = (RenameStmt *) parsetree;
261 commandTag = "RENAME";
264 relname = stmt->relname;
265 if (IsSystemRelationName(relname))
266 elog(ERROR, "class \"%s\" is a system catalog",
269 if (!pg_ownercheck(userName, relname, RELNAME))
270 elog(ERROR, "you do not own class \"%s\"",
275 * XXX using len == 3 to tell the difference
276 * between "rename rel to newrel" and
277 * "rename att in rel to newatt" will not
278 * work soon because "rename type/operator/rule"
279 * stuff is being added. - cim 10/24/90
281 * [another piece of amuzing but useless anecdote -- ay]
283 if (stmt->column == NULL)
288 * Note: we also rename the "type" tuple
289 * corresponding to the relation.
292 renamerel(relname, /* old name */
293 stmt->newname); /* new name */
294 TypeRename(relname, /* old name */
295 stmt->newname); /* new name */
303 renameatt(relname, /* relname */
304 stmt->column, /* old att name */
305 stmt->newname, /* new att name */
307 stmt->inh); /* recursive? */
312 case T_ChangeACLStmt:
314 ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
319 commandTag = "CHANGE";
324 modechg = stmt->modechg;
326 foreach(i, stmt->relNames)
328 relname = strVal(lfirst(i));
329 if (!pg_ownercheck(userName, relname, RELNAME))
330 elog(ERROR, "you do not own class \"%s\"",
334 foreach(i, stmt->relNames)
336 relname = strVal(lfirst(i));
337 ChangeAcl(relname, aip, modechg);
344 * ******************************** object creation /
345 * destruction ********************************
350 DefineStmt *stmt = (DefineStmt *) parsetree;
352 commandTag = "CREATE";
355 switch (stmt->defType)
358 DefineOperator(stmt->defname, /* operator name */
359 stmt->definition); /* rest */
363 DefineType(stmt->defname, stmt->definition);
367 DefineAggregate(stmt->defname, /* aggregate name */
368 stmt->definition); /* rest */
374 case T_ViewStmt: /* CREATE VIEW */
376 ViewStmt *stmt = (ViewStmt *) parsetree;
378 commandTag = "CREATE";
380 DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
384 case T_ProcedureStmt: /* CREATE FUNCTION */
385 commandTag = "CREATE";
387 CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */
390 case T_IndexStmt: /* CREATE INDEX */
392 IndexStmt *stmt = (IndexStmt *) parsetree;
394 commandTag = "CREATE";
396 DefineIndex(stmt->relname, /* relation name */
397 stmt->idxname, /* index name */
398 stmt->accessMethod, /* am name */
399 stmt->indexParams, /* parameters */
402 (Expr *) stmt->whereClause,
407 case T_RuleStmt: /* CREATE RULE */
409 RuleStmt *stmt = (RuleStmt *) parsetree;
413 relname = stmt->object->relname;
414 aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
415 if (aclcheck_result != ACLCHECK_OK)
416 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
418 commandTag = "CREATE";
420 DefineQueryRewrite(stmt);
424 case T_CreateSeqStmt:
425 commandTag = "CREATE";
428 DefineSequence((CreateSeqStmt *) parsetree);
433 ExtendStmt *stmt = (ExtendStmt *) parsetree;
435 commandTag = "EXTEND";
438 ExtendIndex(stmt->idxname, /* index name */
439 (Expr *) stmt->whereClause, /* where */
446 RemoveStmt *stmt = (RemoveStmt *) parsetree;
451 switch (stmt->removeType)
454 relname = stmt->name;
455 if (IsSystemRelationName(relname))
456 elog(ERROR, "class \"%s\" is a system catalog index",
459 if (!pg_ownercheck(userName, relname, RELNAME))
460 elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
462 RemoveIndex(relname);
466 char *rulename = stmt->name;
471 relationName = RewriteGetRuleEventRel(rulename);
472 aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
473 if (aclcheck_result != ACLCHECK_OK)
475 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
478 RemoveRewriteRule(rulename);
483 /* XXX moved to remove.c */
485 RemoveType(stmt->name);
489 char *viewName = stmt->name;
494 ruleName = MakeRetrieveViewRuleName(viewName);
495 relationName = RewriteGetRuleEventRel(ruleName);
496 if (!pg_ownercheck(userName, relationName, RELNAME))
497 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
500 RemoveView(viewName);
508 case T_RemoveAggrStmt:
510 RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
514 RemoveAggregate(stmt->aggname, stmt->aggtype);
518 case T_RemoveFuncStmt:
520 RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
524 RemoveFunction(stmt->funcname,
530 case T_RemoveOperStmt:
532 RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
533 char *type1 = (char *) NULL;
534 char *type2 = (char *) NULL;
539 if (lfirst(stmt->args) != NULL)
540 type1 = strVal(lfirst(stmt->args));
541 if (lsecond(stmt->args) != NULL)
542 type2 = strVal(lsecond(stmt->args));
543 RemoveOperator(stmt->opname, type1, type2);
549 elog(ERROR, "CREATE VERSION is not currently implemented");
555 CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
557 commandTag = "CREATEDB";
559 createdb(stmt->dbname, stmt->dbpath);
563 case T_DestroydbStmt:
565 DestroydbStmt *stmt = (DestroydbStmt *) parsetree;
567 commandTag = "DESTROYDB";
569 destroydb(stmt->dbname);
573 /* Query-level asynchronous notification */
576 NotifyStmt *stmt = (NotifyStmt *) parsetree;
578 commandTag = "NOTIFY";
581 Async_Notify(stmt->relname);
587 ListenStmt *stmt = (ListenStmt *) parsetree;
589 commandTag = "LISTEN";
592 Async_Listen(stmt->relname, MasterPid);
597 * ******************************** dynamic loader ********************************
602 LoadStmt *stmt = (LoadStmt *) parsetree;
609 filename = stmt->filename;
611 if ((fp = AllocateFile(filename, "r")) == NULL)
612 elog(ERROR, "LOAD: could not open file %s", filename);
620 ClusterStmt *stmt = (ClusterStmt *) parsetree;
622 commandTag = "CLUSTER";
625 cluster(stmt->relname, stmt->indexname);
630 commandTag = "VACUUM";
632 vacuum(((VacuumStmt *) parsetree)->vacrel,
633 ((VacuumStmt *) parsetree)->verbose,
634 ((VacuumStmt *) parsetree)->analyze,
635 ((VacuumStmt *) parsetree)->va_spec);
640 ExplainStmt *stmt = (ExplainStmt *) parsetree;
642 commandTag = "EXPLAIN";
645 ExplainQuery(stmt->query, stmt->verbose, dest);
650 * ******************************** Tioga-related statements *******************************
654 RecipeStmt *stmt = (RecipeStmt *) parsetree;
656 commandTag = "EXECUTE RECIPE";
663 * ******************************** set variable statements *******************************
665 case T_VariableSetStmt:
667 VariableSetStmt *n = (VariableSetStmt *) parsetree;
669 SetPGVariable(n->name, n->value);
670 commandTag = "SET VARIABLE";
674 case T_VariableShowStmt:
676 VariableShowStmt *n = (VariableShowStmt *) parsetree;
678 GetPGVariable(n->name);
679 commandTag = "SHOW VARIABLE";
683 case T_VariableResetStmt:
685 VariableResetStmt *n = (VariableResetStmt *) parsetree;
687 ResetPGVariable(n->name);
688 commandTag = "RESET VARIABLE";
693 * ******************************** TRIGGER statements *******************************
695 case T_CreateTrigStmt:
696 commandTag = "CREATE";
699 CreateTrigger((CreateTrigStmt *) parsetree);
706 DropTrigger((DropTrigStmt *) parsetree);
710 * ************* PROCEDURAL LANGUAGE statements *****************
712 case T_CreatePLangStmt:
713 commandTag = "CREATE";
716 CreateProceduralLanguage((CreatePLangStmt *) parsetree);
719 case T_DropPLangStmt:
723 DropProceduralLanguage((DropPLangStmt *) parsetree);
727 * ******************************** USER statements ****
730 case T_CreateUserStmt:
731 commandTag = "CREATE USER";
734 DefineUser((CreateUserStmt*)parsetree);
737 case T_AlterUserStmt:
738 commandTag = "ALTER USER";
741 AlterUser((AlterUserStmt*)parsetree);
745 commandTag = "DROP USER";
748 RemoveUser(((DropUserStmt*)parsetree)->user);
753 * ******************************** default ********************************
757 elog(ERROR, "ProcessUtility: command #%d unsupported",
763 * tell fe/be or whatever that we're done.
766 EndCommand(commandTag, dest);