]> granicus.if.org Git - postgresql/blob - src/backend/tcop/utility.c
74cd794f01d2d6f1dcf31032dc8fb5dff4ab64bd
[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.36 1998/01/05 18:43:09 momjian Exp $
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17 #include "access/xact.h"
18 #include "access/heapam.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/dbcommands.h"
28 #include "commands/sequence.h"
29 #include "commands/defrem.h"
30 #include "commands/rename.h"
31 #include "commands/view.h"
32 #include "commands/version.h"
33 #include "commands/vacuum.h"
34 #include "commands/recipe.h"
35 #include "commands/explain.h"
36 #include "commands/trigger.h"
37 #include "commands/proclang.h"
38 #include "commands/variable.h"
39
40 #include "nodes/parsenodes.h"
41 #include "../backend/parser/parse.h"
42 #include "utils/builtins.h"
43 #include "utils/acl.h"
44 #include "utils/palloc.h"
45 #include "rewrite/rewriteRemove.h"
46 #include "rewrite/rewriteDefine.h"
47 #include "tcop/tcopdebug.h"
48 #include "tcop/dest.h"
49 #include "tcop/utility.h"
50 #include "fmgr.h"                               /* For load_file() */
51 #include "storage/fd.h"
52
53 #ifndef NO_SECURITY
54 #include "miscadmin.h"
55 #include "utils/acl.h"
56 #include "utils/syscache.h"
57 #endif
58
59 void DefineUser(CreateUserStmt *stmt);
60 void AlterUser(AlterUserStmt *stmt);
61 void RemoveUser(char *username);
62
63 /* ----------------
64  *              CHECK_IF_ABORTED() is used to avoid doing unnecessary
65  *              processing within an aborted transaction block.
66  * ----------------
67  */
68 #define CHECK_IF_ABORTED() \
69         if (IsAbortedTransactionBlockState()) { \
70                 elog(NOTICE, "(transaction aborted): %s", \
71                          "queries ignored until END"); \
72                 commandTag = "*ABORT STATE*"; \
73                 break; \
74         } \
75
76 /* ----------------
77  *              general utility function invoker
78  * ----------------
79  */
80 void
81 ProcessUtility(Node * parsetree,
82                            CommandDest dest)
83 {
84         char       *commandTag = NULL;
85         char       *relname;
86         char       *relationName;
87         char       *userName;
88
89         userName = GetPgUserName();
90
91         switch (nodeTag(parsetree))
92         {
93
94                         /*
95                          * ******************************** transactions ********************************
96                          *
97                          */
98                 case T_TransactionStmt:
99                         {
100                                 TransactionStmt *stmt = (TransactionStmt *) parsetree;
101
102                                 switch (stmt->command)
103                                 {
104                                         case BEGIN_TRANS:
105                                                 commandTag = "BEGIN";
106                                                 CHECK_IF_ABORTED();
107                                                 BeginTransactionBlock();
108                                                 break;
109
110                                         case END_TRANS:
111                                                 commandTag = "END";
112                                                 EndTransactionBlock();
113                                                 break;
114
115                                         case ABORT_TRANS:
116                                                 commandTag = "ABORT";
117                                                 UserAbortTransactionBlock();
118                                                 break;
119                                 }
120                         }
121                         break;
122
123                         /*
124                          * ******************************** portal manipulation ********************************
125                          *
126                          */
127                 case T_ClosePortalStmt:
128                         {
129                                 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
130
131                                 commandTag = "CLOSE";
132                                 CHECK_IF_ABORTED();
133
134                                 PerformPortalClose(stmt->portalname, dest);
135                         }
136                         break;
137
138                 case T_FetchStmt:
139                         {
140                                 FetchStmt  *stmt = (FetchStmt *) parsetree;
141                                 char       *portalName = stmt->portalname;
142                                 bool            forward;
143                                 int                     count;
144
145                                 commandTag = (stmt->ismove) ? "MOVE" : "FETCH";
146                                 CHECK_IF_ABORTED();
147
148                                 forward = (bool) (stmt->direction == FORWARD);
149
150                                 /*
151                                  * parser ensures that count is >= 0 and 'fetch ALL' -> 0
152                                  */
153
154                                 count = stmt->howMany;
155                                 PerformPortalFetch(portalName, forward, count, commandTag,
156                                                                    (stmt->ismove) ? None : dest);               /* /dev/null for MOVE */
157                         }
158                         break;
159
160                         /*
161                          * ******************************** relation and attribute
162                          * manipulation ********************************
163                          *
164                          */
165                 case T_CreateStmt:
166                         commandTag = "CREATE";
167                         CHECK_IF_ABORTED();
168
169                         DefineRelation((CreateStmt *) parsetree);
170                         break;
171
172                 case T_DestroyStmt:
173                         {
174                                 DestroyStmt *stmt = (DestroyStmt *) parsetree;
175                                 List       *arg;
176                                 List       *args = stmt->relNames;
177                                 Relation        rel;
178
179                                 commandTag = "DROP";
180                                 CHECK_IF_ABORTED();
181
182                                 foreach(arg, args)
183                                 {
184                                         relname = strVal(lfirst(arg));
185                                         if (IsSystemRelationName(relname))
186                                                 elog(ERROR, "class \"%s\" is a system catalog",
187                                                          relname);
188                                         rel = heap_openr(relname);
189                                         if (RelationIsValid(rel))
190                                         {
191                                                 if (stmt->sequence &&
192                                                         rel->rd_rel->relkind != RELKIND_SEQUENCE)
193                                                         elog(ERROR, "Use DROP TABLE to drop table '%s'",
194                                                                  relname);
195                                                 if (!(stmt->sequence) &&
196                                                         rel->rd_rel->relkind == RELKIND_SEQUENCE)
197                                                         elog(ERROR, "Use DROP SEQUENCE to drop sequence '%s'",
198                                                                  relname);
199                                                 heap_close(rel);
200                                         }
201 #ifndef NO_SECURITY
202                                         if (!pg_ownercheck(userName, relname, RELNAME))
203                                                 elog(ERROR, "you do not own class \"%s\"",
204                                                          relname);
205 #endif
206                                 }
207                                 foreach(arg, args)
208                                 {
209                                         relname = strVal(lfirst(arg));
210                                         RemoveRelation(relname);
211                                 }
212                         }
213                         break;
214
215                 case T_CopyStmt:
216                         {
217                                 CopyStmt   *stmt = (CopyStmt *) parsetree;
218
219                                 commandTag = "COPY";
220                                 CHECK_IF_ABORTED();
221
222                                 DoCopy(stmt->relname,
223                                            stmt->binary,
224                                            stmt->oids,
225                                            (bool) (stmt->direction == FROM),
226                                            (bool) (stmt->filename == NULL),
227
228                                 /*
229                                  * null filename means copy to/from stdout/stdin, rather
230                                  * than to/from a file.
231                                  */
232                                            stmt->filename,
233                                            stmt->delimiter);
234                         }
235                         break;
236
237                 case T_AddAttrStmt:
238                         {
239                                 AddAttrStmt *stmt = (AddAttrStmt *) parsetree;
240
241                                 commandTag = "ADD";
242                                 CHECK_IF_ABORTED();
243
244                                 /*
245                                  * owner checking done in PerformAddAttribute (now recursive)
246                                  */
247                                 PerformAddAttribute(stmt->relname,
248                                                                         userName,
249                                                                         stmt->inh,
250                                                                         (ColumnDef *)stmt->colDef);
251                         }
252                         break;
253
254                         /*
255                          * schema
256                          */
257                 case T_RenameStmt:
258                         {
259                                 RenameStmt *stmt = (RenameStmt *) parsetree;
260
261                                 commandTag = "RENAME";
262                                 CHECK_IF_ABORTED();
263
264                                 relname = stmt->relname;
265                                 if (IsSystemRelationName(relname))
266                                         elog(ERROR, "class \"%s\" is a system catalog",
267                                                  relname);
268 #ifndef NO_SECURITY
269                                 if (!pg_ownercheck(userName, relname, RELNAME))
270                                         elog(ERROR, "you do not own class \"%s\"",
271                                                  relname);
272 #endif
273
274                                 /* ----------------
275                                  *      XXX using len == 3 to tell the difference
276                                  *              between "rename rel to newrel" and
277                                  *              "rename att in rel to newatt" will not
278                                  *              work soon because "rename type/operator/rule"
279                                  *              stuff is being added. - cim 10/24/90
280                                  * ----------------
281                                  * [another piece of amuzing but useless anecdote -- ay]
282                                  */
283                                 if (stmt->column == NULL)
284                                 {
285                                         /* ----------------
286                                          *              rename relation
287                                          *
288                                          *              Note: we also rename the "type" tuple
289                                          *              corresponding to the relation.
290                                          * ----------------
291                                          */
292                                         renamerel(relname,      /* old name */
293                                                           stmt->newname);       /* new name */
294                                         TypeRename(relname, /* old name */
295                                                            stmt->newname);      /* new name */
296                                 }
297                                 else
298                                 {
299                                         /* ----------------
300                                          *              rename attribute
301                                          * ----------------
302                                          */
303                                         renameatt(relname,      /* relname */
304                                                           stmt->column,         /* old att name */
305                                                           stmt->newname,        /* new att name */
306                                                           userName,
307                                                           stmt->inh);           /* recursive? */
308                                 }
309                         }
310                         break;
311
312                 case T_ChangeACLStmt:
313                         {
314                                 ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
315                                 List       *i;
316                                 AclItem    *aip;
317                                 unsigned        modechg;
318
319                                 commandTag = "CHANGE";
320                                 CHECK_IF_ABORTED();
321
322                                 aip = stmt->aclitem;
323
324                                 modechg = stmt->modechg;
325 #ifndef NO_SECURITY
326                                 foreach(i, stmt->relNames)
327                                 {
328                                         relname = strVal(lfirst(i));
329                                         if (!pg_ownercheck(userName, relname, RELNAME))
330                                                 elog(ERROR, "you do not own class \"%s\"",
331                                                          relname);
332                                 }
333 #endif
334                                 foreach(i, stmt->relNames)
335                                 {
336                                         relname = strVal(lfirst(i));
337                                         ChangeAcl(relname, aip, modechg);
338                                 }
339
340                         }
341                         break;
342
343                         /*
344                          * ******************************** object creation /
345                          * destruction ********************************
346                          *
347                          */
348                 case T_DefineStmt:
349                         {
350                                 DefineStmt *stmt = (DefineStmt *) parsetree;
351
352                                 commandTag = "CREATE";
353                                 CHECK_IF_ABORTED();
354
355                                 switch (stmt->defType)
356                                 {
357                                         case OPERATOR:
358                                                 DefineOperator(stmt->defname,   /* operator name */
359                                                                            stmt->definition);           /* rest */
360                                                 break;
361                                         case TYPE_P:
362                                                 {
363                                                         DefineType(stmt->defname, stmt->definition);
364                                                 }
365                                                 break;
366                                         case AGGREGATE:
367                                                 DefineAggregate(stmt->defname,  /* aggregate name */
368                                                                                 stmt->definition);              /* rest */
369                                                 break;
370                                 }
371                         }
372                         break;
373
374                 case T_ViewStmt:                /* CREATE VIEW */
375                         {
376                                 ViewStmt   *stmt = (ViewStmt *) parsetree;
377
378                                 commandTag = "CREATE";
379                                 CHECK_IF_ABORTED();
380                                 DefineView(stmt->viewname, stmt->query);                /* retrieve parsetree */
381                         }
382                         break;
383
384                 case T_ProcedureStmt:   /* CREATE FUNCTION */
385                         commandTag = "CREATE";
386                         CHECK_IF_ABORTED();
387                         CreateFunction((ProcedureStmt *) parsetree, dest);      /* everything */
388                         break;
389
390                 case T_IndexStmt:               /* CREATE INDEX */
391                         {
392                                 IndexStmt  *stmt = (IndexStmt *) parsetree;
393
394                                 commandTag = "CREATE";
395                                 CHECK_IF_ABORTED();
396                                 DefineIndex(stmt->relname,              /* relation name */
397                                                         stmt->idxname,          /* index name */
398                                                         stmt->accessMethod, /* am name */
399                                                         stmt->indexParams,      /* parameters */
400                                                         stmt->withClause,
401                                                         stmt->unique,
402                                                         (Expr *) stmt->whereClause,
403                                                         stmt->rangetable);
404                         }
405                         break;
406
407                 case T_RuleStmt:                /* CREATE RULE */
408                         {
409                                 RuleStmt   *stmt = (RuleStmt *) parsetree;
410                                 int                     aclcheck_result;
411
412 #ifndef NO_SECURITY
413                                 relname = stmt->object->relname;
414                                 aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
415                                 if (aclcheck_result != ACLCHECK_OK)
416                                         elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
417 #endif
418                                 commandTag = "CREATE";
419                                 CHECK_IF_ABORTED();
420                                 DefineQueryRewrite(stmt);
421                         }
422                         break;
423
424                 case T_CreateSeqStmt:
425                         commandTag = "CREATE";
426                         CHECK_IF_ABORTED();
427
428                         DefineSequence((CreateSeqStmt *) parsetree);
429                         break;
430
431                 case T_ExtendStmt:
432                         {
433                                 ExtendStmt *stmt = (ExtendStmt *) parsetree;
434
435                                 commandTag = "EXTEND";
436                                 CHECK_IF_ABORTED();
437
438                                 ExtendIndex(stmt->idxname,              /* index name */
439                                                         (Expr *) stmt->whereClause, /* where */
440                                                         stmt->rangetable);
441                         }
442                         break;
443
444                 case T_RemoveStmt:
445                         {
446                                 RemoveStmt *stmt = (RemoveStmt *) parsetree;
447
448                                 commandTag = "DROP";
449                                 CHECK_IF_ABORTED();
450
451                                 switch (stmt->removeType)
452                                 {
453                                         case INDEX:
454                                                 relname = stmt->name;
455                                                 if (IsSystemRelationName(relname))
456                                                         elog(ERROR, "class \"%s\" is a system catalog index",
457                                                                  relname);
458 #ifndef NO_SECURITY
459                                                 if (!pg_ownercheck(userName, relname, RELNAME))
460                                                         elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
461 #endif
462                                                 RemoveIndex(relname);
463                                                 break;
464                                         case RULE:
465                                                 {
466                                                         char       *rulename = stmt->name;
467                                                         int                     aclcheck_result;
468
469 #ifndef NO_SECURITY
470
471                                                         relationName = RewriteGetRuleEventRel(rulename);
472                                                         aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
473                                                         if (aclcheck_result != ACLCHECK_OK)
474                                                         {
475                                                                 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
476                                                         }
477 #endif
478                                                         RemoveRewriteRule(rulename);
479                                                 }
480                                                 break;
481                                         case TYPE_P:
482 #ifndef NO_SECURITY
483                                                 /* XXX moved to remove.c */
484 #endif
485                                                 RemoveType(stmt->name);
486                                                 break;
487                                         case VIEW:
488                                                 {
489                                                         char       *viewName = stmt->name;
490                                                         char       *ruleName;
491
492 #ifndef NO_SECURITY
493
494                                                         ruleName = MakeRetrieveViewRuleName(viewName);
495                                                         relationName = RewriteGetRuleEventRel(ruleName);
496                                                         if (!pg_ownercheck(userName, relationName, RELNAME))
497                                                                 elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
498                                                         pfree(ruleName);
499 #endif
500                                                         RemoveView(viewName);
501                                                 }
502                                                 break;
503                                 }
504                                 break;
505                         }
506                         break;
507
508                 case T_RemoveAggrStmt:
509                         {
510                                 RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
511
512                                 commandTag = "DROP";
513                                 CHECK_IF_ABORTED();
514                                 RemoveAggregate(stmt->aggname, stmt->aggtype);
515                         }
516                         break;
517
518                 case T_RemoveFuncStmt:
519                         {
520                                 RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
521
522                                 commandTag = "DROP";
523                                 CHECK_IF_ABORTED();
524                                 RemoveFunction(stmt->funcname,
525                                                            length(stmt->args),
526                                                            stmt->args);
527                         }
528                         break;
529
530                 case T_RemoveOperStmt:
531                         {
532                                 RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
533                                 char       *type1 = (char *) NULL;
534                                 char       *type2 = (char *) NULL;
535
536                                 commandTag = "DROP";
537                                 CHECK_IF_ABORTED();
538
539                                 if (lfirst(stmt->args) != NULL)
540                                         type1 = strVal(lfirst(stmt->args));
541                                 if (lsecond(stmt->args) != NULL)
542                                         type2 = strVal(lsecond(stmt->args));
543                                 RemoveOperator(stmt->opname, type1, type2);
544                         }
545                         break;
546
547                 case T_VersionStmt:
548                         {
549                                 elog(ERROR, "CREATE VERSION is not currently implemented");
550                         }
551                         break;
552
553                 case T_CreatedbStmt:
554                         {
555                                 CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
556
557                                 commandTag = "CREATEDB";
558                                 CHECK_IF_ABORTED();
559                                 createdb(stmt->dbname, stmt->dbpath);
560                         }
561                         break;
562
563                 case T_DestroydbStmt:
564                         {
565                                 DestroydbStmt *stmt = (DestroydbStmt *) parsetree;
566
567                                 commandTag = "DESTROYDB";
568                                 CHECK_IF_ABORTED();
569                                 destroydb(stmt->dbname);
570                         }
571                         break;
572
573                         /* Query-level asynchronous notification */
574                 case T_NotifyStmt:
575                         {
576                                 NotifyStmt *stmt = (NotifyStmt *) parsetree;
577
578                                 commandTag = "NOTIFY";
579                                 CHECK_IF_ABORTED();
580
581                                 Async_Notify(stmt->relname);
582                         }
583                         break;
584
585                 case T_ListenStmt:
586                         {
587                                 ListenStmt *stmt = (ListenStmt *) parsetree;
588
589                                 commandTag = "LISTEN";
590                                 CHECK_IF_ABORTED();
591
592                                 Async_Listen(stmt->relname, MasterPid);
593                         }
594                         break;
595
596                         /*
597                          * ******************************** dynamic loader ********************************
598                          *
599                          */
600                 case T_LoadStmt:
601                         {
602                                 LoadStmt   *stmt = (LoadStmt *) parsetree;
603                                 FILE       *fp;
604                                 char       *filename;
605
606                                 commandTag = "LOAD";
607                                 CHECK_IF_ABORTED();
608
609                                 filename = stmt->filename;
610                                 closeAllVfds();
611                                 if ((fp = AllocateFile(filename, "r")) == NULL)
612                                         elog(ERROR, "LOAD: could not open file %s", filename);
613                                 FreeFile(fp);
614                                 load_file(filename);
615                         }
616                         break;
617
618                 case T_ClusterStmt:
619                         {
620                                 ClusterStmt *stmt = (ClusterStmt *) parsetree;
621
622                                 commandTag = "CLUSTER";
623                                 CHECK_IF_ABORTED();
624
625                                 cluster(stmt->relname, stmt->indexname);
626                         }
627                         break;
628
629                 case T_VacuumStmt:
630                         commandTag = "VACUUM";
631                         CHECK_IF_ABORTED();
632                         vacuum(((VacuumStmt *) parsetree)->vacrel,
633                                    ((VacuumStmt *) parsetree)->verbose,
634                                    ((VacuumStmt *) parsetree)->analyze,
635                                    ((VacuumStmt *) parsetree)->va_spec);
636                         break;
637
638                 case T_ExplainStmt:
639                         {
640                                 ExplainStmt *stmt = (ExplainStmt *) parsetree;
641
642                                 commandTag = "EXPLAIN";
643                                 CHECK_IF_ABORTED();
644
645                                 ExplainQuery(stmt->query, stmt->verbose, dest);
646                         }
647                         break;
648
649                         /*
650                          * ******************************** Tioga-related statements *******************************
651                          */
652                 case T_RecipeStmt:
653                         {
654                                 RecipeStmt *stmt = (RecipeStmt *) parsetree;
655
656                                 commandTag = "EXECUTE RECIPE";
657                                 CHECK_IF_ABORTED();
658                                 beginRecipe(stmt);
659                         }
660                         break;
661
662                         /*
663                          * ******************************** set variable statements *******************************
664                          */
665                 case T_VariableSetStmt:
666                         {
667                                 VariableSetStmt *n = (VariableSetStmt *) parsetree;
668
669                                 SetPGVariable(n->name, n->value);
670                                 commandTag = "SET VARIABLE";
671                         }
672                         break;
673
674                 case T_VariableShowStmt:
675                         {
676                                 VariableShowStmt *n = (VariableShowStmt *) parsetree;
677
678                                 GetPGVariable(n->name);
679                                 commandTag = "SHOW VARIABLE";
680                         }
681                         break;
682
683                 case T_VariableResetStmt:
684                         {
685                                 VariableResetStmt *n = (VariableResetStmt *) parsetree;
686
687                                 ResetPGVariable(n->name);
688                                 commandTag = "RESET VARIABLE";
689                         }
690                         break;
691
692                         /*
693                          * ******************************** TRIGGER statements *******************************
694                          */
695                 case T_CreateTrigStmt:
696                         commandTag = "CREATE";
697                         CHECK_IF_ABORTED();
698
699                         CreateTrigger((CreateTrigStmt *) parsetree);
700                         break;
701
702                 case T_DropTrigStmt:
703                         commandTag = "DROP";
704                         CHECK_IF_ABORTED();
705
706                         DropTrigger((DropTrigStmt *) parsetree);
707                         break;
708
709                         /*
710                          * ************* PROCEDURAL LANGUAGE statements *****************
711                          */
712                 case T_CreatePLangStmt:
713                         commandTag = "CREATE";
714                         CHECK_IF_ABORTED();
715
716                         CreateProceduralLanguage((CreatePLangStmt *) parsetree);
717                         break;
718
719                 case T_DropPLangStmt:
720                         commandTag = "DROP";
721                         CHECK_IF_ABORTED();
722
723                         DropProceduralLanguage((DropPLangStmt *) parsetree);
724                         break;
725
726                       /*
727                        * ******************************** USER statements ****
728                        *
729                        */
730                 case T_CreateUserStmt:
731                         commandTag = "CREATE USER";
732                         CHECK_IF_ABORTED();
733
734                         DefineUser((CreateUserStmt*)parsetree);
735                         break;
736
737                 case T_AlterUserStmt:
738                         commandTag = "ALTER USER";
739                         CHECK_IF_ABORTED();
740
741                         AlterUser((AlterUserStmt*)parsetree);
742                         break;
743
744                 case T_DropUserStmt:
745                         commandTag = "DROP USER";
746                         CHECK_IF_ABORTED();
747
748                         RemoveUser(((DropUserStmt*)parsetree)->user);
749                         break;
750
751
752                         /*
753                          * ******************************** default ********************************
754                          *
755                          */
756                 default:
757                         elog(ERROR, "ProcessUtility: command #%d unsupported",
758                                  nodeTag(parsetree));
759                         break;
760         }
761
762         /* ----------------
763          *      tell fe/be or whatever that we're done.
764          * ----------------
765          */
766         EndCommand(commandTag, dest);
767 }