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.20 1997/08/18 20:53:35 momjian Exp $
14 *-------------------------------------------------------------------------
17 #include "parser/dbcommands.h"
18 #include "access/xact.h"
19 #include "access/heapam.h"
20 #include "catalog/catalog.h"
21 #include "catalog/pg_type.h"
23 #include "commands/async.h"
24 #include "commands/cluster.h"
25 #include "commands/command.h"
26 #include "commands/copy.h"
27 #include "commands/creatinh.h"
28 #include "commands/sequence.h"
29 #include "commands/defrem.h"
30 #include "commands/purge.h"
31 #include "commands/rename.h"
32 #include "commands/view.h"
33 #include "commands/version.h"
34 #include "commands/vacuum.h"
35 #include "commands/recipe.h"
36 #include "commands/explain.h"
38 #include "nodes/parsenodes.h"
39 #include "../backend/parser/parse.h"
40 #include "utils/builtins.h"
41 #include "utils/acl.h"
42 #include "utils/palloc.h"
43 #include "rewrite/rewriteRemove.h"
44 #include "rewrite/rewriteDefine.h"
45 #include "tcop/tcopdebug.h"
46 #include "tcop/dest.h"
47 #include "tcop/variable.h"
48 #include "tcop/utility.h"
49 #include "fmgr.h" /* For load_file() */
50 #include "storage/fd.h"
53 #include "miscadmin.h"
54 #include "utils/acl.h"
55 #include "utils/syscache.h"
60 * CHECK_IF_ABORTED() is used to avoid doing unnecessary
61 * processing within an aborted transaction block.
64 #define CHECK_IF_ABORTED() \
65 if (IsAbortedTransactionBlockState()) { \
66 elog(NOTICE, "(transaction aborted): %s", \
67 "queries ignored until END"); \
68 commandTag = "*ABORT STATE*"; \
73 * general utility function invoker
77 ProcessUtility(Node *parsetree,
80 char *commandTag = NULL;
85 userName = GetPgUserName();
87 switch (nodeTag(parsetree)) {
88 /* ********************************
90 * ********************************
92 case T_TransactionStmt:
94 TransactionStmt *stmt = (TransactionStmt *)parsetree;
95 switch (stmt->command) {
99 BeginTransactionBlock();
104 EndTransactionBlock();
108 commandTag = "ABORT";
109 UserAbortTransactionBlock();
115 /* ********************************
116 * portal manipulation
117 * ********************************
119 case T_ClosePortalStmt:
121 ClosePortalStmt *stmt = (ClosePortalStmt *)parsetree;
123 commandTag = "CLOSE";
126 PerformPortalClose(stmt->portalname, dest);
132 FetchStmt *stmt = (FetchStmt *)parsetree;
133 char *portalName = stmt->portalname;
137 commandTag = "FETCH";
140 forward = (bool)(stmt->direction == FORWARD);
142 /* parser ensures that count is >= 0 and
145 count = stmt->howMany;
146 PerformPortalFetch(portalName, forward, count, commandTag, dest);
150 /* ********************************
151 * relation and attribute manipulation
152 * ********************************
155 commandTag = "CREATE";
158 DefineRelation((CreateStmt *)parsetree);
163 DestroyStmt *stmt = (DestroyStmt *)parsetree;
165 List *args = stmt->relNames;
171 foreach (arg, args) {
172 relname = strVal(lfirst(arg));
173 if (IsSystemRelationName(relname))
174 elog(WARN, "class \"%s\" is a system catalog",
176 rel = heap_openr (relname);
177 if ( RelationIsValid (rel) )
179 if ( stmt->sequence &&
180 rel->rd_rel->relkind != RELKIND_SEQUENCE )
181 elog (WARN, "Use DROP TABLE to drop table '%s'",
183 if ( !(stmt->sequence) &&
184 rel->rd_rel->relkind == RELKIND_SEQUENCE )
185 elog (WARN, "Use DROP SEQUENCE to drop sequence '%s'",
190 if (!pg_ownercheck(userName, relname, RELNAME))
191 elog(WARN, "you do not own class \"%s\"",
195 foreach (arg, args) {
196 relname = strVal(lfirst(arg));
197 RemoveRelation(relname);
204 PurgeStmt *stmt = (PurgeStmt *)parsetree;
206 commandTag = "PURGE";
209 RelationPurge(stmt->relname,
210 stmt->beforeDate, /* absolute time string */
211 stmt->afterDate); /* relative time string */
217 CopyStmt *stmt = (CopyStmt *)parsetree;
222 DoCopy(stmt->relname,
225 (bool)(stmt->direction == FROM),
226 (bool)(stmt->filename == NULL),
227 /* null filename means copy to/from stdout/stdin,
228 rather than to/from a file.
237 AddAttrStmt *stmt = (AddAttrStmt *)parsetree;
242 /* owner checking done in PerformAddAttribute (now recursive) */
243 PerformAddAttribute(stmt->relname,
255 RenameStmt *stmt = (RenameStmt *)parsetree;
257 commandTag = "RENAME";
260 relname = stmt->relname;
261 if (IsSystemRelationName(relname))
262 elog(WARN, "class \"%s\" is a system catalog",
265 if (!pg_ownercheck(userName, relname, RELNAME))
266 elog(WARN, "you do not own class \"%s\"",
271 * XXX using len == 3 to tell the difference
272 * between "rename rel to newrel" and
273 * "rename att in rel to newatt" will not
274 * work soon because "rename type/operator/rule"
275 * stuff is being added. - cim 10/24/90
277 * [another piece of amuzing but useless anecdote -- ay]
279 if (stmt->column == NULL) {
283 * Note: we also rename the "type" tuple
284 * corresponding to the relation.
287 renamerel(relname, /* old name */
288 stmt->newname); /* new name */
289 TypeRename(relname, /* old name */
290 stmt->newname); /* new name */
296 renameatt(relname, /* relname */
297 stmt->column, /* old att name */
298 stmt->newname, /* new att name */
300 stmt->inh); /* recursive? */
305 case T_ChangeACLStmt:
307 ChangeACLStmt *stmt = (ChangeACLStmt *)parsetree;
312 commandTag = "CHANGE";
316 modechg = stmt->modechg;
318 foreach (i, stmt->relNames) {
319 relname = strVal(lfirst(i));
320 if (!pg_ownercheck(userName, relname, RELNAME))
321 elog(WARN, "you do not own class \"%s\"",
325 foreach (i, stmt->relNames) {
326 relname = strVal(lfirst(i));
327 ChangeAcl(relname, aip, modechg);
333 /* ********************************
334 * object creation / destruction
335 * ********************************
339 DefineStmt *stmt = (DefineStmt *)parsetree;
341 commandTag = "CREATE";
344 switch(stmt->defType) {
346 DefineOperator(stmt->defname, /* operator name */
347 stmt->definition); /* rest */
351 DefineType (stmt->defname, stmt->definition);
355 DefineAggregate(stmt->defname, /*aggregate name */
356 stmt->definition); /* rest */
362 case T_ViewStmt: /* CREATE VIEW */
364 ViewStmt *stmt = (ViewStmt *)parsetree;
366 commandTag = "CREATE";
368 DefineView (stmt->viewname, stmt->query); /* retrieve parsetree */
372 case T_ProcedureStmt: /* CREATE FUNCTION */
373 commandTag = "CREATE";
375 CreateFunction((ProcedureStmt *)parsetree, dest); /* everything */
378 case T_IndexStmt: /* CREATE INDEX */
380 IndexStmt *stmt = (IndexStmt *)parsetree;
382 commandTag = "CREATE";
384 /* XXX no support for ARCHIVE indices, yet */
385 DefineIndex(stmt->relname, /* relation name */
386 stmt->idxname, /* index name */
387 stmt->accessMethod, /* am name */
388 stmt->indexParams, /* parameters */
391 (Expr*)stmt->whereClause,
396 case T_RuleStmt: /* CREATE RULE */
398 RuleStmt *stmt = (RuleStmt *)parsetree;
402 relname = stmt->object->relname;
403 aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
404 if(aclcheck_result != ACLCHECK_OK)
405 elog(WARN, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
407 commandTag = "CREATE";
409 DefineQueryRewrite(stmt);
413 case T_CreateSeqStmt:
414 commandTag = "CREATE";
417 DefineSequence((CreateSeqStmt *)parsetree);
422 ExtendStmt *stmt = (ExtendStmt *)parsetree;
424 commandTag = "EXTEND";
427 ExtendIndex(stmt->idxname, /* index name */
428 (Expr*)stmt->whereClause, /* where */
435 RemoveStmt *stmt = (RemoveStmt *)parsetree;
440 switch(stmt->removeType) {
442 relname = stmt->name;
443 if (IsSystemRelationName(relname))
444 elog(WARN, "class \"%s\" is a system catalog index",
447 if (!pg_ownercheck(userName, relname, RELNAME))
448 elog(WARN, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
450 RemoveIndex(relname);
454 char *rulename = stmt->name;
458 relationName = RewriteGetRuleEventRel(rulename);
459 aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
460 if(aclcheck_result != ACLCHECK_OK) {
461 elog(WARN, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
464 RemoveRewriteRule(rulename);
469 /* XXX moved to remove.c */
471 RemoveType(stmt->name);
475 char *viewName = stmt->name;
480 ruleName = MakeRetrieveViewRuleName(viewName);
481 relationName = RewriteGetRuleEventRel(ruleName);
482 if (!pg_ownercheck(userName, relationName, RELNAME))
483 elog(WARN, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
486 RemoveView(viewName);
494 case T_RemoveAggrStmt:
496 RemoveAggrStmt *stmt = (RemoveAggrStmt *)parsetree;
499 RemoveAggregate(stmt->aggname, stmt->aggtype);
503 case T_RemoveFuncStmt:
505 RemoveFuncStmt *stmt = (RemoveFuncStmt *)parsetree;
508 RemoveFunction(stmt->funcname,
514 case T_RemoveOperStmt:
516 RemoveOperStmt *stmt = (RemoveOperStmt *)parsetree;
517 char* type1 = (char*) NULL;
518 char *type2 = (char*) NULL;
523 if (lfirst(stmt->args)!=NULL)
524 type1 = strVal(lfirst(stmt->args));
525 if (lsecond(stmt->args)!=NULL)
526 type2 = strVal(lsecond(stmt->args));
527 RemoveOperator(stmt->opname, type1, type2);
533 elog(WARN, "CREATE VERSION is not currently implemented");
539 CreatedbStmt *stmt = (CreatedbStmt *)parsetree;
541 commandTag = "CREATEDB";
543 createdb(stmt->dbname);
547 case T_DestroydbStmt:
549 DestroydbStmt *stmt = (DestroydbStmt *)parsetree;
551 commandTag = "DESTROYDB";
553 destroydb(stmt->dbname);
557 /* Query-level asynchronous notification */
560 NotifyStmt *stmt = (NotifyStmt *)parsetree;
562 commandTag = "NOTIFY";
565 Async_Notify(stmt->relname);
571 ListenStmt *stmt = (ListenStmt *)parsetree;
573 commandTag = "LISTEN";
576 Async_Listen(stmt->relname,MasterPid);
580 /* ********************************
582 * ********************************
586 LoadStmt *stmt = (LoadStmt *)parsetree;
593 filename = stmt->filename;
595 if ((fp = AllocateFile(filename, "r")) == NULL)
596 elog(WARN, "LOAD: could not open file %s", filename);
604 ClusterStmt *stmt = (ClusterStmt *)parsetree;
606 commandTag = "CLUSTER";
609 cluster(stmt->relname, stmt->indexname);
614 commandTag = "VACUUM";
616 vacuum( ((VacuumStmt *) parsetree)->vacrel,
617 ((VacuumStmt *) parsetree)->verbose,
618 ((VacuumStmt *) parsetree)->analyze,
619 ((VacuumStmt *) parsetree)->va_spec);
624 ExplainStmt *stmt = (ExplainStmt *)parsetree;
626 commandTag = "EXPLAIN";
629 ExplainQuery(stmt->query, stmt->verbose, dest);
633 /* ********************************
634 Tioga-related statements
635 *********************************/
638 RecipeStmt* stmt = (RecipeStmt*)parsetree;
639 commandTag="EXECUTE RECIPE";
645 /* ********************************
646 * set variable statements
647 *********************************/
648 case T_VariableSetStmt:
650 VariableSetStmt *n = (VariableSetStmt *) parsetree;
651 SetPGVariable(n->name, n->value);
652 commandTag = "SET VARIABLE";
656 case T_VariableShowStmt:
658 VariableShowStmt *n = (VariableShowStmt *) parsetree;
659 GetPGVariable(n->name);
660 commandTag = "SHOW VARIABLE";
664 case T_VariableResetStmt:
666 VariableResetStmt *n = (VariableResetStmt *) parsetree;
667 ResetPGVariable(n->name);
668 commandTag = "RESET VARIABLE";
672 /* ********************************
674 * ********************************
677 elog(WARN, "ProcessUtility: command #%d unsupported",
683 * tell fe/be or whatever that we're done.
686 EndCommand(commandTag, dest);