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.12 1997/03/12 20:48:27 scrappy 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;
387 relname = stmt->object->relname;
388 aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
389 if(aclcheck_result != ACLCHECK_OK)
390 elog(WARN, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
392 commandTag = "CREATE";
394 DefineQueryRewrite(stmt);
400 ExtendStmt *stmt = (ExtendStmt *)parsetree;
402 commandTag = "EXTEND";
405 ExtendIndex(stmt->idxname, /* index name */
406 (Expr*)stmt->whereClause, /* where */
413 RemoveStmt *stmt = (RemoveStmt *)parsetree;
418 switch(stmt->removeType) {
420 RemoveAggregate(stmt->name);
423 relname = stmt->name;
424 if (IsSystemRelationName(relname))
425 elog(WARN, "class \"%s\" is a system catalog index",
428 if (!pg_ownercheck(userName, relname, RELNAME))
429 elog(WARN, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
431 RemoveIndex(relname);
435 char *rulename = stmt->name;
439 relationName = RewriteGetRuleEventRel(rulename);
440 aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
441 if(aclcheck_result != ACLCHECK_OK) {
442 elog(WARN, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
445 RemoveRewriteRule(rulename);
450 /* XXX moved to remove.c */
452 RemoveType(stmt->name);
456 char *viewName = stmt->name;
458 extern char *RewriteGetRuleEventRel();
462 ruleName = MakeRetrieveViewRuleName(viewName);
463 relationName = RewriteGetRuleEventRel(ruleName);
464 if (!pg_ownercheck(userName, relationName, RELNAME))
465 elog(WARN, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
468 RemoveView(viewName);
475 case T_RemoveFuncStmt:
477 RemoveFuncStmt *stmt = (RemoveFuncStmt *)parsetree;
480 RemoveFunction(stmt->funcname,
486 case T_RemoveOperStmt:
488 RemoveOperStmt *stmt = (RemoveOperStmt *)parsetree;
489 char* type1 = (char*) NULL;
490 char *type2 = (char*) NULL;
495 if (lfirst(stmt->args)!=NULL)
496 type1 = strVal(lfirst(stmt->args));
497 if (lsecond(stmt->args)!=NULL)
498 type2 = strVal(lsecond(stmt->args));
499 RemoveOperator(stmt->opname, type1, type2);
505 elog(WARN, "CREATE VERSION is not currently implemented");
511 CreatedbStmt *stmt = (CreatedbStmt *)parsetree;
513 commandTag = "CREATEDB";
515 createdb(stmt->dbname);
519 case T_DestroydbStmt:
521 DestroydbStmt *stmt = (DestroydbStmt *)parsetree;
523 commandTag = "DESTROYDB";
525 destroydb(stmt->dbname);
529 /* Query-level asynchronous notification */
532 NotifyStmt *stmt = (NotifyStmt *)parsetree;
534 commandTag = "NOTIFY";
537 Async_Notify(stmt->relname);
543 ListenStmt *stmt = (ListenStmt *)parsetree;
545 commandTag = "LISTEN";
548 Async_Listen(stmt->relname,MasterPid);
552 /* ********************************
554 * ********************************
558 LoadStmt *stmt = (LoadStmt *)parsetree;
565 filename = stmt->filename;
567 if ((fp = fopen(filename, "r")) == NULL)
568 elog(WARN, "LOAD: could not open file %s", filename);
576 ClusterStmt *stmt = (ClusterStmt *)parsetree;
578 commandTag = "CLUSTER";
581 cluster(stmt->relname, stmt->indexname);
586 commandTag = "VACUUM";
588 vacuum( ((VacuumStmt *) parsetree)->vacrel,
589 ((VacuumStmt *) parsetree)->verbose);
594 ExplainStmt *stmt = (ExplainStmt *)parsetree;
596 commandTag = "EXPLAIN";
599 ExplainQuery(stmt->query, stmt->verbose, dest);
603 /* ********************************
604 Tioga-related statements
605 *********************************/
608 RecipeStmt* stmt = (RecipeStmt*)parsetree;
609 commandTag="EXECUTE RECIPE";
616 /* ********************************
618 * ********************************
621 elog(WARN, "ProcessUtility: command #%d unsupported",
627 * tell fe/be or whatever that we're done.
630 EndCommand(commandTag, dest);