]> granicus.if.org Git - postgresql/blob - src/backend/tcop/utility.c
Warning removal cleanup
[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.8 1996/11/11 04:54:54 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                         (Expr*)stmt->whereClause,
376                         stmt->rangetable);
377         }
378         break;
379       
380     case T_RuleStmt:            /* CREATE RULE */
381         {
382             RuleStmt *stmt = (RuleStmt *)parsetree;
383 #ifndef NO_SECURITY
384             relname = stmt->object->relname;
385             if (!pg_aclcheck(relname, userName, ACL_RU))
386                 elog(WARN, "%s %s", relname, ACL_NO_PRIV_WARNING);      
387 #endif
388             commandTag = "CREATE";
389             CHECK_IF_ABORTED();
390             DefineQueryRewrite(stmt);
391         }
392         break;
393       
394     case T_ExtendStmt:
395         {
396             ExtendStmt *stmt = (ExtendStmt *)parsetree;
397
398             commandTag = "EXTEND";
399             CHECK_IF_ABORTED();
400         
401             ExtendIndex(stmt->idxname, /* index name */
402                         (Expr*)stmt->whereClause, /* where */
403                         stmt->rangetable);
404         }
405         break;
406       
407     case T_RemoveStmt:
408         {
409             RemoveStmt *stmt = (RemoveStmt *)parsetree;
410
411             commandTag = "DROP";
412             CHECK_IF_ABORTED();
413         
414             switch(stmt->removeType) {
415             case AGGREGATE:
416                 RemoveAggregate(stmt->name);
417                 break;
418             case INDEX:
419                 relname = stmt->name;
420                 if (IsSystemRelationName(relname))
421                     elog(WARN, "class \"%s\" is a system catalog index",
422                          relname);
423 #ifndef NO_SECURITY
424                 if (!pg_ownercheck(userName, relname, RELNAME))
425                     elog(WARN, "you do not own class \"%s\"",
426                          relname);
427 #endif
428                 RemoveIndex(relname);
429                 break;
430             case RULE:
431                 {
432                     char *rulename = stmt->name;
433 #ifndef NO_SECURITY
434                 
435                     relationName = RewriteGetRuleEventRel(rulename);
436                     if (!pg_aclcheck(relationName, userName, ACL_RU))
437                         elog(WARN, "%s %s", relationName, ACL_NO_PRIV_WARNING);
438 #endif
439                     RemoveRewriteRule(rulename);
440                 }
441                 break;
442             case P_TYPE:
443 #ifndef NO_SECURITY
444                 /* XXX moved to remove.c */
445 #endif
446                 RemoveType(stmt->name);
447                 break;
448             case VIEW:
449                 {
450                     char *viewName = stmt->name;
451                     char *ruleName;
452                     extern char *RewriteGetRuleEventRel();
453
454 #ifndef NO_SECURITY
455                 
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);
460                     pfree(ruleName);
461 #endif
462                     RemoveView(viewName);
463                 }
464                 break;
465             }
466             break;
467         }
468         break;
469     case T_RemoveFuncStmt:
470         {
471             RemoveFuncStmt *stmt = (RemoveFuncStmt *)parsetree;
472             commandTag = "DROP";
473             CHECK_IF_ABORTED();
474             RemoveFunction(stmt->funcname,
475                            length(stmt->args),
476                            stmt->args);
477         }
478         break;
479       
480     case T_RemoveOperStmt:
481         {
482             RemoveOperStmt *stmt = (RemoveOperStmt *)parsetree;
483             char* type1 = (char*) NULL; 
484             char *type2 = (char*) NULL;
485                 
486             commandTag = "DROP";
487             CHECK_IF_ABORTED();
488
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);
494         }
495         break;
496       
497     case T_VersionStmt:
498         {
499             elog(WARN, "CREATE VERSION is not currently implemented");
500         }
501         break;
502       
503     case T_CreatedbStmt:
504         {
505             CreatedbStmt *stmt = (CreatedbStmt *)parsetree;
506
507             commandTag = "CREATEDB";
508             CHECK_IF_ABORTED();
509             createdb(stmt->dbname);
510         }
511         break;
512       
513     case T_DestroydbStmt:
514         {
515             DestroydbStmt *stmt = (DestroydbStmt *)parsetree;
516
517             commandTag = "DESTROYDB";
518             CHECK_IF_ABORTED();
519             destroydb(stmt->dbname);
520         }
521         break;
522       
523         /* Query-level asynchronous notification */
524     case T_NotifyStmt:
525         {
526             NotifyStmt *stmt = (NotifyStmt *)parsetree;
527
528             commandTag = "NOTIFY";
529             CHECK_IF_ABORTED();
530
531             Async_Notify(stmt->relname);
532         }
533         break;
534       
535     case T_ListenStmt:
536         {
537             ListenStmt *stmt = (ListenStmt *)parsetree;
538
539             commandTag = "LISTEN";
540             CHECK_IF_ABORTED();
541
542             Async_Listen(stmt->relname,MasterPid);
543         }
544         break;
545       
546         /* ********************************
547          *      dynamic loader
548          * ********************************
549          */
550     case T_LoadStmt:
551         {
552             LoadStmt *stmt = (LoadStmt *)parsetree;
553             FILE *fp, *fopen();
554             char *filename;
555
556             commandTag = "LOAD";
557             CHECK_IF_ABORTED();
558
559             filename = stmt->filename;
560             closeAllVfds();
561             if ((fp = fopen(filename, "r")) == NULL)
562                 elog(WARN, "LOAD: could not open file %s", filename);
563             fclose(fp);
564             load_file(filename);
565         }
566         break;
567
568     case T_ClusterStmt:
569         {
570             ClusterStmt *stmt = (ClusterStmt *)parsetree;
571
572             commandTag = "CLUSTER";
573             CHECK_IF_ABORTED();
574
575             cluster(stmt->relname, stmt->indexname);
576         }
577         break;
578         
579     case T_VacuumStmt:
580         commandTag = "VACUUM";
581         CHECK_IF_ABORTED();
582         vacuum(((VacuumStmt *) parsetree)->vacrel);
583         break;
584
585     case T_ExplainStmt:
586         {
587             ExplainStmt *stmt = (ExplainStmt *)parsetree;
588
589             commandTag = "EXPLAIN";
590             CHECK_IF_ABORTED();
591
592             ExplainQuery(stmt->query, stmt->options, dest);
593         }
594         break;
595         
596         /* ********************************
597            Tioga-related statements
598            *********************************/
599     case T_RecipeStmt:
600         {
601             RecipeStmt* stmt = (RecipeStmt*)parsetree;
602             commandTag="EXECUTE RECIPE";
603             CHECK_IF_ABORTED();
604             beginRecipe(stmt);
605         }
606         break;
607       
608       
609         /* ********************************
610          *      default
611          * ********************************
612          */
613     default:
614         elog(WARN, "ProcessUtility: command #%d unsupported",
615              nodeTag(parsetree));
616         break;
617     }
618     
619     /* ----------------
620      *  tell fe/be or whatever that we're done.
621      * ----------------
622      */
623     EndCommand(commandTag, dest);
624 }
625