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