]> granicus.if.org Git - postgresql/blob - src/backend/tcop/utility.c
Change EXPLAIN options to just use VERBOSE.
[postgresql] / src / backend / tcop / utility.c
1 /*-------------------------------------------------------------------------
2  *
3  * utility.c--
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
6  *    systems.
7  *
8  * Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *    $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.11 1997/01/16 14:56:21 momjian Exp $
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17 #include "parser/dbcommands.h"
18 #include "access/xact.h"
19 #include "catalog/catalog.h"
20 #include "catalog/pg_type.h"
21
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"
35
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() */
47
48 #ifndef NO_SECURITY
49 #include "miscadmin.h"
50 #include "utils/acl.h"
51 #include "utils/syscache.h"
52 #endif
53
54
55 /* ----------------
56  *      CHECK_IF_ABORTED() is used to avoid doing unnecessary
57  *      processing within an aborted transaction block.
58  * ----------------
59  */
60 #define CHECK_IF_ABORTED() \
61     if (IsAbortedTransactionBlockState()) { \
62         elog(NOTICE, "(transaction aborted): %s", \
63              "queries ignored until END"); \
64         commandTag = "*ABORT STATE*"; \
65         break; \
66     } \
67     
68 /* ----------------
69  *      general utility function invoker
70  * ----------------
71  */
72 void
73 ProcessUtility(Node *parsetree,
74                CommandDest dest)
75 {
76     char *commandTag = NULL;
77     char *relname;
78     char *relationName;
79     char *userName;
80     
81     userName = GetPgUserName();
82     
83     switch (nodeTag(parsetree)) {
84         /* ********************************
85          *      transactions
86          * ********************************
87          */
88     case T_TransactionStmt:
89         {
90             TransactionStmt *stmt = (TransactionStmt *)parsetree;
91             switch (stmt->command) {
92             case BEGIN_TRANS:
93                 commandTag = "BEGIN";
94                 CHECK_IF_ABORTED();
95                 BeginTransactionBlock();
96                 break;
97                 
98             case END_TRANS:
99                 commandTag = "END";
100                 EndTransactionBlock();
101                 break;
102                 
103             case ABORT_TRANS:
104                 commandTag = "ABORT";
105                 UserAbortTransactionBlock();
106                 break;
107             }
108         }
109         break;
110       
111         /* ********************************
112          *      portal manipulation
113          * ********************************
114          */
115     case T_ClosePortalStmt:
116         {
117             ClosePortalStmt *stmt = (ClosePortalStmt *)parsetree;
118
119             commandTag = "CLOSE";
120             CHECK_IF_ABORTED();
121         
122             PerformPortalClose(stmt->portalname, dest);
123         }
124         break;
125       
126     case T_FetchStmt:
127         {
128             FetchStmt *stmt = (FetchStmt *)parsetree;
129             char *portalName = stmt->portalname;
130             bool forward;
131             int count;
132
133             commandTag = "FETCH";
134             CHECK_IF_ABORTED();
135
136             forward = (bool)(stmt->direction == FORWARD);
137
138             /* parser ensures that count is >= 0 and 
139                'fetch ALL' -> 0 */
140                
141             count = stmt->howMany;
142             PerformPortalFetch(portalName, forward, count, commandTag, dest);
143         }
144         break;
145       
146         /* ********************************
147          *      relation and attribute manipulation
148          * ********************************
149          */
150     case T_CreateStmt:
151         commandTag = "CREATE";
152         CHECK_IF_ABORTED();
153       
154         DefineRelation((CreateStmt *)parsetree);
155         break;
156       
157     case T_DestroyStmt:
158         {
159             DestroyStmt *stmt = (DestroyStmt *)parsetree;
160             List *arg;
161             List *args = stmt->relNames;
162
163             commandTag = "DROP";
164             CHECK_IF_ABORTED();
165
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);
171 #ifndef NO_SECURITY
172                 if (!pg_ownercheck(userName, relname, RELNAME))
173                     elog(WARN, "you do not own class \"%-.*s\"",
174                          NAMEDATALEN, relname);
175 #endif
176             }
177             foreach (arg, args) {
178                 relname = strVal(lfirst(arg));
179                 RemoveRelation(relname);
180             }
181         }
182         break;
183       
184     case T_PurgeStmt:
185         {
186             PurgeStmt *stmt = (PurgeStmt *)parsetree;
187
188             commandTag = "PURGE";
189             CHECK_IF_ABORTED();
190             
191             RelationPurge(stmt->relname,
192                           stmt->beforeDate, /* absolute time string */
193                           stmt->afterDate); /* relative time string */
194         }
195         break;
196       
197     case T_CopyStmt:
198         {
199             CopyStmt *stmt = (CopyStmt *)parsetree;
200
201             commandTag = "COPY";
202             CHECK_IF_ABORTED();
203             
204             /* Free up file descriptors - going to do a read... */
205             closeOneVfd();
206
207             DoCopy(stmt->relname, 
208                    stmt->binary, 
209                    stmt->oids, 
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.
214                          */
215                    stmt->filename, 
216                    stmt->delimiter);
217         }
218         break;
219       
220     case T_AddAttrStmt:
221         {
222             AddAttrStmt *stmt = (AddAttrStmt *)parsetree;
223
224             commandTag = "ADD";
225             CHECK_IF_ABORTED();
226         
227             /* owner checking done in PerformAddAttribute (now recursive) */
228             PerformAddAttribute(stmt->relname,
229                                 userName,
230                                 stmt->inh,
231                                 stmt->colDef);
232         }
233         break;
234       
235         /*
236          * schema
237          */
238     case T_RenameStmt:
239         {
240             RenameStmt *stmt = (RenameStmt *)parsetree;
241
242             commandTag = "RENAME";
243             CHECK_IF_ABORTED();
244         
245             relname = stmt->relname;
246             if (IsSystemRelationName(relname))
247                 elog(WARN, "class \"%s\" is a system catalog",
248                      relname);
249 #ifndef NO_SECURITY
250             if (!pg_ownercheck(userName, relname, RELNAME))
251                 elog(WARN, "you do not own class \"%s\"",
252                      relname);
253 #endif
254             
255             /* ----------------
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
261              * ----------------
262              * [another piece of amuzing but useless anecdote -- ay]
263              */
264             if (stmt->column == NULL) {
265                 /* ----------------
266                  *      rename relation
267                  *
268                  *      Note: we also rename the "type" tuple
269                  *      corresponding to the relation.
270                  * ----------------
271                  */
272                 renamerel(relname, /* old name */
273                           stmt->newname); /* new name */
274                 TypeRename(relname, /* old name */
275                            stmt->newname); /* new name */
276             } else {
277                 /* ----------------
278                  *      rename attribute
279                  * ----------------
280                  */
281                 renameatt(relname, /* relname */
282                           stmt->column, /* old att name */
283                           stmt->newname, /* new att name */
284                           userName,
285                           stmt->inh); /* recursive? */
286             }
287         }
288         break;
289       
290     case T_ChangeACLStmt:
291         {
292             ChangeACLStmt *stmt = (ChangeACLStmt *)parsetree;
293             List *i;
294             AclItem *aip;
295             unsigned modechg;
296
297             commandTag = "CHANGE";
298             CHECK_IF_ABORTED();
299             
300             aip = stmt->aclitem;
301             modechg = stmt->modechg;
302 #ifndef NO_SECURITY
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);
308             }
309 #endif
310             foreach (i, stmt->relNames) {
311                 relname = strVal(lfirst(i));
312                 ChangeAcl(relname, aip, modechg);
313             }
314
315         }
316         break;
317       
318         /* ********************************
319          *      object creation / destruction
320          * ********************************
321          */
322     case T_DefineStmt:
323         {
324             DefineStmt *stmt = (DefineStmt *)parsetree;
325
326             commandTag = "CREATE";
327             CHECK_IF_ABORTED();
328
329             switch(stmt->defType) {
330             case OPERATOR:
331                 DefineOperator(stmt->defname, /* operator name */
332                                stmt->definition); /* rest */
333                 break;
334             case P_TYPE:
335                 {
336                     DefineType (stmt->defname, stmt->definition);
337                 }
338                 break;
339             case AGGREGATE:
340                 DefineAggregate(stmt->defname, /*aggregate name */
341                                 stmt->definition); /* rest */
342                 break;
343             }
344         }
345         break;
346       
347     case T_ViewStmt:            /* CREATE VIEW */
348         {
349             ViewStmt *stmt = (ViewStmt *)parsetree;
350
351             commandTag = "CREATE";
352             CHECK_IF_ABORTED();
353             DefineView (stmt->viewname, stmt->query); /* retrieve parsetree */
354         }
355         break;
356       
357     case T_ProcedureStmt:       /* CREATE FUNCTION */
358         commandTag = "CREATE";
359         CHECK_IF_ABORTED();
360         CreateFunction((ProcedureStmt *)parsetree, dest); /* everything */
361         break;
362       
363     case T_IndexStmt:           /* CREATE INDEX */
364         {
365             IndexStmt *stmt = (IndexStmt *)parsetree;
366
367             commandTag = "CREATE";
368             CHECK_IF_ABORTED();
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 */
374                         stmt->withClause,
375                         stmt->unique,
376                         (Expr*)stmt->whereClause,
377                         stmt->rangetable);
378         }
379         break;
380       
381     case T_RuleStmt:            /* CREATE RULE */
382         {
383             RuleStmt *stmt = (RuleStmt *)parsetree;
384 #ifndef NO_SECURITY
385             relname = stmt->object->relname;
386             if (!pg_aclcheck(relname, userName, ACL_RU))
387                 elog(WARN, "%s %s", relname, ACL_NO_PRIV_WARNING);      
388 #endif
389             commandTag = "CREATE";
390             CHECK_IF_ABORTED();
391             DefineQueryRewrite(stmt);
392         }
393         break;
394       
395     case T_ExtendStmt:
396         {
397             ExtendStmt *stmt = (ExtendStmt *)parsetree;
398
399             commandTag = "EXTEND";
400             CHECK_IF_ABORTED();
401         
402             ExtendIndex(stmt->idxname, /* index name */
403                         (Expr*)stmt->whereClause, /* where */
404                         stmt->rangetable);
405         }
406         break;
407       
408     case T_RemoveStmt:
409         {
410             RemoveStmt *stmt = (RemoveStmt *)parsetree;
411
412             commandTag = "DROP";
413             CHECK_IF_ABORTED();
414         
415             switch(stmt->removeType) {
416             case AGGREGATE:
417                 RemoveAggregate(stmt->name);
418                 break;
419             case INDEX:
420                 relname = stmt->name;
421                 if (IsSystemRelationName(relname))
422                     elog(WARN, "class \"%s\" is a system catalog index",
423                          relname);
424 #ifndef NO_SECURITY
425                 if (!pg_ownercheck(userName, relname, RELNAME))
426                     elog(WARN, "you do not own class \"%s\"",
427                          relname);
428 #endif
429                 RemoveIndex(relname);
430                 break;
431             case RULE:
432                 {
433                     char *rulename = stmt->name;
434 #ifndef NO_SECURITY
435                 
436                     relationName = RewriteGetRuleEventRel(rulename);
437                     if (!pg_aclcheck(relationName, userName, ACL_RU))
438                         elog(WARN, "%s %s", relationName, ACL_NO_PRIV_WARNING);
439 #endif
440                     RemoveRewriteRule(rulename);
441                 }
442                 break;
443             case P_TYPE:
444 #ifndef NO_SECURITY
445                 /* XXX moved to remove.c */
446 #endif
447                 RemoveType(stmt->name);
448                 break;
449             case VIEW:
450                 {
451                     char *viewName = stmt->name;
452                     char *ruleName;
453                     extern char *RewriteGetRuleEventRel();
454
455 #ifndef NO_SECURITY
456                 
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);
461                     pfree(ruleName);
462 #endif
463                     RemoveView(viewName);
464                 }
465                 break;
466             }
467             break;
468         }
469         break;
470     case T_RemoveFuncStmt:
471         {
472             RemoveFuncStmt *stmt = (RemoveFuncStmt *)parsetree;
473             commandTag = "DROP";
474             CHECK_IF_ABORTED();
475             RemoveFunction(stmt->funcname,
476                            length(stmt->args),
477                            stmt->args);
478         }
479         break;
480       
481     case T_RemoveOperStmt:
482         {
483             RemoveOperStmt *stmt = (RemoveOperStmt *)parsetree;
484             char* type1 = (char*) NULL; 
485             char *type2 = (char*) NULL;
486                 
487             commandTag = "DROP";
488             CHECK_IF_ABORTED();
489
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);
495         }
496         break;
497       
498     case T_VersionStmt:
499         {
500             elog(WARN, "CREATE VERSION is not currently implemented");
501         }
502         break;
503       
504     case T_CreatedbStmt:
505         {
506             CreatedbStmt *stmt = (CreatedbStmt *)parsetree;
507
508             commandTag = "CREATEDB";
509             CHECK_IF_ABORTED();
510             createdb(stmt->dbname);
511         }
512         break;
513       
514     case T_DestroydbStmt:
515         {
516             DestroydbStmt *stmt = (DestroydbStmt *)parsetree;
517
518             commandTag = "DESTROYDB";
519             CHECK_IF_ABORTED();
520             destroydb(stmt->dbname);
521         }
522         break;
523       
524         /* Query-level asynchronous notification */
525     case T_NotifyStmt:
526         {
527             NotifyStmt *stmt = (NotifyStmt *)parsetree;
528
529             commandTag = "NOTIFY";
530             CHECK_IF_ABORTED();
531
532             Async_Notify(stmt->relname);
533         }
534         break;
535       
536     case T_ListenStmt:
537         {
538             ListenStmt *stmt = (ListenStmt *)parsetree;
539
540             commandTag = "LISTEN";
541             CHECK_IF_ABORTED();
542
543             Async_Listen(stmt->relname,MasterPid);
544         }
545         break;
546       
547         /* ********************************
548          *      dynamic loader
549          * ********************************
550          */
551     case T_LoadStmt:
552         {
553             LoadStmt *stmt = (LoadStmt *)parsetree;
554             FILE *fp, *fopen();
555             char *filename;
556
557             commandTag = "LOAD";
558             CHECK_IF_ABORTED();
559
560             filename = stmt->filename;
561             closeAllVfds();
562             if ((fp = fopen(filename, "r")) == NULL)
563                 elog(WARN, "LOAD: could not open file %s", filename);
564             fclose(fp);
565             load_file(filename);
566         }
567         break;
568
569     case T_ClusterStmt:
570         {
571             ClusterStmt *stmt = (ClusterStmt *)parsetree;
572
573             commandTag = "CLUSTER";
574             CHECK_IF_ABORTED();
575
576             cluster(stmt->relname, stmt->indexname);
577         }
578         break;
579         
580     case T_VacuumStmt:
581         commandTag = "VACUUM";
582         CHECK_IF_ABORTED();
583         vacuum( ((VacuumStmt *) parsetree)->vacrel,
584                 ((VacuumStmt *) parsetree)->verbose);
585         break;
586
587     case T_ExplainStmt:
588         {
589             ExplainStmt *stmt = (ExplainStmt *)parsetree;
590
591             commandTag = "EXPLAIN";
592             CHECK_IF_ABORTED();
593
594             ExplainQuery(stmt->query, stmt->verbose, dest);
595         }
596         break;
597         
598         /* ********************************
599            Tioga-related statements
600            *********************************/
601     case T_RecipeStmt:
602         {
603             RecipeStmt* stmt = (RecipeStmt*)parsetree;
604             commandTag="EXECUTE RECIPE";
605             CHECK_IF_ABORTED();
606             beginRecipe(stmt);
607         }
608         break;
609       
610       
611         /* ********************************
612          *      default
613          * ********************************
614          */
615     default:
616         elog(WARN, "ProcessUtility: command #%d unsupported",
617              nodeTag(parsetree));
618         break;
619     }
620     
621     /* ----------------
622      *  tell fe/be or whatever that we're done.
623      * ----------------
624      */
625     EndCommand(commandTag, dest);
626 }
627