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.8 1996/11/11 04:54:54 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 */
375 (Expr*)stmt->whereClause,
380 case T_RuleStmt: /* CREATE RULE */
382 RuleStmt *stmt = (RuleStmt *)parsetree;
384 relname = stmt->object->relname;
385 if (!pg_aclcheck(relname, userName, ACL_RU))
386 elog(WARN, "%s %s", relname, ACL_NO_PRIV_WARNING);
388 commandTag = "CREATE";
390 DefineQueryRewrite(stmt);
396 ExtendStmt *stmt = (ExtendStmt *)parsetree;
398 commandTag = "EXTEND";
401 ExtendIndex(stmt->idxname, /* index name */
402 (Expr*)stmt->whereClause, /* where */
409 RemoveStmt *stmt = (RemoveStmt *)parsetree;
414 switch(stmt->removeType) {
416 RemoveAggregate(stmt->name);
419 relname = stmt->name;
420 if (IsSystemRelationName(relname))
421 elog(WARN, "class \"%s\" is a system catalog index",
424 if (!pg_ownercheck(userName, relname, RELNAME))
425 elog(WARN, "you do not own class \"%s\"",
428 RemoveIndex(relname);
432 char *rulename = stmt->name;
435 relationName = RewriteGetRuleEventRel(rulename);
436 if (!pg_aclcheck(relationName, userName, ACL_RU))
437 elog(WARN, "%s %s", relationName, ACL_NO_PRIV_WARNING);
439 RemoveRewriteRule(rulename);
444 /* XXX moved to remove.c */
446 RemoveType(stmt->name);
450 char *viewName = stmt->name;
452 extern char *RewriteGetRuleEventRel();
456 ruleName = MakeRetrieveViewRuleName(viewName);
457 relationName = RewriteGetRuleEventRel(ruleName);
458 if (!pg_ownercheck(userName, relationName, RELNAME))
459 elog(WARN, "%s %s", relationName, ACL_NO_PRIV_WARNING);
462 RemoveView(viewName);
469 case T_RemoveFuncStmt:
471 RemoveFuncStmt *stmt = (RemoveFuncStmt *)parsetree;
474 RemoveFunction(stmt->funcname,
480 case T_RemoveOperStmt:
482 RemoveOperStmt *stmt = (RemoveOperStmt *)parsetree;
483 char* type1 = (char*) NULL;
484 char *type2 = (char*) NULL;
489 if (lfirst(stmt->args)!=NULL)
490 type1 = strVal(lfirst(stmt->args));
491 if (lsecond(stmt->args)!=NULL)
492 type2 = strVal(lsecond(stmt->args));
493 RemoveOperator(stmt->opname, type1, type2);
499 elog(WARN, "CREATE VERSION is not currently implemented");
505 CreatedbStmt *stmt = (CreatedbStmt *)parsetree;
507 commandTag = "CREATEDB";
509 createdb(stmt->dbname);
513 case T_DestroydbStmt:
515 DestroydbStmt *stmt = (DestroydbStmt *)parsetree;
517 commandTag = "DESTROYDB";
519 destroydb(stmt->dbname);
523 /* Query-level asynchronous notification */
526 NotifyStmt *stmt = (NotifyStmt *)parsetree;
528 commandTag = "NOTIFY";
531 Async_Notify(stmt->relname);
537 ListenStmt *stmt = (ListenStmt *)parsetree;
539 commandTag = "LISTEN";
542 Async_Listen(stmt->relname,MasterPid);
546 /* ********************************
548 * ********************************
552 LoadStmt *stmt = (LoadStmt *)parsetree;
559 filename = stmt->filename;
561 if ((fp = fopen(filename, "r")) == NULL)
562 elog(WARN, "LOAD: could not open file %s", filename);
570 ClusterStmt *stmt = (ClusterStmt *)parsetree;
572 commandTag = "CLUSTER";
575 cluster(stmt->relname, stmt->indexname);
580 commandTag = "VACUUM";
582 vacuum(((VacuumStmt *) parsetree)->vacrel);
587 ExplainStmt *stmt = (ExplainStmt *)parsetree;
589 commandTag = "EXPLAIN";
592 ExplainQuery(stmt->query, stmt->options, dest);
596 /* ********************************
597 Tioga-related statements
598 *********************************/
601 RecipeStmt* stmt = (RecipeStmt*)parsetree;
602 commandTag="EXECUTE RECIPE";
609 /* ********************************
611 * ********************************
614 elog(WARN, "ProcessUtility: command #%d unsupported",
620 * tell fe/be or whatever that we're done.
623 EndCommand(commandTag, dest);