aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/utility.c
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
committerMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
commitd31084e9d1118b25fd16580d9d8c2924b5740dff (patch)
tree3179e66307d54df9c7b966543550e601eb55e668 /src/backend/tcop/utility.c
downloadpostgresql-PG95-1_01.tar.gz
postgresql-PG95-1_01.zip
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/tcop/utility.c')
-rw-r--r--src/backend/tcop/utility.c646
1 files changed, 646 insertions, 0 deletions
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
new file mode 100644
index 00000000000..e12d18b91ee
--- /dev/null
+++ b/src/backend/tcop/utility.c
@@ -0,0 +1,646 @@
+/*-------------------------------------------------------------------------
+ *
+ * utility.c--
+ * Contains functions which control the execution of the POSTGRES utility
+ * commands. At one time acted as an interface between the Lisp and C
+ * systems.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.1.1.1 1996/07/09 06:22:00 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+#include "parser/dbcommands.h"
+#include "access/xact.h"
+#include "catalog/catalog.h"
+#include "catalog/pg_type.h"
+
+#include "commands/async.h"
+#include "commands/cluster.h"
+#include "commands/command.h"
+#include "commands/copy.h"
+#include "commands/creatinh.h"
+#include "commands/defrem.h"
+#include "commands/purge.h"
+#include "commands/rename.h"
+#include "commands/view.h"
+#include "commands/version.h"
+#include "commands/vacuum.h"
+#include "commands/recipe.h"
+#include "commands/explain.h"
+
+#include "nodes/parsenodes.h"
+#include "parse.h"
+#include "utils/elog.h"
+#include "utils/builtins.h"
+#include "utils/acl.h"
+#include "utils/palloc.h"
+#include "rewrite/rewriteRemove.h"
+#include "rewrite/rewriteDefine.h"
+#include "tcop/tcopdebug.h"
+#include "tcop/dest.h"
+
+#ifndef NO_SECURITY
+#include "miscadmin.h"
+#include "utils/acl.h"
+#include "utils/syscache.h"
+#endif
+
+
+/* ----------------
+ * CHECK_IF_ABORTED() is used to avoid doing unnecessary
+ * processing within an aborted transaction block.
+ * ----------------
+ */
+#define CHECK_IF_ABORTED() \
+ if (IsAbortedTransactionBlockState()) { \
+ elog(NOTICE, "(transaction aborted): %s", \
+ "queries ignored until END"); \
+ commandTag = "*ABORT STATE*"; \
+ break; \
+ } \
+
+/* ----------------
+ * general utility function invoker
+ * ----------------
+ */
+void
+ProcessUtility(Node *parsetree,
+ CommandDest dest)
+{
+ char *commandTag = NULL;
+ char *relname;
+ char *relationName;
+ char *userName;
+
+ userName = GetPgUserName();
+
+ switch (nodeTag(parsetree)) {
+ /* ********************************
+ * transactions
+ * ********************************
+ */
+ case T_TransactionStmt:
+ {
+ TransactionStmt *stmt = (TransactionStmt *)parsetree;
+ switch (stmt->command) {
+ case BEGIN_TRANS:
+ commandTag = "BEGIN";
+ CHECK_IF_ABORTED();
+ BeginTransactionBlock();
+ break;
+
+ case END_TRANS:
+ commandTag = "END";
+ EndTransactionBlock();
+ break;
+
+ case ABORT_TRANS:
+ commandTag = "ABORT";
+ UserAbortTransactionBlock();
+ break;
+ }
+ }
+ break;
+
+ /* ********************************
+ * portal manipulation
+ * ********************************
+ */
+ case T_ClosePortalStmt:
+ {
+ ClosePortalStmt *stmt = (ClosePortalStmt *)parsetree;
+
+ commandTag = "CLOSE";
+ CHECK_IF_ABORTED();
+
+ PerformPortalClose(stmt->portalname, dest);
+ }
+ break;
+
+ case T_FetchStmt:
+ {
+ FetchStmt *stmt = (FetchStmt *)parsetree;
+ char *portalName = stmt->portalname;
+ bool forward;
+ int count;
+
+ commandTag = "FETCH";
+ CHECK_IF_ABORTED();
+
+ forward = (bool)(stmt->direction == FORWARD);
+
+ /* parser ensures that count is >= 0 and
+ 'fetch ALL' -> 0 */
+
+ count = stmt->howMany;
+ PerformPortalFetch(portalName, forward, count, commandTag, dest);
+ }
+ break;
+
+ /* ********************************
+ * relation and attribute manipulation
+ * ********************************
+ */
+ case T_CreateStmt:
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+
+ DefineRelation((CreateStmt *)parsetree);
+ break;
+
+ case T_DestroyStmt:
+ {
+ DestroyStmt *stmt = (DestroyStmt *)parsetree;
+ List *arg;
+ List *args = stmt->relNames;
+
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+
+ foreach (arg, args) {
+ relname = strVal(lfirst(arg));
+ if (IsSystemRelationName(relname))
+ elog(WARN, "class \"%-.*s\" is a system catalog",
+ NAMEDATALEN, relname);
+#ifndef NO_SECURITY
+ if (!pg_ownercheck(userName, relname, RELNAME))
+ elog(WARN, "you do not own class \"%-.*s\"",
+ NAMEDATALEN, relname);
+#endif
+ }
+ foreach (arg, args) {
+ relname = strVal(lfirst(arg));
+ RemoveRelation(relname);
+ }
+ }
+ break;
+
+ case T_PurgeStmt:
+ {
+ PurgeStmt *stmt = (PurgeStmt *)parsetree;
+
+ commandTag = "PURGE";
+ CHECK_IF_ABORTED();
+
+ RelationPurge(stmt->relname,
+ stmt->beforeDate, /* absolute time string */
+ stmt->afterDate); /* relative time string */
+ }
+ break;
+
+ case T_CopyStmt:
+ {
+ CopyStmt *stmt = (CopyStmt *)parsetree;
+ char *filename;
+ char *delim;
+ bool isBinary;
+ bool isFrom;
+ bool pipe = false;
+
+ commandTag = "COPY";
+ CHECK_IF_ABORTED();
+
+ relname = stmt->relname;
+ isBinary = stmt->binary;
+
+ isFrom = (bool)(stmt->direction == FROM);
+ filename = stmt->filename;
+ delim = stmt->delimiter;
+
+#ifndef NO_SECURITY
+ if (isFrom) {
+ if (!pg_aclcheck(relname, userName, ACL_RD))
+ elog(WARN, "%s %s", relname, ACL_NO_PRIV_WARNING);
+ } else {
+ if (!pg_aclcheck(relname, userName, ACL_WR))
+ elog(WARN, "%s %s", relname, ACL_NO_PRIV_WARNING);
+ }
+#endif
+
+ /* Free up file descriptors - going to do a read... */
+
+ closeOneVfd();
+
+ /*
+ * use stdin/stdout if filename is null.
+ */
+ if (filename == NULL)
+ pipe = true;
+
+ if (pipe && IsUnderPostmaster) dest = CopyEnd;
+
+ DoCopy(relname, isBinary, isFrom, pipe, filename, delim);
+ }
+ break;
+
+ case T_AddAttrStmt:
+ {
+ AddAttrStmt *stmt = (AddAttrStmt *)parsetree;
+
+ commandTag = "ADD";
+ CHECK_IF_ABORTED();
+
+ /* owner checking done in PerformAddAttribute (now recursive) */
+ PerformAddAttribute(stmt->relname,
+ userName,
+ stmt->inh,
+ stmt->colDef);
+ }
+ break;
+
+ /*
+ * schema
+ */
+ case T_RenameStmt:
+ {
+ RenameStmt *stmt = (RenameStmt *)parsetree;
+
+ commandTag = "RENAME";
+ CHECK_IF_ABORTED();
+
+ relname = stmt->relname;
+ if (IsSystemRelationName(relname))
+ elog(WARN, "class \"%s\" is a system catalog",
+ relname);
+#ifndef NO_SECURITY
+ if (!pg_ownercheck(userName, relname, RELNAME))
+ elog(WARN, "you do not own class \"%s\"",
+ relname);
+#endif
+
+ /* ----------------
+ * XXX using len == 3 to tell the difference
+ * between "rename rel to newrel" and
+ * "rename att in rel to newatt" will not
+ * work soon because "rename type/operator/rule"
+ * stuff is being added. - cim 10/24/90
+ * ----------------
+ * [another piece of amuzing but useless anecdote -- ay]
+ */
+ if (stmt->column == NULL) {
+ /* ----------------
+ * rename relation
+ *
+ * Note: we also rename the "type" tuple
+ * corresponding to the relation.
+ * ----------------
+ */
+ renamerel(relname, /* old name */
+ stmt->newname); /* new name */
+ TypeRename(relname, /* old name */
+ stmt->newname); /* new name */
+ } else {
+ /* ----------------
+ * rename attribute
+ * ----------------
+ */
+ renameatt(relname, /* relname */
+ stmt->column, /* old att name */
+ stmt->newname, /* new att name */
+ userName,
+ stmt->inh); /* recursive? */
+ }
+ }
+ break;
+
+ case T_ChangeACLStmt:
+ {
+ ChangeACLStmt *stmt = (ChangeACLStmt *)parsetree;
+ List *i;
+ AclItem *aip;
+ unsigned modechg;
+
+ commandTag = "CHANGE";
+ CHECK_IF_ABORTED();
+
+ aip = stmt->aclitem;
+ modechg = stmt->modechg;
+#ifndef NO_SECURITY
+ foreach (i, stmt->relNames) {
+ relname = strVal(lfirst(i));
+ if (!pg_ownercheck(userName, relname, RELNAME))
+ elog(WARN, "you do not own class \"%-.*s\"",
+ NAMEDATALEN, relname);
+ }
+#endif
+ foreach (i, stmt->relNames) {
+ relname = strVal(lfirst(i));
+ ChangeAcl(relname, aip, modechg);
+ }
+
+ }
+ break;
+
+ /* ********************************
+ * object creation / destruction
+ * ********************************
+ */
+ case T_DefineStmt:
+ {
+ DefineStmt *stmt = (DefineStmt *)parsetree;
+
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+
+ switch(stmt->defType) {
+ case OPERATOR:
+ DefineOperator(stmt->defname, /* operator name */
+ stmt->definition); /* rest */
+ break;
+ case P_TYPE:
+ {
+ DefineType (stmt->defname, stmt->definition);
+ }
+ break;
+ case AGGREGATE:
+ DefineAggregate(stmt->defname, /*aggregate name */
+ stmt->definition); /* rest */
+ break;
+ }
+ }
+ break;
+
+ case T_ViewStmt: /* VIEW */
+ {
+ ViewStmt *stmt = (ViewStmt *)parsetree;
+
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+ DefineView (stmt->viewname, stmt->query); /* retrieve parsetree */
+ }
+ break;
+
+ case T_ProcedureStmt: /* FUNCTION */
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+ DefineFunction((ProcedureStmt *)parsetree, dest); /* everything */
+ break;
+
+ case T_IndexStmt:
+ {
+ IndexStmt *stmt = (IndexStmt *)parsetree;
+
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+ /* XXX no support for ARCHIVE indices, yet */
+ DefineIndex(stmt->relname, /* relation name */
+ stmt->idxname, /* index name */
+ stmt->accessMethod, /* am name */
+ stmt->indexParams, /* parameters */
+ stmt->withClause,
+ (Expr*)stmt->whereClause,
+ stmt->rangetable);
+ }
+ break;
+
+ case T_RuleStmt:
+ {
+ RuleStmt *stmt = (RuleStmt *)parsetree;
+#ifndef NO_SECURITY
+ relname = stmt->object->relname;
+ if (!pg_aclcheck(relname, userName, ACL_RU))
+ elog(WARN, "%s %s", relname, ACL_NO_PRIV_WARNING);
+#endif
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+ DefineQueryRewrite(stmt);
+ }
+ break;
+
+ case T_ExtendStmt:
+ {
+ ExtendStmt *stmt = (ExtendStmt *)parsetree;
+
+ commandTag = "EXTEND";
+ CHECK_IF_ABORTED();
+
+ ExtendIndex(stmt->idxname, /* index name */
+ (Expr*)stmt->whereClause, /* where */
+ stmt->rangetable);
+ }
+ break;
+
+ case T_RemoveStmt:
+ {
+ RemoveStmt *stmt = (RemoveStmt *)parsetree;
+
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+
+ switch(stmt->removeType) {
+ case AGGREGATE:
+ RemoveAggregate(stmt->name);
+ break;
+ case INDEX:
+ relname = stmt->name;
+ if (IsSystemRelationName(relname))
+ elog(WARN, "class \"%s\" is a system catalog index",
+ relname);
+#ifndef NO_SECURITY
+ if (!pg_ownercheck(userName, relname, RELNAME))
+ elog(WARN, "you do not own class \"%s\"",
+ relname);
+#endif
+ RemoveIndex(relname);
+ break;
+ case RULE:
+ {
+ char *rulename = stmt->name;
+#ifndef NO_SECURITY
+
+ relationName = RewriteGetRuleEventRel(rulename);
+ if (!pg_aclcheck(relationName, userName, ACL_RU))
+ elog(WARN, "%s %s", relationName, ACL_NO_PRIV_WARNING);
+#endif
+ RemoveRewriteRule(rulename);
+ }
+ break;
+ case P_TYPE:
+#ifndef NO_SECURITY
+ /* XXX moved to remove.c */
+#endif
+ RemoveType(stmt->name);
+ break;
+ case VIEW:
+ {
+ char *viewName = stmt->name;
+ char *ruleName;
+ extern char *RewriteGetRuleEventRel();
+
+#ifndef NO_SECURITY
+
+ ruleName = MakeRetrieveViewRuleName(viewName);
+ relationName = RewriteGetRuleEventRel(ruleName);
+ if (!pg_ownercheck(userName, relationName, RELNAME))
+ elog(WARN, "%s %s", relationName, ACL_NO_PRIV_WARNING);
+ pfree(ruleName);
+#endif
+ RemoveView(viewName);
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case T_RemoveFuncStmt:
+ {
+ RemoveFuncStmt *stmt = (RemoveFuncStmt *)parsetree;
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+ RemoveFunction(stmt->funcname,
+ length(stmt->args),
+ stmt->args);
+ }
+ break;
+
+ case T_RemoveOperStmt:
+ {
+ RemoveOperStmt *stmt = (RemoveOperStmt *)parsetree;
+ char* type1 = (char*) NULL;
+ char *type2 = (char*) NULL;
+
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+
+ if (lfirst(stmt->args)!=NULL)
+ type1 = strVal(lfirst(stmt->args));
+ if (lsecond(stmt->args)!=NULL)
+ type2 = strVal(lsecond(stmt->args));
+ RemoveOperator(stmt->opname, type1, type2);
+ }
+ break;
+
+ case T_VersionStmt:
+ {
+ elog(WARN, "CREATE VERSION is not currently implemented");
+ }
+ break;
+
+ case T_CreatedbStmt:
+ {
+ CreatedbStmt *stmt = (CreatedbStmt *)parsetree;
+
+ commandTag = "CREATEDB";
+ CHECK_IF_ABORTED();
+ createdb(stmt->dbname);
+ }
+ break;
+
+ case T_DestroydbStmt:
+ {
+ DestroydbStmt *stmt = (DestroydbStmt *)parsetree;
+
+ commandTag = "DESTROYDB";
+ CHECK_IF_ABORTED();
+ destroydb(stmt->dbname);
+ }
+ break;
+
+ /* Query-level asynchronous notification */
+ case T_NotifyStmt:
+ {
+ NotifyStmt *stmt = (NotifyStmt *)parsetree;
+
+ commandTag = "NOTIFY";
+ CHECK_IF_ABORTED();
+
+ Async_Notify(stmt->relname);
+ }
+ break;
+
+ case T_ListenStmt:
+ {
+ ListenStmt *stmt = (ListenStmt *)parsetree;
+
+ commandTag = "LISTEN";
+ CHECK_IF_ABORTED();
+
+ Async_Listen(stmt->relname,MasterPid);
+ }
+ break;
+
+ /* ********************************
+ * dynamic loader
+ * ********************************
+ */
+ case T_LoadStmt:
+ {
+ LoadStmt *stmt = (LoadStmt *)parsetree;
+ FILE *fp, *fopen();
+ char *filename;
+
+ commandTag = "LOAD";
+ CHECK_IF_ABORTED();
+
+ filename = stmt->filename;
+ closeAllVfds();
+ if ((fp = fopen(filename, "r")) == NULL)
+ elog(WARN, "LOAD: could not open file %s", filename);
+ fclose(fp);
+ load_file(filename);
+ }
+ break;
+
+ case T_ClusterStmt:
+ {
+ ClusterStmt *stmt = (ClusterStmt *)parsetree;
+
+ commandTag = "CLUSTER";
+ CHECK_IF_ABORTED();
+
+ cluster(stmt->relname, stmt->indexname);
+ }
+ break;
+
+ case T_VacuumStmt:
+ commandTag = "VACUUM";
+ CHECK_IF_ABORTED();
+ vacuum(((VacuumStmt *) parsetree)->vacrel);
+ break;
+
+ case T_ExplainStmt:
+ {
+ ExplainStmt *stmt = (ExplainStmt *)parsetree;
+
+ commandTag = "EXPLAIN";
+ CHECK_IF_ABORTED();
+
+ ExplainQuery(stmt->query, stmt->options, dest);
+ }
+ break;
+
+ /* ********************************
+ Tioga-related statements
+ *********************************/
+ case T_RecipeStmt:
+ {
+ RecipeStmt* stmt = (RecipeStmt*)parsetree;
+ commandTag="EXECUTE RECIPE";
+ CHECK_IF_ABORTED();
+ beginRecipe(stmt);
+ }
+ break;
+
+
+ /* ********************************
+ * default
+ * ********************************
+ */
+ default:
+ elog(WARN, "ProcessUtility: command #%d unsupported",
+ nodeTag(parsetree));
+ break;
+ }
+
+ /* ----------------
+ * tell fe/be or whatever that we're done.
+ * ----------------
+ */
+ EndCommand(commandTag, dest);
+}
+