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.11 1997/01/16 14:56:21 momjian Exp $
14 *-------------------------------------------------------------------------
17 #include "parser/dbcommands.h"
18 #include "access/xact.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/defrem.h"
28 #include "commands/purge.h"
29 #include "commands/rename.h"
30 #include "commands/view.h"
31 #include "commands/version.h"
32 #include "commands/vacuum.h"
33 #include "commands/recipe.h"
34 #include "commands/explain.h"
36 #include "nodes/parsenodes.h"
37 #include "../backend/parser/parse.h"
38 #include "utils/builtins.h"
39 #include "utils/acl.h"
40 #include "utils/palloc.h"
41 #include "rewrite/rewriteRemove.h"
42 #include "rewrite/rewriteDefine.h"
43 #include "tcop/tcopdebug.h"
44 #include "tcop/dest.h"
45 #include "tcop/utility.h"
46 #include "fmgr.h" /* For load_file() */
49 #include "miscadmin.h"
50 #include "utils/acl.h"
51 #include "utils/syscache.h"
56 * CHECK_IF_ABORTED() is used to avoid doing unnecessary
57 * processing within an aborted transaction block.
60 #define CHECK_IF_ABORTED() \
61 if (IsAbortedTransactionBlockState()) { \
62 elog(NOTICE, "(transaction aborted): %s", \
63 "queries ignored until END"); \
64 commandTag = "*ABORT STATE*"; \
69 * general utility function invoker
73 ProcessUtility(Node *parsetree,
76 char *commandTag = NULL;
81 userName = GetPgUserName();
83 switch (nodeTag(parsetree)) {
84 /* ********************************
86 * ********************************
88 case T_TransactionStmt:
90 TransactionStmt *stmt = (TransactionStmt *)parsetree;
91 switch (stmt->command) {
95 BeginTransactionBlock();
100 EndTransactionBlock();
104 commandTag = "ABORT";
105 UserAbortTransactionBlock();
111 /* ********************************
112 * portal manipulation
113 * ********************************
115 case T_ClosePortalStmt:
117 ClosePortalStmt *stmt = (ClosePortalStmt *)parsetree;
119 commandTag = "CLOSE";
122 PerformPortalClose(stmt->portalname, dest);
128 FetchStmt *stmt = (FetchStmt *)parsetree;
129 char *portalName = stmt->portalname;
133 commandTag = "FETCH";
136 forward = (bool)(stmt->direction == FORWARD);
138 /* parser ensures that count is >= 0 and
141 count = stmt->howMany;
142 PerformPortalFetch(portalName, forward, count, commandTag, dest);
146 /* ********************************
147 * relation and attribute manipulation
148 * ********************************
151 commandTag = "CREATE";
154 DefineRelation((CreateStmt *)parsetree);
159 DestroyStmt *stmt = (DestroyStmt *)parsetree;
161 List *args = stmt->relNames;
166 foreach (arg, args) {
167 relname = strVal(lfirst(arg));
168 if (IsSystemRelationName(relname))
169 elog(WARN, "class \"%-.*s\" is a system catalog",
170 NAMEDATALEN, relname);
172 if (!pg_ownercheck(userName, relname, RELNAME))
173 elog(WARN, "you do not own class \"%-.*s\"",
174 NAMEDATALEN, relname);
177 foreach (arg, args) {
178 relname = strVal(lfirst(arg));
179 RemoveRelation(relname);
186 PurgeStmt *stmt = (PurgeStmt *)parsetree;
188 commandTag = "PURGE";
191 RelationPurge(stmt->relname,
192 stmt->beforeDate, /* absolute time string */
193 stmt->afterDate); /* relative time string */
199 CopyStmt *stmt = (CopyStmt *)parsetree;
204 /* Free up file descriptors - going to do a read... */
207 DoCopy(stmt->relname,
210 (bool)(stmt->direction == FROM),
211 (bool)(stmt->filename == NULL),
212 /* null filename means copy to/from stdout/stdin,
213 rather than to/from a file.
222 AddAttrStmt *stmt = (AddAttrStmt *)parsetree;
227 /* owner checking done in PerformAddAttribute (now recursive) */
228 PerformAddAttribute(stmt->relname,
240 RenameStmt *stmt = (RenameStmt *)parsetree;
242 commandTag = "RENAME";
245 relname = stmt->relname;
246 if (IsSystemRelationName(relname))
247 elog(WARN, "class \"%s\" is a system catalog",
250 if (!pg_ownercheck(userName, relname, RELNAME))
251 elog(WARN, "you do not own class \"%s\"",
256 * XXX using len == 3 to tell the difference
257 * between "rename rel to newrel" and
258 * "rename att in rel to newatt" will not
259 * work soon because "rename type/operator/rule"
260 * stuff is being added. - cim 10/24/90
262 * [another piece of amuzing but useless anecdote -- ay]
264 if (stmt->column == NULL) {
268 * Note: we also rename the "type" tuple
269 * corresponding to the relation.
272 renamerel(relname, /* old name */
273 stmt->newname); /* new name */
274 TypeRename(relname, /* old name */
275 stmt->newname); /* new name */
281 renameatt(relname, /* relname */
282 stmt->column, /* old att name */
283 stmt->newname, /* new att name */
285 stmt->inh); /* recursive? */
290 case T_ChangeACLStmt:
292 ChangeACLStmt *stmt = (ChangeACLStmt *)parsetree;
297 commandTag = "CHANGE";
301 modechg = stmt->modechg;
303 foreach (i, stmt->relNames) {
304 relname = strVal(lfirst(i));
305 if (!pg_ownercheck(userName, relname, RELNAME))
306 elog(WARN, "you do not own class \"%-.*s\"",
307 NAMEDATALEN, relname);
310 foreach (i, stmt->relNames) {
311 relname = strVal(lfirst(i));
312 ChangeAcl(relname, aip, modechg);
318 /* ********************************
319 * object creation / destruction
320 * ********************************
324 DefineStmt *stmt = (DefineStmt *)parsetree;
326 commandTag = "CREATE";
329 switch(stmt->defType) {
331 DefineOperator(stmt->defname, /* operator name */
332 stmt->definition); /* rest */
336 DefineType (stmt->defname, stmt->definition);
340 DefineAggregate(stmt->defname, /*aggregate name */
341 stmt->definition); /* rest */
347 case T_ViewStmt: /* CREATE VIEW */
349 ViewStmt *stmt = (ViewStmt *)parsetree;
351 commandTag = "CREATE";
353 DefineView (stmt->viewname, stmt->query); /* retrieve parsetree */
357 case T_ProcedureStmt: /* CREATE FUNCTION */
358 commandTag = "CREATE";
360 CreateFunction((ProcedureStmt *)parsetree, dest); /* everything */
363 case T_IndexStmt: /* CREATE INDEX */
365 IndexStmt *stmt = (IndexStmt *)parsetree;
367 commandTag = "CREATE";
369 /* XXX no support for ARCHIVE indices, yet */
370 DefineIndex(stmt->relname, /* relation name */
371 stmt->idxname, /* index name */
372 stmt->accessMethod, /* am name */
373 stmt->indexParams, /* parameters */
376 (Expr*)stmt->whereClause,
381 case T_RuleStmt: /* CREATE RULE */
383 RuleStmt *stmt = (RuleStmt *)parsetree;
385 relname = stmt->object->relname;
386 if (!pg_aclcheck(relname, userName, ACL_RU))
387 elog(WARN, "%s %s", relname, ACL_NO_PRIV_WARNING);
389 commandTag = "CREATE";
391 DefineQueryRewrite(stmt);
397 ExtendStmt *stmt = (ExtendStmt *)parsetree;
399 commandTag = "EXTEND";
402 ExtendIndex(stmt->idxname, /* index name */
403 (Expr*)stmt->whereClause, /* where */
410 RemoveStmt *stmt = (RemoveStmt *)parsetree;
415 switch(stmt->removeType) {
417 RemoveAggregate(stmt->name);
420 relname = stmt->name;
421 if (IsSystemRelationName(relname))
422 elog(WARN, "class \"%s\" is a system catalog index",
425 if (!pg_ownercheck(userName, relname, RELNAME))
426 elog(WARN, "you do not own class \"%s\"",
429 RemoveIndex(relname);
433 char *rulename = stmt->name;
436 relationName = RewriteGetRuleEventRel(rulename);
437 if (!pg_aclcheck(relationName, userName, ACL_RU))
438 elog(WARN, "%s %s", relationName, ACL_NO_PRIV_WARNING);
440 RemoveRewriteRule(rulename);
445 /* XXX moved to remove.c */
447 RemoveType(stmt->name);
451 char *viewName = stmt->name;
453 extern char *RewriteGetRuleEventRel();
457 ruleName = MakeRetrieveViewRuleName(viewName);
458 relationName = RewriteGetRuleEventRel(ruleName);
459 if (!pg_ownercheck(userName, relationName, RELNAME))
460 elog(WARN, "%s %s", relationName, ACL_NO_PRIV_WARNING);
463 RemoveView(viewName);
470 case T_RemoveFuncStmt:
472 RemoveFuncStmt *stmt = (RemoveFuncStmt *)parsetree;
475 RemoveFunction(stmt->funcname,
481 case T_RemoveOperStmt:
483 RemoveOperStmt *stmt = (RemoveOperStmt *)parsetree;
484 char* type1 = (char*) NULL;
485 char *type2 = (char*) NULL;
490 if (lfirst(stmt->args)!=NULL)
491 type1 = strVal(lfirst(stmt->args));
492 if (lsecond(stmt->args)!=NULL)
493 type2 = strVal(lsecond(stmt->args));
494 RemoveOperator(stmt->opname, type1, type2);
500 elog(WARN, "CREATE VERSION is not currently implemented");
506 CreatedbStmt *stmt = (CreatedbStmt *)parsetree;
508 commandTag = "CREATEDB";
510 createdb(stmt->dbname);
514 case T_DestroydbStmt:
516 DestroydbStmt *stmt = (DestroydbStmt *)parsetree;
518 commandTag = "DESTROYDB";
520 destroydb(stmt->dbname);
524 /* Query-level asynchronous notification */
527 NotifyStmt *stmt = (NotifyStmt *)parsetree;
529 commandTag = "NOTIFY";
532 Async_Notify(stmt->relname);
538 ListenStmt *stmt = (ListenStmt *)parsetree;
540 commandTag = "LISTEN";
543 Async_Listen(stmt->relname,MasterPid);
547 /* ********************************
549 * ********************************
553 LoadStmt *stmt = (LoadStmt *)parsetree;
560 filename = stmt->filename;
562 if ((fp = fopen(filename, "r")) == NULL)
563 elog(WARN, "LOAD: could not open file %s", filename);
571 ClusterStmt *stmt = (ClusterStmt *)parsetree;
573 commandTag = "CLUSTER";
576 cluster(stmt->relname, stmt->indexname);
581 commandTag = "VACUUM";
583 vacuum( ((VacuumStmt *) parsetree)->vacrel,
584 ((VacuumStmt *) parsetree)->verbose);
589 ExplainStmt *stmt = (ExplainStmt *)parsetree;
591 commandTag = "EXPLAIN";
594 ExplainQuery(stmt->query, stmt->verbose, dest);
598 /* ********************************
599 Tioga-related statements
600 *********************************/
603 RecipeStmt* stmt = (RecipeStmt*)parsetree;
604 commandTag="EXECUTE RECIPE";
611 /* ********************************
613 * ********************************
616 elog(WARN, "ProcessUtility: command #%d unsupported",
622 * tell fe/be or whatever that we're done.
625 EndCommand(commandTag, dest);