aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>1997-09-07 05:04:48 +0000
committerBruce Momjian <bruce@momjian.us>1997-09-07 05:04:48 +0000
commit1ccd423235a48739d6f7a4d7889705b5f9ecc69b (patch)
tree8001c4e839dfad8f29ceda7f8c5f5dbb8759b564 /src/backend/tcop
parent8fecd4febf8357f3cc20383ed29ced484877d5ac (diff)
downloadpostgresql-1ccd423235a48739d6f7a4d7889705b5f9ecc69b.tar.gz
postgresql-1ccd423235a48739d6f7a4d7889705b5f9ecc69b.zip
Massive commit to run PGINDENT on all *.c and *.h files.
Diffstat (limited to 'src/backend/tcop')
-rw-r--r--src/backend/tcop/aclchk.c952
-rw-r--r--src/backend/tcop/dest.c502
-rw-r--r--src/backend/tcop/fastpath.c520
-rw-r--r--src/backend/tcop/postgres.c2789
-rw-r--r--src/backend/tcop/pquery.c563
-rw-r--r--src/backend/tcop/utility.c1212
-rw-r--r--src/backend/tcop/variable.c598
7 files changed, 3728 insertions, 3408 deletions
diff --git a/src/backend/tcop/aclchk.c b/src/backend/tcop/aclchk.c
index fade9d09826..db6932586b7 100644
--- a/src/backend/tcop/aclchk.c
+++ b/src/backend/tcop/aclchk.c
@@ -1,23 +1,23 @@
/*-------------------------------------------------------------------------
*
* aclchk.c--
- * Routines to check access control permissions.
+ * Routines to check access control permissions.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/Attic/aclchk.c,v 1.13 1997/08/19 21:33:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/Attic/aclchk.c,v 1.14 1997/09/07 04:49:28 momjian Exp $
*
* NOTES
- * See acl.h.
+ * See acl.h.
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h"
-#include "utils/acl.h" /* where declarations for this file go */
+#include "utils/acl.h" /* where declarations for this file go */
#include "access/heapam.h"
#include "access/htup.h"
#include "access/tupmacs.h"
@@ -36,7 +36,7 @@
#include "parser/catalog_utils.h"
#include "fmgr.h"
-static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode);
+static int32 aclcheck(Acl * acl, AclId id, AclIdType idtype, AclMode mode);
/*
* Enable use of user relations in place of real system catalogs.
@@ -49,209 +49,226 @@ static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode);
* relname and relowner are in the same place, happily.
*/
#undef Anum_pg_class_relacl
-#define Anum_pg_class_relacl 3
+#define Anum_pg_class_relacl 3
#undef Natts_pg_class
-#define Natts_pg_class 3
+#define Natts_pg_class 3
#undef Name_pg_class
-#define Name_pg_class "pgacls"
+#define Name_pg_class "pgacls"
#undef Name_pg_group
-#define Name_pg_group "pggroup"
+#define Name_pg_group "pggroup"
#endif
/* warning messages, now more explicit. */
/* should correspond to the order of the ACLCHK_* result codes above. */
-char *aclcheck_error_strings[] = {
- "No error.",
- "Permission denied.",
- "Table does not exist.",
- "Must be table owner."
+char *aclcheck_error_strings[] = {
+ "No error.",
+ "Permission denied.",
+ "Table does not exist.",
+ "Must be table owner."
};
#ifdef ACLDEBUG_TRACE
static
-dumpacl(Acl *acl)
+dumpacl(Acl * acl)
{
- register unsigned i;
- AclItem *aip;
-
- elog(DEBUG, "acl size = %d, # acls = %d",
- ACL_SIZE(acl), ACL_NUM(acl));
- aip = (AclItem *) ACL_DAT(acl);
- for (i = 0; i < ACL_NUM(acl); ++i)
- elog(DEBUG, " acl[%d]: %s", i, aclitemout(aip + i));
+ register unsigned i;
+ AclItem *aip;
+
+ elog(DEBUG, "acl size = %d, # acls = %d",
+ ACL_SIZE(acl), ACL_NUM(acl));
+ aip = (AclItem *) ACL_DAT(acl);
+ for (i = 0; i < ACL_NUM(acl); ++i)
+ elog(DEBUG, " acl[%d]: %s", i, aclitemout(aip + i));
}
+
#endif
/*
- *
+ *
*/
void
-ChangeAcl(char *relname,
- AclItem *mod_aip,
- unsigned modechg)
+ChangeAcl(char *relname,
+ AclItem * mod_aip,
+ unsigned modechg)
{
- register unsigned i;
- Acl *old_acl = (Acl *) NULL, *new_acl;
- Relation relation;
- static ScanKeyData relkey[1] = {
- { 0, Anum_pg_class_relname, NameEqualRegProcedure }
- };
- HeapScanDesc hsdp;
- HeapTuple htp;
- Buffer buffer;
- Datum values[Natts_pg_class];
- char nulls[Natts_pg_class];
- char replaces[Natts_pg_class];
- ItemPointerData tmp_ipd;
- Relation idescs[Num_pg_class_indices];
- int free_old_acl = 0;
-
- /*
- * Find the pg_class tuple matching 'relname' and extract the ACL.
- * If there's no ACL, create a default using the pg_class.relowner
- * field.
- *
- * We can't use the syscache here, since we need to do a heap_replace
- * on the tuple we find. Feh.
- */
- relation = heap_openr(RelationRelationName);
- if (!RelationIsValid(relation))
- elog(WARN, "ChangeAcl: could not open '%s'??",
- RelationRelationName);
- fmgr_info(NameEqualRegProcedure, &relkey[0].sk_func, &relkey[0].sk_nargs);
- relkey[0].sk_argument = NameGetDatum(relname);
- hsdp = heap_beginscan(relation,
- 0,
- NowTimeQual,
- (unsigned) 1,
- relkey);
- htp = heap_getnext(hsdp, 0, &buffer);
- if (!HeapTupleIsValid(htp)) {
- heap_endscan(hsdp);
- heap_close(relation);
- elog(WARN, "ChangeAcl: class \"%s\" not found",
- relname);
- return;
- }
- if (!heap_attisnull(htp, Anum_pg_class_relacl))
- old_acl = (Acl *) heap_getattr(htp, buffer,
- Anum_pg_class_relacl,
- RelationGetTupleDescriptor(relation),
- (bool *) NULL);
- if (!old_acl || ACL_NUM(old_acl) < 1) {
+ register unsigned i;
+ Acl *old_acl = (Acl *) NULL,
+ *new_acl;
+ Relation relation;
+ static ScanKeyData relkey[1] = {
+ {0, Anum_pg_class_relname, NameEqualRegProcedure}
+ };
+ HeapScanDesc hsdp;
+ HeapTuple htp;
+ Buffer buffer;
+ Datum values[Natts_pg_class];
+ char nulls[Natts_pg_class];
+ char replaces[Natts_pg_class];
+ ItemPointerData tmp_ipd;
+ Relation idescs[Num_pg_class_indices];
+ int free_old_acl = 0;
+
+ /*
+ * Find the pg_class tuple matching 'relname' and extract the ACL. If
+ * there's no ACL, create a default using the pg_class.relowner field.
+ *
+ * We can't use the syscache here, since we need to do a heap_replace on
+ * the tuple we find. Feh.
+ */
+ relation = heap_openr(RelationRelationName);
+ if (!RelationIsValid(relation))
+ elog(WARN, "ChangeAcl: could not open '%s'??",
+ RelationRelationName);
+ fmgr_info(NameEqualRegProcedure, &relkey[0].sk_func, &relkey[0].sk_nargs);
+ relkey[0].sk_argument = NameGetDatum(relname);
+ hsdp = heap_beginscan(relation,
+ 0,
+ NowTimeQual,
+ (unsigned) 1,
+ relkey);
+ htp = heap_getnext(hsdp, 0, &buffer);
+ if (!HeapTupleIsValid(htp))
+ {
+ heap_endscan(hsdp);
+ heap_close(relation);
+ elog(WARN, "ChangeAcl: class \"%s\" not found",
+ relname);
+ return;
+ }
+ if (!heap_attisnull(htp, Anum_pg_class_relacl))
+ old_acl = (Acl *) heap_getattr(htp, buffer,
+ Anum_pg_class_relacl,
+ RelationGetTupleDescriptor(relation),
+ (bool *) NULL);
+ if (!old_acl || ACL_NUM(old_acl) < 1)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "ChangeAcl: using default ACL");
+ elog(DEBUG, "ChangeAcl: using default ACL");
#endif
-/* old_acl = acldefault(((Form_pg_class) GETSTRUCT(htp))->relowner); */
- old_acl = acldefault();
- free_old_acl = 1;
- }
+/* old_acl = acldefault(((Form_pg_class) GETSTRUCT(htp))->relowner); */
+ old_acl = acldefault();
+ free_old_acl = 1;
+ }
#ifdef ACLDEBUG_TRACE
- dumpacl(old_acl);
+ dumpacl(old_acl);
#endif
- new_acl = aclinsert3(old_acl, mod_aip, modechg);
+ new_acl = aclinsert3(old_acl, mod_aip, modechg);
#ifdef ACLDEBUG_TRACE
- dumpacl(new_acl);
+ dumpacl(new_acl);
#endif
- for (i = 0; i < Natts_pg_class; ++i) {
- replaces[i] = ' ';
- nulls[i] = ' '; /* ignored if replaces[i] == ' ' anyway */
- values[i] = (Datum)NULL;/* ignored if replaces[i] == ' ' anyway */
- }
- replaces[Anum_pg_class_relacl - 1] = 'r';
- values[Anum_pg_class_relacl - 1] = (Datum)new_acl;
- htp = heap_modifytuple(htp, buffer, relation, values, nulls, replaces);
- /* XXX is this necessary? */
- ItemPointerCopy(&htp->t_ctid, &tmp_ipd);
- /* XXX handle index on pg_class? */
- setheapoverride(true);
- heap_replace(relation, &tmp_ipd, htp);
- setheapoverride(false);
- heap_endscan(hsdp);
-
- /* keep the catalog indices up to date */
- CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
- idescs);
- CatalogIndexInsert(idescs, Num_pg_class_indices, relation, htp);
- CatalogCloseIndices(Num_pg_class_indices, idescs);
-
- heap_close(relation);
- if (free_old_acl)
- pfree(old_acl);
- pfree(new_acl);
+ for (i = 0; i < Natts_pg_class; ++i)
+ {
+ replaces[i] = ' ';
+ nulls[i] = ' '; /* ignored if replaces[i] == ' ' anyway */
+ values[i] = (Datum) NULL; /* ignored if replaces[i] == ' '
+ * anyway */
+ }
+ replaces[Anum_pg_class_relacl - 1] = 'r';
+ values[Anum_pg_class_relacl - 1] = (Datum) new_acl;
+ htp = heap_modifytuple(htp, buffer, relation, values, nulls, replaces);
+ /* XXX is this necessary? */
+ ItemPointerCopy(&htp->t_ctid, &tmp_ipd);
+ /* XXX handle index on pg_class? */
+ setheapoverride(true);
+ heap_replace(relation, &tmp_ipd, htp);
+ setheapoverride(false);
+ heap_endscan(hsdp);
+
+ /* keep the catalog indices up to date */
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
+ idescs);
+ CatalogIndexInsert(idescs, Num_pg_class_indices, relation, htp);
+ CatalogCloseIndices(Num_pg_class_indices, idescs);
+
+ heap_close(relation);
+ if (free_old_acl)
+ pfree(old_acl);
+ pfree(new_acl);
}
AclId
get_grosysid(char *groname)
{
- HeapTuple htp;
- AclId id = 0;
-
- htp = SearchSysCacheTuple(GRONAME, PointerGetDatum(groname),
- 0,0,0);
- if (HeapTupleIsValid(htp)) {
- id = ((Form_pg_group) GETSTRUCT(htp))->grosysid;
- } else {
- elog(WARN, "non-existent group \"%s\"", groname);
- }
- return(id);
+ HeapTuple htp;
+ AclId id = 0;
+
+ htp = SearchSysCacheTuple(GRONAME, PointerGetDatum(groname),
+ 0, 0, 0);
+ if (HeapTupleIsValid(htp))
+ {
+ id = ((Form_pg_group) GETSTRUCT(htp))->grosysid;
+ }
+ else
+ {
+ elog(WARN, "non-existent group \"%s\"", groname);
+ }
+ return (id);
}
-char*
+char *
get_groname(AclId grosysid)
{
- HeapTuple htp;
- char *name = NULL;
-
- htp = SearchSysCacheTuple(GROSYSID, PointerGetDatum(grosysid),
- 0,0,0);
- if (HeapTupleIsValid(htp)) {
- name = (((Form_pg_group) GETSTRUCT(htp))->groname).data;
- } else {
- elog(NOTICE, "get_groname: group %d not found", grosysid);
- }
- return(name);
+ HeapTuple htp;
+ char *name = NULL;
+
+ htp = SearchSysCacheTuple(GROSYSID, PointerGetDatum(grosysid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(htp))
+ {
+ name = (((Form_pg_group) GETSTRUCT(htp))->groname).data;
+ }
+ else
+ {
+ elog(NOTICE, "get_groname: group %d not found", grosysid);
+ }
+ return (name);
}
-static int32
+static int32
in_group(AclId uid, AclId gid)
{
- Relation relation;
- HeapTuple htp;
- Acl *tmp;
- unsigned i, num;
- AclId *aidp;
- int32 found = 0;
+ Relation relation;
+ HeapTuple htp;
+ Acl *tmp;
+ unsigned i,
+ num;
+ AclId *aidp;
+ int32 found = 0;
relation = heap_openr(GroupRelationName);
- if (!RelationIsValid(relation)) {
+ if (!RelationIsValid(relation))
+ {
elog(NOTICE, "in_group: could not open \"%s\"??",
- GroupRelationName);
- return(0);
+ GroupRelationName);
+ return (0);
}
htp = SearchSysCacheTuple(GROSYSID, ObjectIdGetDatum(gid),
- 0,0,0);
+ 0, 0, 0);
if (HeapTupleIsValid(htp) &&
- !heap_attisnull(htp, Anum_pg_group_grolist)) {
+ !heap_attisnull(htp, Anum_pg_group_grolist))
+ {
tmp = (IdList *) heap_getattr(htp, InvalidBuffer,
- Anum_pg_group_grolist,
- RelationGetTupleDescriptor(relation),
- (bool *) NULL);
+ Anum_pg_group_grolist,
+ RelationGetTupleDescriptor(relation),
+ (bool *) NULL);
/* XXX make me a function */
num = IDLIST_NUM(tmp);
aidp = IDLIST_DAT(tmp);
for (i = 0; i < num; ++i)
- if (aidp[i] == uid) {
+ if (aidp[i] == uid)
+ {
found = 1;
break;
}
- } else {
+ }
+ else
+ {
elog(NOTICE, "in_group: group %d not found", gid);
}
heap_close(relation);
- return(found);
+ return (found);
}
/*
@@ -259,348 +276,387 @@ in_group(AclId uid, AclId gid)
* Returns 1 if the 'id' of type 'idtype' has ACL entries in 'acl' to satisfy
* any one of the requirements of 'mode'. Returns 0 otherwise.
*/
-static int32
-aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
+static int32
+aclcheck(Acl * acl, AclId id, AclIdType idtype, AclMode mode)
{
- register unsigned i;
- register AclItem *aip, *aidat;
- unsigned num, found_group;
-
- /* if no acl is found, use world default */
- if (!acl) {
- acl = acldefault();
- }
-
- num = ACL_NUM(acl);
- aidat = ACL_DAT(acl);
-
- /*
- * We'll treat the empty ACL like that, too, although this is more
- * like an error (i.e., you manually blew away your ACL array) --
- * the system never creates an empty ACL.
- */
- if (num < 1) {
+ register unsigned i;
+ register AclItem *aip,
+ *aidat;
+ unsigned num,
+ found_group;
+
+ /* if no acl is found, use world default */
+ if (!acl)
+ {
+ acl = acldefault();
+ }
+
+ num = ACL_NUM(acl);
+ aidat = ACL_DAT(acl);
+
+ /*
+ * We'll treat the empty ACL like that, too, although this is more
+ * like an error (i.e., you manually blew away your ACL array) -- the
+ * system never creates an empty ACL.
+ */
+ if (num < 1)
+ {
#if ACLDEBUG_TRACE || 1
- elog(DEBUG, "aclcheck: zero-length ACL, returning 1");
+ elog(DEBUG, "aclcheck: zero-length ACL, returning 1");
#endif
- return ACLCHECK_OK;
- }
-
- switch (idtype) {
- case ACL_IDTYPE_UID:
- for (i = 1, aip = aidat + 1; /* skip world entry */
- i < num && aip->ai_idtype == ACL_IDTYPE_UID;
- ++i, ++aip) {
- if (aip->ai_id == id) {
+ return ACLCHECK_OK;
+ }
+
+ switch (idtype)
+ {
+ case ACL_IDTYPE_UID:
+ for (i = 1, aip = aidat + 1; /* skip world entry */
+ i < num && aip->ai_idtype == ACL_IDTYPE_UID;
+ ++i, ++aip)
+ {
+ if (aip->ai_id == id)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "aclcheck: found %d/%d",
- aip->ai_id, aip->ai_mode);
+ elog(DEBUG, "aclcheck: found %d/%d",
+ aip->ai_id, aip->ai_mode);
#endif
- return((aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
- }
- }
- for (found_group = 0;
- i < num && aip->ai_idtype == ACL_IDTYPE_GID;
- ++i, ++aip) {
- if (in_group(id, aip->ai_id)) {
- if (aip->ai_mode & mode) {
- found_group = 1;
- break;
+ return ((aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
+ }
}
- }
- }
- if (found_group) {
+ for (found_group = 0;
+ i < num && aip->ai_idtype == ACL_IDTYPE_GID;
+ ++i, ++aip)
+ {
+ if (in_group(id, aip->ai_id))
+ {
+ if (aip->ai_mode & mode)
+ {
+ found_group = 1;
+ break;
+ }
+ }
+ }
+ if (found_group)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG,"aclcheck: all groups ok");
+ elog(DEBUG, "aclcheck: all groups ok");
#endif
- return ACLCHECK_OK;
- }
- break;
- case ACL_IDTYPE_GID:
- for (i = 1, aip = aidat + 1; /* skip world entry and UIDs */
- i < num && aip->ai_idtype == ACL_IDTYPE_UID;
- ++i, ++aip)
- ;
- for (;
- i < num && aip->ai_idtype == ACL_IDTYPE_GID;
- ++i, ++aip) {
- if (aip->ai_id == id) {
+ return ACLCHECK_OK;
+ }
+ break;
+ case ACL_IDTYPE_GID:
+ for (i = 1, aip = aidat + 1; /* skip world entry and UIDs */
+ i < num && aip->ai_idtype == ACL_IDTYPE_UID;
+ ++i, ++aip)
+ ;
+ for (;
+ i < num && aip->ai_idtype == ACL_IDTYPE_GID;
+ ++i, ++aip)
+ {
+ if (aip->ai_id == id)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "aclcheck: found %d/%d",
- aip->ai_id, aip->ai_mode);
+ elog(DEBUG, "aclcheck: found %d/%d",
+ aip->ai_id, aip->ai_mode);
#endif
- return((aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
- }
+ return ((aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
+ }
+ }
+ break;
+ case ACL_IDTYPE_WORLD:
+ break;
+ default:
+ elog(WARN, "aclcheck: bogus ACL id type: %d", idtype);
+ break;
}
- break;
- case ACL_IDTYPE_WORLD:
- break;
- default:
- elog(WARN, "aclcheck: bogus ACL id type: %d", idtype);
- break;
- }
-
+
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode);
+ elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode);
#endif
- return((aidat->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
+ return ((aidat->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
}
int32
pg_aclcheck(char *relname, char *usename, AclMode mode)
{
- HeapTuple htp;
- AclId id;
- Acl *acl = (Acl *) NULL, *tmp;
- int32 result;
- Relation relation;
-
- htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
- 0,0,0);
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_aclcheck: user \"%s\" not found",
- usename);
- id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
-
- /* for the 'pg_database' relation, check the usecreatedb
- field before checking normal permissions */
- if ( strcmp(DatabaseRelationName, relname) == 0 &&
- (((Form_pg_user) GETSTRUCT(htp))->usecreatedb)) {
- /* note that even though the user can now append to the
- pg_database table, there is still additional permissions checking
- in dbcommands.c */
- if (mode & ACL_AP)
- return ACLCHECK_OK;
- }
-
- /*
- * Deny anyone permission to update a system catalog unless
- * pg_user.usecatupd is set. (This is to let superusers protect
- * themselves from themselves.)
- */
- if (((mode & ACL_WR) || (mode & ACL_AP)) &&
- IsSystemRelationName(relname) &&
- !((Form_pg_user) GETSTRUCT(htp))->usecatupd) {
- elog(DEBUG, "pg_aclcheck: catalog update to \"%s\": permission denied",
- relname);
- return ACLCHECK_NO_PRIV;
- }
-
- /*
- * Otherwise, superusers bypass all permission-checking.
- */
- if (((Form_pg_user) GETSTRUCT(htp))->usesuper) {
+ HeapTuple htp;
+ AclId id;
+ Acl *acl = (Acl *) NULL,
+ *tmp;
+ int32 result;
+ Relation relation;
+
+ htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_aclcheck: user \"%s\" not found",
+ usename);
+ id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
+
+ /*
+ * for the 'pg_database' relation, check the usecreatedb field before
+ * checking normal permissions
+ */
+ if (strcmp(DatabaseRelationName, relname) == 0 &&
+ (((Form_pg_user) GETSTRUCT(htp))->usecreatedb))
+ {
+
+ /*
+ * note that even though the user can now append to the
+ * pg_database table, there is still additional permissions
+ * checking in dbcommands.c
+ */
+ if (mode & ACL_AP)
+ return ACLCHECK_OK;
+ }
+
+ /*
+ * Deny anyone permission to update a system catalog unless
+ * pg_user.usecatupd is set. (This is to let superusers protect
+ * themselves from themselves.)
+ */
+ if (((mode & ACL_WR) || (mode & ACL_AP)) &&
+ IsSystemRelationName(relname) &&
+ !((Form_pg_user) GETSTRUCT(htp))->usecatupd)
+ {
+ elog(DEBUG, "pg_aclcheck: catalog update to \"%s\": permission denied",
+ relname);
+ return ACLCHECK_NO_PRIV;
+ }
+
+ /*
+ * Otherwise, superusers bypass all permission-checking.
+ */
+ if (((Form_pg_user) GETSTRUCT(htp))->usesuper)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "pg_aclcheck: \"%s\" is superuser",
- usename);
+ elog(DEBUG, "pg_aclcheck: \"%s\" is superuser",
+ usename);
#endif
- return ACLCHECK_OK;
- }
-
-#ifndef ACLDEBUG
- htp = SearchSysCacheTuple(RELNAME, PointerGetDatum(relname),
- 0,0,0);
- if (!HeapTupleIsValid(htp)) {
- elog(WARN, "pg_aclcheck: class \"%s\" not found",
- relname);
- /* an elog(WARN) kills us, so no need to return anything. */
- }
- if (!heap_attisnull(htp, Anum_pg_class_relacl)) {
- relation = heap_openr(RelationRelationName);
- tmp = (Acl *) heap_getattr(htp, InvalidBuffer,
- Anum_pg_class_relacl,
- RelationGetTupleDescriptor(relation),
- (bool *) NULL);
- acl = makeacl(ACL_NUM(tmp));
- memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
- heap_close(relation);
- } else {
- /* if the acl is null, by default the owner can do whatever
- he wants to with it */
- Oid ownerId;
- relation = heap_openr(RelationRelationName);
- ownerId = (Oid)heap_getattr(htp, InvalidBuffer,
- Anum_pg_class_relowner,
- RelationGetTupleDescriptor(relation),
- (bool*) NULL);
- acl = aclownerdefault(ownerId);
- }
-#else
- { /* This is why the syscache is great... */
- static ScanKeyData relkey[1] = {
- { 0, Anum_pg_class_relname, NameEqualRegProcedure }
- };
- HeapScanDesc hsdp;
+ return ACLCHECK_OK;
+ }
- relation = heap_openr(RelationRelationName);
- if (!RelationIsValid(relation)) {
- elog(NOTICE, "pg_checkacl: could not open \"%-.*s\"??",
- RelationRelationName);
- return ACLCHECK_NO_CLASS;
+#ifndef ACLDEBUG
+ htp = SearchSysCacheTuple(RELNAME, PointerGetDatum(relname),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ {
+ elog(WARN, "pg_aclcheck: class \"%s\" not found",
+ relname);
+ /* an elog(WARN) kills us, so no need to return anything. */
}
- fmgr_info(NameEqualRegProcedure,
- &relkey[0].sk_func,
- &relkey[0].sk_nargs);
- relkey[0].sk_argument = NameGetDatum(relname);
- hsdp = heap_beginscan(relation, 0, NowTimeQual, 1, relkey);
- htp = heap_getnext(hsdp, 0, (Buffer *) 0);
- if (HeapTupleIsValid(htp) &&
- !heap_attisnull(htp, Anum_pg_class_relacl)) {
- tmp = (Acl *) heap_getattr(htp, InvalidBuffer,
- Anum_pg_class_relacl,
- RelationGetTupleDescriptor(relation),
- (bool *) NULL);
- acl = makeacl(ACL_NUM(tmp));
- memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
+ if (!heap_attisnull(htp, Anum_pg_class_relacl))
+ {
+ relation = heap_openr(RelationRelationName);
+ tmp = (Acl *) heap_getattr(htp, InvalidBuffer,
+ Anum_pg_class_relacl,
+ RelationGetTupleDescriptor(relation),
+ (bool *) NULL);
+ acl = makeacl(ACL_NUM(tmp));
+ memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
+ heap_close(relation);
+ }
+ else
+ {
+
+ /*
+ * if the acl is null, by default the owner can do whatever he
+ * wants to with it
+ */
+ Oid ownerId;
+
+ relation = heap_openr(RelationRelationName);
+ ownerId = (Oid) heap_getattr(htp, InvalidBuffer,
+ Anum_pg_class_relowner,
+ RelationGetTupleDescriptor(relation),
+ (bool *) NULL);
+ acl = aclownerdefault(ownerId);
+ }
+#else
+ { /* This is why the syscache is great... */
+ static ScanKeyData relkey[1] = {
+ {0, Anum_pg_class_relname, NameEqualRegProcedure}
+ };
+ HeapScanDesc hsdp;
+
+ relation = heap_openr(RelationRelationName);
+ if (!RelationIsValid(relation))
+ {
+ elog(NOTICE, "pg_checkacl: could not open \"%-.*s\"??",
+ RelationRelationName);
+ return ACLCHECK_NO_CLASS;
+ }
+ fmgr_info(NameEqualRegProcedure,
+ &relkey[0].sk_func,
+ &relkey[0].sk_nargs);
+ relkey[0].sk_argument = NameGetDatum(relname);
+ hsdp = heap_beginscan(relation, 0, NowTimeQual, 1, relkey);
+ htp = heap_getnext(hsdp, 0, (Buffer *) 0);
+ if (HeapTupleIsValid(htp) &&
+ !heap_attisnull(htp, Anum_pg_class_relacl))
+ {
+ tmp = (Acl *) heap_getattr(htp, InvalidBuffer,
+ Anum_pg_class_relacl,
+ RelationGetTupleDescriptor(relation),
+ (bool *) NULL);
+ acl = makeacl(ACL_NUM(tmp));
+ memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
+ }
+ heap_endscan(hsdp);
+ heap_close(relation);
}
- heap_endscan(hsdp);
- heap_close(relation);
- }
#endif
- result = aclcheck(acl, id, (AclIdType) ACL_IDTYPE_UID, mode);
- if (acl)
- pfree(acl);
- return(result);
+ result = aclcheck(acl, id, (AclIdType) ACL_IDTYPE_UID, mode);
+ if (acl)
+ pfree(acl);
+ return (result);
}
int32
pg_ownercheck(char *usename,
- char *value,
- int cacheid)
+ char *value,
+ int cacheid)
{
- HeapTuple htp;
- AclId user_id, owner_id = 0;
-
- htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
- 0,0,0);
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_ownercheck: user \"%s\" not found",
- usename);
- user_id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
-
- /*
- * Superusers bypass all permission-checking.
- */
- if (((Form_pg_user) GETSTRUCT(htp))->usesuper) {
+ HeapTuple htp;
+ AclId user_id,
+ owner_id = 0;
+
+ htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_ownercheck: user \"%s\" not found",
+ usename);
+ user_id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
+
+ /*
+ * Superusers bypass all permission-checking.
+ */
+ if (((Form_pg_user) GETSTRUCT(htp))->usesuper)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
- usename);
+ elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
+ usename);
#endif
- return(1);
- }
+ return (1);
+ }
- htp = SearchSysCacheTuple(cacheid, PointerGetDatum(value),
- 0,0,0);
- switch (cacheid) {
- case OPROID:
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_ownercheck: operator %ld not found",
- PointerGetDatum(value));
- owner_id = ((OperatorTupleForm) GETSTRUCT(htp))->oprowner;
- break;
- case PRONAME:
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_ownercheck: function \"%s\" not found",
- value);
- owner_id = ((Form_pg_proc) GETSTRUCT(htp))->proowner;
- break;
- case RELNAME:
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_ownercheck: class \"%s\" not found",
- value);
- owner_id = ((Form_pg_class) GETSTRUCT(htp))->relowner;
- break;
- case TYPNAME:
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_ownercheck: type \"%s\" not found",
- value);
- owner_id = ((TypeTupleForm) GETSTRUCT(htp))->typowner;
- break;
- default:
- elog(WARN, "pg_ownercheck: invalid cache id: %d",
- cacheid);
- break;
- }
-
- return(user_id == owner_id);
+ htp = SearchSysCacheTuple(cacheid, PointerGetDatum(value),
+ 0, 0, 0);
+ switch (cacheid)
+ {
+ case OPROID:
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_ownercheck: operator %ld not found",
+ PointerGetDatum(value));
+ owner_id = ((OperatorTupleForm) GETSTRUCT(htp))->oprowner;
+ break;
+ case PRONAME:
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_ownercheck: function \"%s\" not found",
+ value);
+ owner_id = ((Form_pg_proc) GETSTRUCT(htp))->proowner;
+ break;
+ case RELNAME:
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_ownercheck: class \"%s\" not found",
+ value);
+ owner_id = ((Form_pg_class) GETSTRUCT(htp))->relowner;
+ break;
+ case TYPNAME:
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_ownercheck: type \"%s\" not found",
+ value);
+ owner_id = ((TypeTupleForm) GETSTRUCT(htp))->typowner;
+ break;
+ default:
+ elog(WARN, "pg_ownercheck: invalid cache id: %d",
+ cacheid);
+ break;
+ }
+
+ return (user_id == owner_id);
}
int32
-pg_func_ownercheck(char *usename,
- char *funcname,
- int nargs,
- Oid *arglist)
+pg_func_ownercheck(char *usename,
+ char *funcname,
+ int nargs,
+ Oid * arglist)
{
- HeapTuple htp;
- AclId user_id, owner_id;
-
- htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
- 0,0,0);
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_func_ownercheck: user \"%s\" not found",
- usename);
- user_id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
-
- /*
- * Superusers bypass all permission-checking.
- */
- if (((Form_pg_user) GETSTRUCT(htp))->usesuper) {
+ HeapTuple htp;
+ AclId user_id,
+ owner_id;
+
+ htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_func_ownercheck: user \"%s\" not found",
+ usename);
+ user_id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
+
+ /*
+ * Superusers bypass all permission-checking.
+ */
+ if (((Form_pg_user) GETSTRUCT(htp))->usesuper)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
- usename);
+ elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
+ usename);
#endif
- return(1);
- }
-
- htp = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(funcname),
- PointerGetDatum(nargs),
- PointerGetDatum(arglist),
- 0);
- if (!HeapTupleIsValid(htp))
- func_error("pg_func_ownercheck", funcname, nargs, arglist);
-
- owner_id = ((Form_pg_proc) GETSTRUCT(htp))->proowner;
-
- return(user_id == owner_id);
+ return (1);
+ }
+
+ htp = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(funcname),
+ PointerGetDatum(nargs),
+ PointerGetDatum(arglist),
+ 0);
+ if (!HeapTupleIsValid(htp))
+ func_error("pg_func_ownercheck", funcname, nargs, arglist);
+
+ owner_id = ((Form_pg_proc) GETSTRUCT(htp))->proowner;
+
+ return (user_id == owner_id);
}
int32
-pg_aggr_ownercheck(char *usename,
- char *aggname,
- Oid basetypeID)
+pg_aggr_ownercheck(char *usename,
+ char *aggname,
+ Oid basetypeID)
{
- HeapTuple htp;
- AclId user_id, owner_id;
-
- htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
- 0,0,0);
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_aggr_ownercheck: user \"%s\" not found",
- usename);
- user_id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
-
- /*
- * Superusers bypass all permission-checking.
- */
- if (((Form_pg_user) GETSTRUCT(htp))->usesuper) {
+ HeapTuple htp;
+ AclId user_id,
+ owner_id;
+
+ htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_aggr_ownercheck: user \"%s\" not found",
+ usename);
+ user_id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
+
+ /*
+ * Superusers bypass all permission-checking.
+ */
+ if (((Form_pg_user) GETSTRUCT(htp))->usesuper)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "pg_aggr_ownercheck: user \"%s\" is superuser",
- usename);
+ elog(DEBUG, "pg_aggr_ownercheck: user \"%s\" is superuser",
+ usename);
#endif
- return(1);
- }
+ return (1);
+ }
- htp = SearchSysCacheTuple(AGGNAME,
- PointerGetDatum(aggname),
- PointerGetDatum(basetypeID),
- 0,
- 0);
+ htp = SearchSysCacheTuple(AGGNAME,
+ PointerGetDatum(aggname),
+ PointerGetDatum(basetypeID),
+ 0,
+ 0);
+
+ if (!HeapTupleIsValid(htp))
+ agg_error("pg_aggr_ownercheck", aggname, basetypeID);
- if (!HeapTupleIsValid(htp))
- agg_error("pg_aggr_ownercheck", aggname, basetypeID);
+ owner_id = ((Form_pg_aggregate) GETSTRUCT(htp))->aggowner;
- owner_id = ((Form_pg_aggregate) GETSTRUCT(htp))->aggowner;
-
- return(user_id == owner_id);
+ return (user_id == owner_id);
}
diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c
index ea1548cd3de..1c0306b18d9 100644
--- a/src/backend/tcop/dest.c
+++ b/src/backend/tcop/dest.c
@@ -1,29 +1,29 @@
/*-------------------------------------------------------------------------
*
* dest.c--
- * support for various communication destinations - see lib/H/tcop/dest.h
+ * support for various communication destinations - see lib/H/tcop/dest.h
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.10 1997/08/29 09:04:18 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.11 1997/09/07 04:49:31 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * INTERFACE ROUTINES
- * BeginCommand - prepare destination for tuples of the given type
- * EndCommand - tell destination that no more tuples will arrive
- * NullCommand - tell dest that the last of a query sequence was processed
- *
- * NOTES
- * These routines do the appropriate work before and after
- * tuples are returned by a query to keep the backend and the
- * "destination" portals synchronized.
+ * INTERFACE ROUTINES
+ * BeginCommand - prepare destination for tuples of the given type
+ * EndCommand - tell destination that no more tuples will arrive
+ * NullCommand - tell dest that the last of a query sequence was processed
+ *
+ * NOTES
+ * These routines do the appropriate work before and after
+ * tuples are returned by a query to keep the backend and the
+ * "destination" portals synchronized.
*
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include "postgres.h"
@@ -43,10 +43,10 @@
#include "commands/async.h"
-static char CommandInfo[32] = {0};
+static char CommandInfo[32] = {0};
/* ----------------
- * output functions
+ * output functions
* ----------------
*/
static void
@@ -54,85 +54,88 @@ donothing(HeapTuple tuple, TupleDesc attrdesc)
{
}
-extern void spi_printtup (HeapTuple tuple, TupleDesc tupdesc);
+extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc);
-void (*DestToFunction(CommandDest dest))(HeapTuple, TupleDesc)
+void (*
+ DestToFunction(CommandDest dest)) (HeapTuple, TupleDesc)
{
- switch (dest) {
- case RemoteInternal:
- return printtup_internal;
- break;
-
- case Remote:
- return printtup;
- break;
-
- case Local:
- return be_printtup;
- break;
-
- case Debug:
- return debugtup;
- break;
-
- case SPI:
- return spi_printtup;
- break;
-
- case None:
- default:
+ switch (dest)
+ {
+ case RemoteInternal:
+ return printtup_internal;
+ break;
+
+ case Remote:
+ return printtup;
+ break;
+
+ case Local:
+ return be_printtup;
+ break;
+
+ case Debug:
+ return debugtup;
+ break;
+
+ case SPI:
+ return spi_printtup;
+ break;
+
+ case None:
+ default:
+ return donothing;
+ break;
+ }
+
+ /*
+ * never gets here, but DECstation lint appears to be stupid...
+ */
+
return donothing;
- break;
- }
-
- /*
- * never gets here, but DECstation lint appears to be stupid...
- */
-
- return donothing;
}
/* ----------------
- * EndCommand - tell destination that no more tuples will arrive
+ * EndCommand - tell destination that no more tuples will arrive
* ----------------
*/
void
EndCommand(char *commandTag, CommandDest dest)
{
- char buf[64];
-
- switch (dest) {
- case RemoteInternal:
- case Remote:
- /* ----------------
- * tell the fe that the query is over
- * ----------------
- */
- pq_putnchar("C", 1);
- sprintf(buf, "%s%s", commandTag, CommandInfo);
- CommandInfo[0] = 0;
- pq_putstr(buf);
- pq_flush();
- break;
-
- case Local:
- case Debug:
- break;
- case CopyEnd:
- pq_putnchar("Z", 1);
- pq_flush();
- break;
- case None:
- default:
- break;
- }
+ char buf[64];
+
+ switch (dest)
+ {
+ case RemoteInternal:
+ case Remote:
+ /* ----------------
+ * tell the fe that the query is over
+ * ----------------
+ */
+ pq_putnchar("C", 1);
+ sprintf(buf, "%s%s", commandTag, CommandInfo);
+ CommandInfo[0] = 0;
+ pq_putstr(buf);
+ pq_flush();
+ break;
+
+ case Local:
+ case Debug:
+ break;
+ case CopyEnd:
+ pq_putnchar("Z", 1);
+ pq_flush();
+ break;
+ case None:
+ default:
+ break;
+ }
}
/*
* These are necessary to sync communications between fe/be processes doing
* COPY rel TO stdout
- *
- * or
+ *
+ * or
*
* COPY rel FROM stdin
*
@@ -140,198 +143,211 @@ EndCommand(char *commandTag, CommandDest dest)
void
SendCopyBegin(void)
{
- pq_putnchar("B", 1);
-/* pq_putint(0, 4); */
- pq_flush();
+ pq_putnchar("B", 1);
+/* pq_putint(0, 4); */
+ pq_flush();
}
void
ReceiveCopyBegin(void)
{
- pq_putnchar("D", 1);
-/* pq_putint(0, 4); */
- pq_flush();
+ pq_putnchar("D", 1);
+/* pq_putint(0, 4); */
+ pq_flush();
}
/* ----------------
- * NullCommand - tell dest that the last of a query sequence was processed
- *
- * Necessary to implement the hacky FE/BE interface to handle
- * multiple-return queries.
+ * NullCommand - tell dest that the last of a query sequence was processed
+ *
+ * Necessary to implement the hacky FE/BE interface to handle
+ * multiple-return queries.
* ----------------
*/
void
NullCommand(CommandDest dest)
{
- switch (dest) {
- case RemoteInternal:
- case Remote: {
+ switch (dest)
+ {
+ case RemoteInternal:
+ case Remote:
+ {
#if 0
- /* Do any asynchronous notification. If front end wants to poll,
- it can send null queries to call this function.
- */
- PQNotifyList *nPtr;
- MemoryContext orig;
-
- if (notifyContext == NULL) {
- notifyContext = CreateGlobalMemory("notify");
- }
- orig = MemoryContextSwitchTo((MemoryContext)notifyContext);
-
- for (nPtr = PQnotifies() ;
- nPtr != NULL;
- nPtr = (PQNotifyList *)SLGetSucc(&nPtr->Node)) {
- pq_putnchar("A",1);
- pq_putint(0, 4);
- pq_putstr(nPtr->relname);
- pq_putint(nPtr->be_pid,4);
- PQremoveNotify(nPtr);
- }
- pq_flush();
- PQcleanNotify(); /* garbage collect */
- MemoryContextSwitchTo(orig);
+
+ /*
+ * Do any asynchronous notification. If front end wants to
+ * poll, it can send null queries to call this function.
+ */
+ PQNotifyList *nPtr;
+ MemoryContext orig;
+
+ if (notifyContext == NULL)
+ {
+ notifyContext = CreateGlobalMemory("notify");
+ }
+ orig = MemoryContextSwitchTo((MemoryContext) notifyContext);
+
+ for (nPtr = PQnotifies();
+ nPtr != NULL;
+ nPtr = (PQNotifyList *) SLGetSucc(&nPtr->Node))
+ {
+ pq_putnchar("A", 1);
+ pq_putint(0, 4);
+ pq_putstr(nPtr->relname);
+ pq_putint(nPtr->be_pid, 4);
+ PQremoveNotify(nPtr);
+ }
+ pq_flush();
+ PQcleanNotify(); /* garbage collect */
+ MemoryContextSwitchTo(orig);
#endif
- /* ----------------
- * tell the fe that the last of the queries has finished
- * ----------------
- */
-/* pq_putnchar("I", 1); */
- pq_putstr("I");
- /* pq_putint(0, 4);*/
- pq_flush();
- }
- break;
-
- case Local:
- case Debug:
- case None:
- default:
- break;
- }
+ /* ----------------
+ * tell the fe that the last of the queries has finished
+ * ----------------
+ */
+/* pq_putnchar("I", 1); */
+ pq_putstr("I");
+ /* pq_putint(0, 4); */
+ pq_flush();
+ }
+ break;
+
+ case Local:
+ case Debug:
+ case None:
+ default:
+ break;
+ }
}
/* ----------------
- * BeginCommand - prepare destination for tuples of the given type
+ * BeginCommand - prepare destination for tuples of the given type
* ----------------
*/
void
BeginCommand(char *pname,
- int operation,
- TupleDesc tupdesc,
- bool isIntoRel,
- bool isIntoPortal,
- char *tag,
- CommandDest dest)
+ int operation,
+ TupleDesc tupdesc,
+ bool isIntoRel,
+ bool isIntoPortal,
+ char *tag,
+ CommandDest dest)
{
- PortalEntry *entry;
- AttributeTupleForm *attrs = tupdesc->attrs;
- int natts = tupdesc->natts;
- int i;
- char *p;
-
- switch (dest) {
- case RemoteInternal:
- case Remote:
- /* ----------------
- * if this is a "retrieve portal" query, just return
- * because nothing needs to be sent to the fe.
- * ----------------
- */
- CommandInfo[0] = 0;
- if (isIntoPortal)
- return;
-
- /* ----------------
- * if portal name not specified for remote query,
- * use the "blank" portal.
- * ----------------
- */
- if (pname == NULL)
- pname = "blank";
-
- /* ----------------
- * send fe info on tuples we're about to send
- * ----------------
- */
- pq_flush();
- pq_putnchar("P", 1); /* new portal.. */
- pq_putstr(pname); /* portal name */
-
- /* ----------------
- * if this is a retrieve, then we send back the tuple
- * descriptor of the tuples. "retrieve into" is an
- * exception because no tuples are returned in that case.
- * ----------------
- */
- if (operation == CMD_SELECT && !isIntoRel) {
- pq_putnchar("T", 1); /* type info to follow.. */
- pq_putint(natts, 2); /* number of attributes in tuples */
-
- for (i = 0; i < natts; ++i) {
- pq_putstr(attrs[i]->attname.data);/* if 16 char name oops.. */
- pq_putint((int) attrs[i]->atttypid, 4);
- pq_putint(attrs[i]->attlen, 2);
- }
- }
- pq_flush();
- break;
-
- case Local:
- /* ----------------
- * prepare local portal buffer for query results
- * and setup result for PQexec()
- * ----------------
- */
- entry = be_currentportal();
- if (pname != NULL)
- pbuf_setportalinfo(entry, pname);
-
- if (operation == CMD_SELECT && !isIntoRel) {
- be_typeinit(entry, tupdesc, natts);
- p = (char *) palloc(strlen(entry->name)+2);
- p[0] = 'P';
- strcpy(p+1,entry->name);
- } else {
- p = (char *) palloc(strlen(tag)+2);
- p[0] = 'C';
- strcpy(p+1,tag);
+ PortalEntry *entry;
+ AttributeTupleForm *attrs = tupdesc->attrs;
+ int natts = tupdesc->natts;
+ int i;
+ char *p;
+
+ switch (dest)
+ {
+ case RemoteInternal:
+ case Remote:
+ /* ----------------
+ * if this is a "retrieve portal" query, just return
+ * because nothing needs to be sent to the fe.
+ * ----------------
+ */
+ CommandInfo[0] = 0;
+ if (isIntoPortal)
+ return;
+
+ /* ----------------
+ * if portal name not specified for remote query,
+ * use the "blank" portal.
+ * ----------------
+ */
+ if (pname == NULL)
+ pname = "blank";
+
+ /* ----------------
+ * send fe info on tuples we're about to send
+ * ----------------
+ */
+ pq_flush();
+ pq_putnchar("P", 1); /* new portal.. */
+ pq_putstr(pname); /* portal name */
+
+ /* ----------------
+ * if this is a retrieve, then we send back the tuple
+ * descriptor of the tuples. "retrieve into" is an
+ * exception because no tuples are returned in that case.
+ * ----------------
+ */
+ if (operation == CMD_SELECT && !isIntoRel)
+ {
+ pq_putnchar("T", 1);/* type info to follow.. */
+ pq_putint(natts, 2);/* number of attributes in tuples */
+
+ for (i = 0; i < natts; ++i)
+ {
+ pq_putstr(attrs[i]->attname.data); /* if 16 char name
+ * oops.. */
+ pq_putint((int) attrs[i]->atttypid, 4);
+ pq_putint(attrs[i]->attlen, 2);
+ }
+ }
+ pq_flush();
+ break;
+
+ case Local:
+ /* ----------------
+ * prepare local portal buffer for query results
+ * and setup result for PQexec()
+ * ----------------
+ */
+ entry = be_currentportal();
+ if (pname != NULL)
+ pbuf_setportalinfo(entry, pname);
+
+ if (operation == CMD_SELECT && !isIntoRel)
+ {
+ be_typeinit(entry, tupdesc, natts);
+ p = (char *) palloc(strlen(entry->name) + 2);
+ p[0] = 'P';
+ strcpy(p + 1, entry->name);
+ }
+ else
+ {
+ p = (char *) palloc(strlen(tag) + 2);
+ p[0] = 'C';
+ strcpy(p + 1, tag);
+ }
+ entry->result = p;
+ break;
+
+ case Debug:
+ /* ----------------
+ * show the return type of the tuples
+ * ----------------
+ */
+ if (pname == NULL)
+ pname = "blank";
+
+ showatts(pname, tupdesc);
+ break;
+
+ case None:
+ default:
+ break;
}
- entry->result = p;
- break;
-
- case Debug:
- /* ----------------
- * show the return type of the tuples
- * ----------------
- */
- if (pname == NULL)
- pname = "blank";
-
- showatts(pname, tupdesc);
- break;
-
- case None:
- default:
- break;
- }
}
void
-UpdateCommandInfo (int operation, Oid lastoid, uint32 tuples)
+UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples)
{
- switch (operation)
- {
- case CMD_INSERT :
- if ( tuples > 1 )
- lastoid = InvalidOid;
- sprintf (CommandInfo, " %u %u", lastoid, tuples);
- break;
- case CMD_DELETE :
- case CMD_UPDATE :
- sprintf (CommandInfo, " %u", tuples);
- break;
- default :
- CommandInfo[0] = 0;
- }
- return;
+ switch (operation)
+ {
+ case CMD_INSERT:
+ if (tuples > 1)
+ lastoid = InvalidOid;
+ sprintf(CommandInfo, " %u %u", lastoid, tuples);
+ break;
+ case CMD_DELETE:
+ case CMD_UPDATE:
+ sprintf(CommandInfo, " %u", tuples);
+ break;
+ default:
+ CommandInfo[0] = 0;
+ }
+ return;
}
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index 20951fa4cb0..27c01ff1a17 100644
--- a/src/backend/tcop/fastpath.c
+++ b/src/backend/tcop/fastpath.c
@@ -1,59 +1,59 @@
/*-------------------------------------------------------------------------
*
* fastpath.c--
- * routines to handle function requests from the frontend
+ * routines to handle function requests from the frontend
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.4 1997/03/12 21:07:50 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.5 1997/09/07 04:49:32 momjian Exp $
*
* NOTES
- * This cruft is the server side of PQfn.
+ * This cruft is the server side of PQfn.
*
- * - jolly 07/11/95:
+ * - jolly 07/11/95:
*
- * no longer rely on return sizes provided by the frontend. Always
- * use the true lengths for the catalogs. Assume that the frontend
- * has allocated enough space to handle the result value returned.
- *
- * trust that the user knows what he is doing with the args. If the
- * sys catalog says it is a varlena, assume that the user is only sending
- * down VARDATA and that the argsize is the VARSIZE. If the arg is
- * fixed len, assume that the argsize given by the user is correct.
- *
- * if the function returns by value, then only send 4 bytes value
- * back to the frontend. If the return returns by reference,
- * send down only the data portion and set the return size appropriately.
- *
- * OLD COMMENTS FOLLOW
+ * no longer rely on return sizes provided by the frontend. Always
+ * use the true lengths for the catalogs. Assume that the frontend
+ * has allocated enough space to handle the result value returned.
*
- * The VAR_LENGTH_{ARGS,RESULT} stuff is limited to MAX_STRING_LENGTH
- * (see src/backend/tmp/fastpath.h) for no obvious reason. Since its
- * primary use (for us) is for Inversion path names, it should probably
- * be increased to 256 (MAXPATHLEN for Inversion, hidden in pg_type
- * as well as utils/adt/filename.c).
+ * trust that the user knows what he is doing with the args. If the
+ * sys catalog says it is a varlena, assume that the user is only sending
+ * down VARDATA and that the argsize is the VARSIZE. If the arg is
+ * fixed len, assume that the argsize given by the user is correct.
*
- * Quoth PMA on 08/15/93:
+ * if the function returns by value, then only send 4 bytes value
+ * back to the frontend. If the return returns by reference,
+ * send down only the data portion and set the return size appropriately.
*
- * This code has been almost completely rewritten with an eye to
- * keeping it as compatible as possible with the previous (broken)
- * implementation.
+ * OLD COMMENTS FOLLOW
*
- * The previous implementation would assume (1) that any value of
- * length <= 4 bytes was passed-by-value, and that any other value
- * was a struct varlena (by-reference). There was NO way to pass a
- * fixed-length by-reference argument (like char16) or a struct
- * varlena of size <= 4 bytes.
- *
- * The new implementation checks the catalogs to determine whether
- * a value is by-value (type "0" is null-delimited character string,
- * as it is for, e.g., the parser). The only other item obtained
- * from the catalogs is whether or not the value should be placed in
- * a struct varlena or not. Otherwise, the size given by the
- * frontend is assumed to be correct (probably a bad decision, but
- * we do strange things in the name of compatibility).
+ * The VAR_LENGTH_{ARGS,RESULT} stuff is limited to MAX_STRING_LENGTH
+ * (see src/backend/tmp/fastpath.h) for no obvious reason. Since its
+ * primary use (for us) is for Inversion path names, it should probably
+ * be increased to 256 (MAXPATHLEN for Inversion, hidden in pg_type
+ * as well as utils/adt/filename.c).
+ *
+ * Quoth PMA on 08/15/93:
+ *
+ * This code has been almost completely rewritten with an eye to
+ * keeping it as compatible as possible with the previous (broken)
+ * implementation.
+ *
+ * The previous implementation would assume (1) that any value of
+ * length <= 4 bytes was passed-by-value, and that any other value
+ * was a struct varlena (by-reference). There was NO way to pass a
+ * fixed-length by-reference argument (like char16) or a struct
+ * varlena of size <= 4 bytes.
+ *
+ * The new implementation checks the catalogs to determine whether
+ * a value is by-value (type "0" is null-delimited character string,
+ * as it is for, e.g., the parser). The only other item obtained
+ * from the catalogs is whether or not the value should be placed in
+ * a struct varlena or not. Otherwise, the size given by the
+ * frontend is assumed to be correct (probably a bad decision, but
+ * we do strange things in the name of compatibility).
*
*-------------------------------------------------------------------------
*/
@@ -65,11 +65,11 @@
#include "utils/palloc.h"
#include "fmgr.h"
-#include "utils/builtins.h" /* for oideq */
+#include "utils/builtins.h" /* for oideq */
#include "tcop/fastpath.h"
#include "libpq/libpq.h"
-#include "access/xact.h" /* for TransactionId/CommandId protos */
+#include "access/xact.h" /* for TransactionId/CommandId protos */
#include "utils/syscache.h"
#include "catalog/pg_proc.h"
@@ -77,90 +77,98 @@
/* ----------------
- * SendFunctionResult
+ * SendFunctionResult
* ----------------
*/
static void
-SendFunctionResult(Oid fid, /* function id */
- char *retval, /* actual return value */
- bool retbyval,
- int retlen /* the length according to the catalogs */
- )
+SendFunctionResult(Oid fid, /* function id */
+ char *retval,/* actual return value */
+ bool retbyval,
+ int retlen /* the length according to the catalogs */
+)
{
- pq_putnchar("V", 1);
-
- if (retlen != 0) {
- pq_putnchar("G", 1);
- if (retbyval) { /* by-value */
- pq_putint(retlen, 4);
- pq_putint((int)(Datum)retval, retlen);
- } else { /* by-reference ... */
- if (retlen < 0) { /* ... varlena */
- pq_putint(VARSIZE(retval) - VARHDRSZ, 4);
- pq_putnchar(VARDATA(retval), VARSIZE(retval) - VARHDRSZ);
- } else { /* ... fixed */
- pq_putint(retlen, 4);
- pq_putnchar(retval, retlen);
- }
+ pq_putnchar("V", 1);
+
+ if (retlen != 0)
+ {
+ pq_putnchar("G", 1);
+ if (retbyval)
+ { /* by-value */
+ pq_putint(retlen, 4);
+ pq_putint((int) (Datum) retval, retlen);
+ }
+ else
+ { /* by-reference ... */
+ if (retlen < 0)
+ { /* ... varlena */
+ pq_putint(VARSIZE(retval) - VARHDRSZ, 4);
+ pq_putnchar(VARDATA(retval), VARSIZE(retval) - VARHDRSZ);
+ }
+ else
+ { /* ... fixed */
+ pq_putint(retlen, 4);
+ pq_putnchar(retval, retlen);
+ }
+ }
}
- }
- pq_putnchar("0", 1);
- pq_flush();
+ pq_putnchar("0", 1);
+ pq_flush();
}
/*
* This structure saves enough state so that one can avoid having to
- * do catalog lookups over and over again. (Each RPC can require up
+ * do catalog lookups over and over again. (Each RPC can require up
* to MAXFMGRARGS+2 lookups, which is quite tedious.)
*
* The previous incarnation of this code just assumed that any argument
- * of size <= 4 was by value; this is not correct. There is no cheap
+ * of size <= 4 was by value; this is not correct. There is no cheap
* way to determine function argument length etc.; one must simply pay
* the price of catalog lookups.
*/
-struct fp_info {
- Oid funcid;
- int nargs;
- bool argbyval[MAXFMGRARGS];
- int32 arglen[MAXFMGRARGS]; /* signed (for varlena) */
- bool retbyval;
- int32 retlen; /* signed (for varlena) */
- TransactionId xid;
- CommandId cid;
+struct fp_info
+{
+ Oid funcid;
+ int nargs;
+ bool argbyval[MAXFMGRARGS];
+ int32 arglen[MAXFMGRARGS]; /* signed (for varlena) */
+ bool retbyval;
+ int32 retlen; /* signed (for varlena) */
+ TransactionId xid;
+ CommandId cid;
};
/*
- * We implement one-back caching here. If we need to do more, we can.
+ * We implement one-back caching here. If we need to do more, we can.
* Most routines in tight loops (like PQfswrite -> F_LOWRITE) will do
* the same thing repeatedly.
*/
-static struct fp_info last_fp = { InvalidOid };
+static struct fp_info last_fp = {InvalidOid};
/*
* valid_fp_info
*
* RETURNS:
- * 1 if the state in 'fip' is valid
- * 0 otherwise
+ * 1 if the state in 'fip' is valid
+ * 0 otherwise
*
* "valid" means:
* The saved state was either uninitialized, for another function,
- * or from a previous command. (Commands can do updates, which
- * may invalidate catalog entries for subsequent commands. This
+ * or from a previous command. (Commands can do updates, which
+ * may invalidate catalog entries for subsequent commands. This
* is overly pessimistic but since there is no smarter invalidation
* scheme...).
*/
static int
-valid_fp_info(Oid func_id, struct fp_info *fip)
+valid_fp_info(Oid func_id, struct fp_info * fip)
{
- Assert(OidIsValid(func_id));
- Assert(fip != (struct fp_info *) NULL);
-
- return(OidIsValid(fip->funcid) &&
- oideq(func_id, fip->funcid) &&
- TransactionIdIsCurrentTransactionId(fip->xid) &&
- CommandIdIsCurrentCommandId(fip->cid));
+ Assert(OidIsValid(func_id));
+ Assert(fip != (struct fp_info *) NULL);
+
+ return (OidIsValid(fip->funcid) &&
+ oideq(func_id, fip->funcid) &&
+ TransactionIdIsCurrentTransactionId(fip->xid) &&
+ CommandIdIsCurrentCommandId(fip->cid));
}
/*
@@ -170,79 +178,86 @@ valid_fp_info(Oid func_id, struct fp_info *fip)
* function 'func_id'.
*
* RETURNS:
- * The correct information in 'fip'. Sets 'fip->funcid' to
- * InvalidOid if an exception occurs.
+ * The correct information in 'fip'. Sets 'fip->funcid' to
+ * InvalidOid if an exception occurs.
*/
static void
-update_fp_info(Oid func_id, struct fp_info *fip)
+update_fp_info(Oid func_id, struct fp_info * fip)
{
- Oid *argtypes; /* an oid8 */
- Oid rettype;
- HeapTuple func_htp, type_htp;
- TypeTupleForm tp;
- Form_pg_proc pp;
- int i;
-
- Assert(OidIsValid(func_id));
- Assert(fip != (struct fp_info *) NULL);
-
- /*
- * Since the validity of this structure is determined by whether
- * the funcid is OK, we clear the funcid here. It must not be
- * set to the correct value until we are about to return with
- * a good struct fp_info, since we can be interrupted (i.e., with
- * an elog(WARN, ...)) at any time.
- */
- memset((char *) fip, 0, (int) sizeof(struct fp_info));
- fip->funcid = InvalidOid;
-
- func_htp = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(func_id),
- 0,0,0);
- if (!HeapTupleIsValid(func_htp)) {
- elog(WARN, "update_fp_info: cache lookup for function %d failed",
- func_id);
- }
- pp = (Form_pg_proc) GETSTRUCT(func_htp);
- fip->nargs = pp->pronargs;
- rettype = pp->prorettype;
- argtypes = pp->proargtypes;
-
- for (i = 0; i < fip->nargs; ++i) {
- if (OidIsValid(argtypes[i])) {
- type_htp = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(argtypes[i]),
- 0,0,0);
- if (!HeapTupleIsValid(type_htp)) {
- elog(WARN, "update_fp_info: bad argument type %d for %d",
- argtypes[i], func_id);
- }
- tp = (TypeTupleForm) GETSTRUCT(type_htp);
- fip->argbyval[i] = tp->typbyval;
- fip->arglen[i] = tp->typlen;
- } /* else it had better be VAR_LENGTH_ARG */
- }
-
- if (OidIsValid(rettype)) {
- type_htp = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(rettype),
- 0,0,0);
- if (!HeapTupleIsValid(type_htp)) {
- elog(WARN, "update_fp_info: bad return type %d for %d",
- rettype, func_id);
+ Oid *argtypes; /* an oid8 */
+ Oid rettype;
+ HeapTuple func_htp,
+ type_htp;
+ TypeTupleForm tp;
+ Form_pg_proc pp;
+ int i;
+
+ Assert(OidIsValid(func_id));
+ Assert(fip != (struct fp_info *) NULL);
+
+ /*
+ * Since the validity of this structure is determined by whether the
+ * funcid is OK, we clear the funcid here. It must not be set to the
+ * correct value until we are about to return with a good struct
+ * fp_info, since we can be interrupted (i.e., with an elog(WARN,
+ * ...)) at any time.
+ */
+ memset((char *) fip, 0, (int) sizeof(struct fp_info));
+ fip->funcid = InvalidOid;
+
+ func_htp = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(func_id),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(func_htp))
+ {
+ elog(WARN, "update_fp_info: cache lookup for function %d failed",
+ func_id);
}
- tp = (TypeTupleForm) GETSTRUCT(type_htp);
- fip->retbyval = tp->typbyval;
- fip->retlen = tp->typlen;
- } /* else it had better by VAR_LENGTH_RESULT */
-
- fip->xid = GetCurrentTransactionId();
- fip->cid = GetCurrentCommandId();
-
- /*
- * This must be last!
- */
- fip->funcid = func_id;
+ pp = (Form_pg_proc) GETSTRUCT(func_htp);
+ fip->nargs = pp->pronargs;
+ rettype = pp->prorettype;
+ argtypes = pp->proargtypes;
+
+ for (i = 0; i < fip->nargs; ++i)
+ {
+ if (OidIsValid(argtypes[i]))
+ {
+ type_htp = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(argtypes[i]),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(type_htp))
+ {
+ elog(WARN, "update_fp_info: bad argument type %d for %d",
+ argtypes[i], func_id);
+ }
+ tp = (TypeTupleForm) GETSTRUCT(type_htp);
+ fip->argbyval[i] = tp->typbyval;
+ fip->arglen[i] = tp->typlen;
+ } /* else it had better be VAR_LENGTH_ARG */
+ }
+
+ if (OidIsValid(rettype))
+ {
+ type_htp = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(rettype),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(type_htp))
+ {
+ elog(WARN, "update_fp_info: bad return type %d for %d",
+ rettype, func_id);
+ }
+ tp = (TypeTupleForm) GETSTRUCT(type_htp);
+ fip->retbyval = tp->typbyval;
+ fip->retlen = tp->typlen;
+ } /* else it had better by VAR_LENGTH_RESULT */
+
+ fip->xid = GetCurrentTransactionId();
+ fip->cid = GetCurrentCommandId();
+
+ /*
+ * This must be last!
+ */
+ fip->funcid = func_id;
}
-
+
/*
* HandleFunctionRequest
@@ -251,104 +266,119 @@ update_fp_info(Oid func_id, struct fp_info *fip)
* This corresponds to the libpq protocol symbol "F".
*
* RETURNS:
- * nothing of significance.
- * All errors result in elog(WARN,...).
+ * nothing of significance.
+ * All errors result in elog(WARN,...).
*/
int
HandleFunctionRequest()
{
- Oid fid;
- int argsize;
- int nargs;
- char *arg[8];
- char *retval;
- int i;
- uint32 palloced;
- char *p;
- struct fp_info *fip;
-
- fid = (Oid) pq_getint(4); /* function oid */
- nargs = pq_getint(4); /* # of arguments */
-
- /*
- * This is where the one-back caching is done.
- * If you want to save more state, make this a loop around an array.
- */
- fip = &last_fp;
- if (!valid_fp_info(fid, fip)) {
- update_fp_info(fid, fip);
- }
-
- if (fip->nargs != nargs) {
- elog(WARN, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)",
- nargs, fip->nargs);
- }
-
- /*
- * Copy arguments into arg vector. If we palloc() an argument, we need
- * to remember, so that we pfree() it after the call.
- */
- palloced = 0x0;
- for (i = 0; i < 8; ++i) {
- if (i >= nargs) {
- arg[i] = (char *) NULL;
- } else {
- argsize = pq_getint(4);
-
- Assert(argsize > 0);
- if (fip->argbyval[i]) { /* by-value */
- Assert(argsize <= 4);
- arg[i] = (char *) pq_getint(argsize);
- } else { /* by-reference ... */
- if (fip->arglen[i] < 0) { /* ... varlena */
- if (!(p = palloc(argsize + VARHDRSZ))) {
- elog(WARN, "HandleFunctionRequest: palloc failed");
- }
- VARSIZE(p) = argsize + VARHDRSZ;
- pq_getnchar(VARDATA(p), 0, argsize);
- } else { /* ... fixed */
- /* XXX cross our fingers and trust "argsize" */
- if (!(p = palloc(argsize))) {
- elog(WARN, "HandleFunctionRequest: palloc failed");
+ Oid fid;
+ int argsize;
+ int nargs;
+ char *arg[8];
+ char *retval;
+ int i;
+ uint32 palloced;
+ char *p;
+ struct fp_info *fip;
+
+ fid = (Oid) pq_getint(4); /* function oid */
+ nargs = pq_getint(4); /* # of arguments */
+
+ /*
+ * This is where the one-back caching is done. If you want to save
+ * more state, make this a loop around an array.
+ */
+ fip = &last_fp;
+ if (!valid_fp_info(fid, fip))
+ {
+ update_fp_info(fid, fip);
+ }
+
+ if (fip->nargs != nargs)
+ {
+ elog(WARN, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)",
+ nargs, fip->nargs);
+ }
+
+ /*
+ * Copy arguments into arg vector. If we palloc() an argument, we
+ * need to remember, so that we pfree() it after the call.
+ */
+ palloced = 0x0;
+ for (i = 0; i < 8; ++i)
+ {
+ if (i >= nargs)
+ {
+ arg[i] = (char *) NULL;
+ }
+ else
+ {
+ argsize = pq_getint(4);
+
+ Assert(argsize > 0);
+ if (fip->argbyval[i])
+ { /* by-value */
+ Assert(argsize <= 4);
+ arg[i] = (char *) pq_getint(argsize);
}
- pq_getnchar(p, 0, argsize);
- }
- palloced |= (1 << i);
- arg[i] = p;
- }
+ else
+ { /* by-reference ... */
+ if (fip->arglen[i] < 0)
+ { /* ... varlena */
+ if (!(p = palloc(argsize + VARHDRSZ)))
+ {
+ elog(WARN, "HandleFunctionRequest: palloc failed");
+ }
+ VARSIZE(p) = argsize + VARHDRSZ;
+ pq_getnchar(VARDATA(p), 0, argsize);
+ }
+ else
+ { /* ... fixed */
+ /* XXX cross our fingers and trust "argsize" */
+ if (!(p = palloc(argsize)))
+ {
+ elog(WARN, "HandleFunctionRequest: palloc failed");
+ }
+ pq_getnchar(p, 0, argsize);
+ }
+ palloced |= (1 << i);
+ arg[i] = p;
+ }
+ }
}
- }
#ifndef NO_FASTPATH
- retval = fmgr(fid,
- arg[0], arg[1], arg[2], arg[3],
- arg[4], arg[5], arg[6], arg[7]);
+ retval = fmgr(fid,
+ arg[0], arg[1], arg[2], arg[3],
+ arg[4], arg[5], arg[6], arg[7]);
#else
- retval = NULL;
-#endif /* NO_FASTPATH */
-
- /* free palloc'ed arguments */
- for (i = 0; i < nargs; ++i) {
- if (palloced & (1 << i))
- pfree(arg[i]);
- }
-
- /*
- * If this is an ordinary query (not a retrieve portal p ...), then
- * we return the data to the user. If the return value was palloc'ed,
- * then it must also be freed.
- */
+ retval = NULL;
+#endif /* NO_FASTPATH */
+
+ /* free palloc'ed arguments */
+ for (i = 0; i < nargs; ++i)
+ {
+ if (palloced & (1 << i))
+ pfree(arg[i]);
+ }
+
+ /*
+ * If this is an ordinary query (not a retrieve portal p ...), then we
+ * return the data to the user. If the return value was palloc'ed,
+ * then it must also be freed.
+ */
#ifndef NO_FASTPATH
- SendFunctionResult(fid, retval, fip->retbyval, fip->retlen);
+ SendFunctionResult(fid, retval, fip->retbyval, fip->retlen);
#else
- SendFunctionResult(fid, retval, fip->retbyval, 0);
-#endif /* NO_FASTPATH */
+ SendFunctionResult(fid, retval, fip->retbyval, 0);
+#endif /* NO_FASTPATH */
+
+ if (!fip->retbyval)
+ pfree(retval);
+
- if (!fip->retbyval)
- pfree(retval);
-
-
- return(0);
+ return (0);
}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index cd658704f03..f70d30434bb 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* postgres.c--
- * POSTGRES C Backend Interface
+ * POSTGRES C Backend Interface
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.42 1997/08/19 21:34:04 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.43 1997/09/07 04:49:33 momjian Exp $
*
* NOTES
- * this is the "main" module of the postgres backend and
- * hence the main module of the "traffic cop".
+ * this is the "main" module of the postgres backend and
+ * hence the main module of the "traffic cop".
*
*-------------------------------------------------------------------------
*/
@@ -25,17 +25,17 @@
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
-#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
+#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
#ifndef MAXHOSTNAMELEN
-#include <netdb.h> /* for MAXHOSTNAMELEN on some */
+#include <netdb.h> /* for MAXHOSTNAMELEN on some */
#endif
-#ifndef MAXHOSTNAMELEN /* for MAXHOSTNAMELEN under sco3.2v5.0.2 */
+#ifndef MAXHOSTNAMELEN /* for MAXHOSTNAMELEN under sco3.2v5.0.2 */
#include <sys/socket.h>
#endif
#include <errno.h>
#ifdef aix
#include <sys/select.h>
-#endif /* aix */
+#endif /* aix */
#include "postgres.h"
@@ -46,9 +46,9 @@
#include "lib/dllist.h"
#include "parser/catalog_utils.h"
-#include "parser/parse_query.h" /* for MakeTimeRange() */
+#include "parser/parse_query.h" /* for MakeTimeRange() */
#include "commands/async.h"
-#include "tcop/tcopprot.h" /* where declarations for this file go */
+#include "tcop/tcopprot.h" /* where declarations for this file go */
#include "optimizer/planner.h"
#include "tcop/tcopprot.h"
@@ -88,1488 +88,1623 @@
#include "libpq/libpq.h"
#include "libpq/pqsignal.h"
-#include "rewrite/rewriteHandler.h" /* for QueryRewrite() */
+#include "rewrite/rewriteHandler.h" /* for QueryRewrite() */
-static void quickdie(SIGNAL_ARGS);
+static void quickdie(SIGNAL_ARGS);
/* ----------------
- * global variables
+ * global variables
* ----------------
*/
-static bool DebugPrintQuery = false;
-static bool DebugPrintPlan = false;
-static bool DebugPrintParse = false;
-static bool DebugPrintRewrittenParsetree = false;
-/*static bool EnableRewrite = true; , never changes why have it*/
-CommandDest whereToSendOutput;
+static bool DebugPrintQuery = false;
+static bool DebugPrintPlan = false;
+static bool DebugPrintParse = false;
+static bool DebugPrintRewrittenParsetree = false;
+
+/*static bool EnableRewrite = true; , never changes why have it*/
+CommandDest whereToSendOutput;
#ifdef LOCK_MGR_DEBUG
-extern int lockDebug;
+extern int lockDebug;
+
#endif
-extern int lockingOff;
-extern int NBuffers;
+extern int lockingOff;
+extern int NBuffers;
-int dontExecute = 0;
-static int ShowStats;
-static bool IsEmptyQuery = false;
+int dontExecute = 0;
+static int ShowStats;
+static bool IsEmptyQuery = false;
-char relname[80]; /* current relation name */
+char relname[80]; /* current relation name */
#if defined(nextstep)
-jmp_buf Warn_restart;
-#define sigsetjmp(x,y) setjmp(x)
+jmp_buf Warn_restart;
+
+#define sigsetjmp(x,y) setjmp(x)
#define siglongjmp longjmp
#else
-sigjmp_buf Warn_restart;
-#endif /* defined(nextstep) */
-int InWarn;
-
-extern int NBuffers;
-
-static int EchoQuery = 0; /* default don't echo */
-time_t tim;
-char pg_pathname[256];
-static int ShowParserStats;
-static int ShowPlannerStats;
-int ShowExecutorStats;
-FILE *StatFp;
-
-typedef struct frontend {
- bool fn_connected;
- Port fn_port;
- FILE *fn_Pfin; /* the input fd */
- FILE *fn_Pfout; /* the output fd */
- bool fn_done; /* set after the frontend closes its connection */
-} FrontEnd;
-
-static Dllist* frontendList;
+sigjmp_buf Warn_restart;
+
+#endif /* defined(nextstep) */
+int InWarn;
+
+extern int NBuffers;
+
+static int EchoQuery = 0; /* default don't echo */
+time_t tim;
+char pg_pathname[256];
+static int ShowParserStats;
+static int ShowPlannerStats;
+int ShowExecutorStats;
+FILE *StatFp;
+
+typedef struct frontend
+{
+ bool fn_connected;
+ Port fn_port;
+ FILE *fn_Pfin; /* the input fd */
+ FILE *fn_Pfout; /* the output fd */
+ bool fn_done; /* set after the frontend closes its
+ * connection */
+} FrontEnd;
+
+static Dllist *frontendList;
/* ----------------
- * people who want to use EOF should #define DONTUSENEWLINE in
- * tcop/tcopdebug.h
+ * people who want to use EOF should #define DONTUSENEWLINE in
+ * tcop/tcopdebug.h
* ----------------
*/
#ifndef TCOP_DONTUSENEWLINE
-int UseNewLine = 1; /* Use newlines query delimiters (the default) */
+int UseNewLine = 1; /* Use newlines query delimiters (the
+ * default) */
+
#else
-int UseNewLine = 0; /* Use EOF as query delimiters */
-#endif /* TCOP_DONTUSENEWLINE */
+int UseNewLine = 0; /* Use EOF as query delimiters */
+
+#endif /* TCOP_DONTUSENEWLINE */
/* ----------------
- * bushy tree plan flag: if true planner will generate bushy-tree
- * plans
+ * bushy tree plan flag: if true planner will generate bushy-tree
+ * plans
* ----------------
*/
-int BushyPlanFlag = 0; /* default to false -- consider only left-deep trees */
+int BushyPlanFlag = 0; /* default to false -- consider
+ * only left-deep trees */
/*
** Flags for expensive function optimization -- JMH 3/9/92
*/
-int XfuncMode = 0;
+int XfuncMode = 0;
/*
* ----------------
- * Note: _exec_repeat_ defaults to 1 but may be changed
- * by a DEBUG command. If you set this to a large
- * number N, run a single query, and then set it
- * back to 1 and run N queries, you can get an idea
- * of how much time is being spent in the parser and
- * planner b/c in the first case this overhead only
- * happens once. -cim 6/9/91
+ * Note: _exec_repeat_ defaults to 1 but may be changed
+ * by a DEBUG command. If you set this to a large
+ * number N, run a single query, and then set it
+ * back to 1 and run N queries, you can get an idea
+ * of how much time is being spent in the parser and
+ * planner b/c in the first case this overhead only
+ * happens once. -cim 6/9/91
* ----------------
*/
-int _exec_repeat_ = 1;
+int _exec_repeat_ = 1;
/* ----------------------------------------------------------------
- * decls for routines only used in this file
+ * decls for routines only used in this file
* ----------------------------------------------------------------
*/
-static char InteractiveBackend(char *inBuf);
-static char SocketBackend(char *inBuf, bool multiplexedBackend);
-static char ReadCommand(char *inBuf, bool multiplexedBackend);
+static char InteractiveBackend(char *inBuf);
+static char SocketBackend(char *inBuf, bool multiplexedBackend);
+static char ReadCommand(char *inBuf, bool multiplexedBackend);
/* ----------------------------------------------------------------
- * routines to obtain user input
+ * routines to obtain user input
* ----------------------------------------------------------------
*/
/* ----------------
- * InteractiveBackend() is called for user interactive connections
- * the string entered by the user is placed in its parameter inBuf.
+ * InteractiveBackend() is called for user interactive connections
+ * the string entered by the user is placed in its parameter inBuf.
* ----------------
*/
static char
InteractiveBackend(char *inBuf)
{
- char *stuff = inBuf; /* current place in input buffer */
- int c; /* character read from getc() */
- bool end = false; /* end-of-input flag */
- bool backslashSeen = false; /* have we seen a \ ? */
-
- /* ----------------
- * display a prompt and obtain input from the user
- * ----------------
- */
- printf("> ");
-
- for (;;) {
- if (UseNewLine) {
- /* ----------------
- * if we are using \n as a delimiter, then read
- * characters until the \n.
- * ----------------
- */
- while ( (c = getc(stdin)) != EOF) {
- if (c == '\n') {
- if (backslashSeen) {
- stuff--;
- continue;
- } else {
- /* keep the newline character */
- *stuff++ = '\n';
- *stuff++ = '\0';
- break;
- }
- } else if (c == '\\')
- backslashSeen = true;
- else
- backslashSeen = false;
-
- *stuff++ = (char)c;
- }
-
- if (c == EOF)
- end = true;
- } else {
- /* ----------------
- * otherwise read characters until EOF.
- * ----------------
- */
- while ( (c = getc(stdin)) != EOF )
- *stuff++ = (char)c;
-
- if ( stuff == inBuf )
- end = true;
- }
-
- if (end) {
- if (!Quiet) puts("EOF");
- IsEmptyQuery = true;
- exitpg(0);
- }
-
- /* ----------------
- * otherwise we have a user query so process it.
- * ----------------
- */
- break;
- }
-
- /* ----------------
- * if the query echo flag was given, print the query..
- * ----------------
- */
- if (EchoQuery)
- printf("query is: %s\n", inBuf);
-
- return('Q');
+ char *stuff = inBuf; /* current place in input buffer */
+ int c; /* character read from getc() */
+ bool end = false;/* end-of-input flag */
+ bool backslashSeen = false; /* have we seen a \ ? */
+
+ /* ----------------
+ * display a prompt and obtain input from the user
+ * ----------------
+ */
+ printf("> ");
+
+ for (;;)
+ {
+ if (UseNewLine)
+ {
+ /* ----------------
+ * if we are using \n as a delimiter, then read
+ * characters until the \n.
+ * ----------------
+ */
+ while ((c = getc(stdin)) != EOF)
+ {
+ if (c == '\n')
+ {
+ if (backslashSeen)
+ {
+ stuff--;
+ continue;
+ }
+ else
+ {
+ /* keep the newline character */
+ *stuff++ = '\n';
+ *stuff++ = '\0';
+ break;
+ }
+ }
+ else if (c == '\\')
+ backslashSeen = true;
+ else
+ backslashSeen = false;
+
+ *stuff++ = (char) c;
+ }
+
+ if (c == EOF)
+ end = true;
+ }
+ else
+ {
+ /* ----------------
+ * otherwise read characters until EOF.
+ * ----------------
+ */
+ while ((c = getc(stdin)) != EOF)
+ *stuff++ = (char) c;
+
+ if (stuff == inBuf)
+ end = true;
+ }
+
+ if (end)
+ {
+ if (!Quiet)
+ puts("EOF");
+ IsEmptyQuery = true;
+ exitpg(0);
+ }
+
+ /* ----------------
+ * otherwise we have a user query so process it.
+ * ----------------
+ */
+ break;
+ }
+
+ /* ----------------
+ * if the query echo flag was given, print the query..
+ * ----------------
+ */
+ if (EchoQuery)
+ printf("query is: %s\n", inBuf);
+
+ return ('Q');
}
/* ----------------
- * SocketBackend() Is called for frontend-backend connections
+ * SocketBackend() Is called for frontend-backend connections
*
- * If the input is a query (case 'Q') then the string entered by
- * the user is placed in its parameter inBuf.
+ * If the input is a query (case 'Q') then the string entered by
+ * the user is placed in its parameter inBuf.
*
- * If the input is a fastpath function call (case 'F') then
- * the function call is processed in HandleFunctionRequest().
- * (now called from PostgresMain())
+ * If the input is a fastpath function call (case 'F') then
+ * the function call is processed in HandleFunctionRequest().
+ * (now called from PostgresMain())
* ----------------
*/
static char
SocketBackend(char *inBuf, bool multiplexedBackend)
{
- char qtype[2];
- char result = '\0';
-
- /* ----------------
- * get input from the frontend
- * ----------------
- */
- strcpy(qtype, "?");
- if (pq_getnchar(qtype,0,1) == EOF) {
- /* ------------
- * when front-end applications quits/dies
- * ------------
- */
- if (multiplexedBackend) {
- return 'X';
- }
- else
- exitpg(0);
- }
-
- switch(*qtype) {
- /* ----------------
- * 'Q': user entered a query
- * ----------------
- */
- case 'Q':
- pq_getstr(inBuf, MAX_PARSE_BUFFER);
- result = 'Q';
- break;
-
- /* ----------------
- * 'F': calling user/system functions
- * ----------------
- */
- case 'F':
- pq_getstr(inBuf, MAX_PARSE_BUFFER);/* ignore the rest of the line */
- result = 'F';
- break;
-
- /* ----------------
- * 'X': frontend is exiting
- * ----------------
- */
- case 'X':
- result = 'X';
- break;
-
- /* ----------------
- * otherwise we got garbage from the frontend.
- *
- * XXX are we certain that we want to do an elog(FATAL) here?
- * -cim 1/24/90
- * ----------------
- */
- default:
- elog(FATAL, "Socket command type %c unknown\n", *qtype);
- break;
- }
- return result;
+ char qtype[2];
+ char result = '\0';
+
+ /* ----------------
+ * get input from the frontend
+ * ----------------
+ */
+ strcpy(qtype, "?");
+ if (pq_getnchar(qtype, 0, 1) == EOF)
+ {
+ /* ------------
+ * when front-end applications quits/dies
+ * ------------
+ */
+ if (multiplexedBackend)
+ {
+ return 'X';
+ }
+ else
+ exitpg(0);
+ }
+
+ switch (*qtype)
+ {
+ /* ----------------
+ * 'Q': user entered a query
+ * ----------------
+ */
+ case 'Q':
+ pq_getstr(inBuf, MAX_PARSE_BUFFER);
+ result = 'Q';
+ break;
+
+ /* ----------------
+ * 'F': calling user/system functions
+ * ----------------
+ */
+ case 'F':
+ pq_getstr(inBuf, MAX_PARSE_BUFFER); /* ignore the rest of the
+ * line */
+ result = 'F';
+ break;
+
+ /* ----------------
+ * 'X': frontend is exiting
+ * ----------------
+ */
+ case 'X':
+ result = 'X';
+ break;
+
+ /* ----------------
+ * otherwise we got garbage from the frontend.
+ *
+ * XXX are we certain that we want to do an elog(FATAL) here?
+ * -cim 1/24/90
+ * ----------------
+ */
+ default:
+ elog(FATAL, "Socket command type %c unknown\n", *qtype);
+ break;
+ }
+ return result;
}
/* ----------------
- * ReadCommand reads a command from either the frontend or
- * standard input, places it in inBuf, and returns a char
- * representing whether the string is a 'Q'uery or a 'F'astpath
- * call.
+ * ReadCommand reads a command from either the frontend or
+ * standard input, places it in inBuf, and returns a char
+ * representing whether the string is a 'Q'uery or a 'F'astpath
+ * call.
* ----------------
*/
static char
ReadCommand(char *inBuf, bool multiplexedBackend)
{
- if (IsUnderPostmaster || multiplexedBackend)
- return SocketBackend(inBuf, multiplexedBackend);
- else
- return InteractiveBackend(inBuf);
+ if (IsUnderPostmaster || multiplexedBackend)
+ return SocketBackend(inBuf, multiplexedBackend);
+ else
+ return InteractiveBackend(inBuf);
}
-List *
-pg_plan(char *query_string, /* string to execute */
- Oid *typev, /* argument types */
- int nargs, /* number of arguments */
- QueryTreeList **queryListP, /* pointer to the parse trees */
- CommandDest dest) /* where results should go */
+List *
+pg_plan(char *query_string, /* string to execute */
+ Oid * typev, /* argument types */
+ int nargs, /* number of arguments */
+ QueryTreeList ** queryListP, /* pointer to the parse trees */
+ CommandDest dest) /* where results should go */
{
- QueryTreeList *querytree_list;
- int i;
- List *plan_list = NIL;
- Plan *plan;
- int j;
- QueryTreeList *new_list;
- List *rewritten = NIL;
- Query* querytree;
-
- /* ----------------
- * (1) parse the request string into a list of parse trees
- * ----------------
- */
- if (ShowParserStats)
- ResetUsage();
-
- querytree_list = parser(query_string, typev, nargs);
-
- if (ShowParserStats) {
- fprintf(stderr, "! Parser Stats:\n");
- ShowUsage();
- }
-
- /* new_list holds the rewritten queries */
- new_list = (QueryTreeList*)malloc(sizeof(QueryTreeList));
- new_list->len = querytree_list->len;
- new_list->qtrees = (Query**)malloc(new_list->len * sizeof(Query*));
-
- /* ----------------
- * (2) rewrite the queries, as necessary
- * ----------------
- */
- j = 0; /* counter for the new_list, new_list can be longer than
- old list as a result of rewrites */
- for (i=0;i<querytree_list->len;i++) {
- querytree = querytree_list->qtrees[i];
-
-
- /* don't rewrite utilites */
- if (querytree->commandType == CMD_UTILITY) {
- new_list->qtrees[j++] = querytree;
- continue;
- }
-
- if ( DebugPrintQuery == true ) {
- printf("\n---- \tquery is:\n%s\n",query_string);
- printf("\n");
- fflush(stdout);
- }
-
- if ( DebugPrintParse == true ) {
- printf("\n---- \tparser outputs :\n");
- nodeDisplay(querytree);
- printf("\n");
- }
-
- /* rewrite queries (retrieve, append, delete, replace) */
- rewritten = QueryRewrite(querytree);
- if (rewritten != NULL) {
- int len, k;
- len = length(rewritten);
- if (len == 1)
- new_list->qtrees[j++] = (Query*)lfirst(rewritten);
- else {
- /* rewritten queries are longer than original query */
- /* grow the new_list to accommodate */
- new_list->len += len - 1; /* - 1 because originally we
- allocated one space for the query */
- new_list->qtrees = realloc(new_list->qtrees,
- new_list->len * sizeof(Query*));
- for (k=0;k<len;k++)
- new_list->qtrees[j++] = (Query*)nth(k, rewritten);
- }
- }
- }
-
- /* we're done with the original lists, free it */
- free(querytree_list->qtrees);
- free(querytree_list);
-
- querytree_list = new_list;
-
- /* ----------------
- * Fix time range quals
- * this _must_ go here, because it must take place after rewrites
- * ( if they take place ) so that time quals are usable by the executor
- *
- * Also, need to frob the range table entries here to plan union
- * queries for archived relations.
- * ----------------
- */
- for (i=0;i<querytree_list->len;i++) {
- List *l;
- List *rt = NULL;
-
- querytree = querytree_list->qtrees[i];
-
- /* ----------------
- * utilities don't have time ranges
- * ----------------
- */
- if (querytree->commandType == CMD_UTILITY)
- continue;
-
- rt = querytree->rtable;
-
- foreach (l, rt) {
- RangeTblEntry *rte = lfirst(l);
- TimeRange *timequal = rte->timeRange;
-
- if (timequal) {
- int timecode = (rte->timeRange->endDate == NULL)? 0 : 1;
-
- rte->timeQual = makeTimeRange(rte->timeRange->startDate,
- rte->timeRange->endDate,
- timecode);
- }else {
- rte->timeQual = NULL;
- }
- }
-
- /* check for archived relations */
- plan_archive(rt);
- }
-
- if (DebugPrintRewrittenParsetree == true) {
- printf("\n---- \tafter rewriting:\n");
-
- for (i=0; i<querytree_list->len; i++) {
- print(querytree_list->qtrees[i]);
- printf("\n");
- }
- }
-
- for (i=0; i<querytree_list->len;i++) {
- querytree = querytree_list->qtrees[i];
-
- /*
- * For each query that isn't a utility invocation,
- * generate a plan.
- */
-
- if (querytree->commandType != CMD_UTILITY) {
-
- if (IsAbortedTransactionBlockState()) {
- /* ----------------
- * the EndCommand() stuff is to tell the frontend
- * that the command ended. -cim 6/1/90
- * ----------------
- */
- char *tag = "*ABORT STATE*";
- EndCommand(tag, dest);
-
- elog(NOTICE, "(transaction aborted): %s",
- "queries ignored until END");
-
- *queryListP = (QueryTreeList*)NULL;
- return (List*)NULL;
- }
-
- if (ShowPlannerStats) ResetUsage();
- plan = planner(querytree);
- if (ShowPlannerStats) {
- fprintf(stderr, "! Planner Stats:\n");
- ShowUsage();
- }
- plan_list = lappend(plan_list, plan);
+ QueryTreeList *querytree_list;
+ int i;
+ List *plan_list = NIL;
+ Plan *plan;
+ int j;
+ QueryTreeList *new_list;
+ List *rewritten = NIL;
+ Query *querytree;
+
+ /* ----------------
+ * (1) parse the request string into a list of parse trees
+ * ----------------
+ */
+ if (ShowParserStats)
+ ResetUsage();
+
+ querytree_list = parser(query_string, typev, nargs);
+
+ if (ShowParserStats)
+ {
+ fprintf(stderr, "! Parser Stats:\n");
+ ShowUsage();
+ }
+
+ /* new_list holds the rewritten queries */
+ new_list = (QueryTreeList *) malloc(sizeof(QueryTreeList));
+ new_list->len = querytree_list->len;
+ new_list->qtrees = (Query **) malloc(new_list->len * sizeof(Query *));
+
+ /* ----------------
+ * (2) rewrite the queries, as necessary
+ * ----------------
+ */
+ j = 0; /* counter for the new_list, new_list can
+ * be longer than old list as a result of
+ * rewrites */
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ querytree = querytree_list->qtrees[i];
+
+
+ /* don't rewrite utilites */
+ if (querytree->commandType == CMD_UTILITY)
+ {
+ new_list->qtrees[j++] = querytree;
+ continue;
+ }
+
+ if (DebugPrintQuery == true)
+ {
+ printf("\n---- \tquery is:\n%s\n", query_string);
+ printf("\n");
+ fflush(stdout);
+ }
+
+ if (DebugPrintParse == true)
+ {
+ printf("\n---- \tparser outputs :\n");
+ nodeDisplay(querytree);
+ printf("\n");
+ }
+
+ /* rewrite queries (retrieve, append, delete, replace) */
+ rewritten = QueryRewrite(querytree);
+ if (rewritten != NULL)
+ {
+ int len,
+ k;
+
+ len = length(rewritten);
+ if (len == 1)
+ new_list->qtrees[j++] = (Query *) lfirst(rewritten);
+ else
+ {
+ /* rewritten queries are longer than original query */
+ /* grow the new_list to accommodate */
+ new_list->len += len - 1; /* - 1 because originally
+ * we allocated one space
+ * for the query */
+ new_list->qtrees = realloc(new_list->qtrees,
+ new_list->len * sizeof(Query *));
+ for (k = 0; k < len; k++)
+ new_list->qtrees[j++] = (Query *) nth(k, rewritten);
+ }
+ }
+ }
+
+ /* we're done with the original lists, free it */
+ free(querytree_list->qtrees);
+ free(querytree_list);
+
+ querytree_list = new_list;
+
+ /* ----------------
+ * Fix time range quals
+ * this _must_ go here, because it must take place after rewrites
+ * ( if they take place ) so that time quals are usable by the executor
+ *
+ * Also, need to frob the range table entries here to plan union
+ * queries for archived relations.
+ * ----------------
+ */
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ List *l;
+ List *rt = NULL;
+
+ querytree = querytree_list->qtrees[i];
+
+ /* ----------------
+ * utilities don't have time ranges
+ * ----------------
+ */
+ if (querytree->commandType == CMD_UTILITY)
+ continue;
+
+ rt = querytree->rtable;
+
+ foreach(l, rt)
+ {
+ RangeTblEntry *rte = lfirst(l);
+ TimeRange *timequal = rte->timeRange;
+
+ if (timequal)
+ {
+ int timecode = (rte->timeRange->endDate == NULL) ? 0 : 1;
+
+ rte->timeQual = makeTimeRange(rte->timeRange->startDate,
+ rte->timeRange->endDate,
+ timecode);
+ }
+ else
+ {
+ rte->timeQual = NULL;
+ }
+ }
+
+ /* check for archived relations */
+ plan_archive(rt);
+ }
+
+ if (DebugPrintRewrittenParsetree == true)
+ {
+ printf("\n---- \tafter rewriting:\n");
+
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ print(querytree_list->qtrees[i]);
+ printf("\n");
+ }
+ }
+
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ querytree = querytree_list->qtrees[i];
+
+ /*
+ * For each query that isn't a utility invocation, generate a
+ * plan.
+ */
+
+ if (querytree->commandType != CMD_UTILITY)
+ {
+
+ if (IsAbortedTransactionBlockState())
+ {
+ /* ----------------
+ * the EndCommand() stuff is to tell the frontend
+ * that the command ended. -cim 6/1/90
+ * ----------------
+ */
+ char *tag = "*ABORT STATE*";
+
+ EndCommand(tag, dest);
+
+ elog(NOTICE, "(transaction aborted): %s",
+ "queries ignored until END");
+
+ *queryListP = (QueryTreeList *) NULL;
+ return (List *) NULL;
+ }
+
+ if (ShowPlannerStats)
+ ResetUsage();
+ plan = planner(querytree);
+ if (ShowPlannerStats)
+ {
+ fprintf(stderr, "! Planner Stats:\n");
+ ShowUsage();
+ }
+ plan_list = lappend(plan_list, plan);
#ifdef INDEXSCAN_PATCH
- /* ----------------
- * Print plan if debugging.
- * This has been moved here to get debugging output
- * also for queries in functions. DZ - 27-8-1996
- * ----------------
- */
- if ( DebugPrintPlan == true ) {
- printf("\n---- \tplan is :\n");
- nodeDisplay(plan);
- printf("\n");
- }
+ /* ----------------
+ * Print plan if debugging.
+ * This has been moved here to get debugging output
+ * also for queries in functions. DZ - 27-8-1996
+ * ----------------
+ */
+ if (DebugPrintPlan == true)
+ {
+ printf("\n---- \tplan is :\n");
+ nodeDisplay(plan);
+ printf("\n");
+ }
#endif
- }
+ }
#ifdef FUNC_UTIL_PATCH
- /*
- * If the command is an utility append a null plan. This is
- * needed to keep the plan_list aligned with the querytree_list
- * or the function executor will crash. DZ - 30-8-1996
- */
- else {
- plan_list = lappend(plan_list, NULL);
- }
+
+ /*
+ * If the command is an utility append a null plan. This is needed
+ * to keep the plan_list aligned with the querytree_list or the
+ * function executor will crash. DZ - 30-8-1996
+ */
+ else
+ {
+ plan_list = lappend(plan_list, NULL);
+ }
#endif
- }
-
- if (queryListP)
- *queryListP = querytree_list;
-
- return (plan_list);
+ }
+
+ if (queryListP)
+ *queryListP = querytree_list;
+
+ return (plan_list);
}
/* ----------------------------------------------------------------
- * pg_eval()
- *
- * Takes a querystring, runs the parser/utilities or
- * parser/planner/executor over it as necessary
- * Begin Transaction Should have been called before this
- * and CommitTransaction After this is called
- * This is strictly because we do not allow for nested xactions.
+ * pg_eval()
+ *
+ * Takes a querystring, runs the parser/utilities or
+ * parser/planner/executor over it as necessary
+ * Begin Transaction Should have been called before this
+ * and CommitTransaction After this is called
+ * This is strictly because we do not allow for nested xactions.
*
- * NON-OBVIOUS-RESTRICTIONS
- * this function _MUST_ allocate a new "parsetree" each time,
- * since it may be stored in a named portal and should not
- * change its value.
+ * NON-OBVIOUS-RESTRICTIONS
+ * this function _MUST_ allocate a new "parsetree" each time,
+ * since it may be stored in a named portal and should not
+ * change its value.
*
* ----------------------------------------------------------------
*/
void
-pg_eval(char *query_string, char **argv, Oid *typev, int nargs)
+pg_eval(char *query_string, char **argv, Oid * typev, int nargs)
{
- pg_eval_dest(query_string, argv, typev, nargs, whereToSendOutput);
+ pg_eval_dest(query_string, argv, typev, nargs, whereToSendOutput);
}
void
-pg_eval_dest(char *query_string, /* string to execute */
- char **argv, /* arguments */
- Oid *typev, /* argument types */
- int nargs, /* number of arguments */
- CommandDest dest) /* where results should go */
+pg_eval_dest(char *query_string,/* string to execute */
+ char **argv, /* arguments */
+ Oid * typev, /* argument types */
+ int nargs, /* number of arguments */
+ CommandDest dest) /* where results should go */
{
- List *plan_list;
- Plan *plan;
- Query *querytree;
- int i,j;
- QueryTreeList *querytree_list;
-
- /* plan the queries */
- plan_list = pg_plan(query_string, typev, nargs, &querytree_list, dest);
-
- /* pg_plan could have failed */
- if (querytree_list == NULL)
- return;
-
- for (i=0;i<querytree_list->len;i++) {
- querytree = querytree_list->qtrees[i];
-
+ List *plan_list;
+ Plan *plan;
+ Query *querytree;
+ int i,
+ j;
+ QueryTreeList *querytree_list;
+
+ /* plan the queries */
+ plan_list = pg_plan(query_string, typev, nargs, &querytree_list, dest);
+
+ /* pg_plan could have failed */
+ if (querytree_list == NULL)
+ return;
+
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ querytree = querytree_list->qtrees[i];
+
#ifdef FUNC_UTIL_PATCH
- /*
- * Advance on the plan_list in every case. Now the plan_list
- * has the same length of the querytree_list. DZ - 30-8-1996
- */
- plan = (Plan *) lfirst(plan_list);
- plan_list = lnext(plan_list);
+
+ /*
+ * Advance on the plan_list in every case. Now the plan_list has
+ * the same length of the querytree_list. DZ - 30-8-1996
+ */
+ plan = (Plan *) lfirst(plan_list);
+ plan_list = lnext(plan_list);
#endif
- if (querytree->commandType == CMD_UTILITY) {
- /* ----------------
- * process utility functions (create, destroy, etc..)
- *
- * Note: we do not check for the transaction aborted state
- * because that is done in ProcessUtility.
- * ----------------
- */
- if (! Quiet) {
- time(&tim);
- printf("\tProcessUtility() at %s\n", ctime(&tim));
- }
-
- ProcessUtility(querytree->utilityStmt, dest);
-
- } else {
+ if (querytree->commandType == CMD_UTILITY)
+ {
+ /* ----------------
+ * process utility functions (create, destroy, etc..)
+ *
+ * Note: we do not check for the transaction aborted state
+ * because that is done in ProcessUtility.
+ * ----------------
+ */
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tProcessUtility() at %s\n", ctime(&tim));
+ }
+
+ ProcessUtility(querytree->utilityStmt, dest);
+
+ }
+ else
+ {
#ifndef FUNC_UTIL_PATCH
- /*
- * Moved before the if. DZ - 30-8-1996
- */
- plan = (Plan *) lfirst(plan_list);
- plan_list = lnext(plan_list);
+
+ /*
+ * Moved before the if. DZ - 30-8-1996
+ */
+ plan = (Plan *) lfirst(plan_list);
+ plan_list = lnext(plan_list);
#endif
-
+
#ifdef INDEXSCAN_PATCH
- /*
- * Print moved in pg_plan. DZ - 27-8-1996
- */
+
+ /*
+ * Print moved in pg_plan. DZ - 27-8-1996
+ */
#else
- /* ----------------
- * print plan if debugging
- * ----------------
- */
- if ( DebugPrintPlan == true ) {
- printf("\n---- plan is :\n");
- nodeDisplay(plan);
- printf("\n");
- }
+ /* ----------------
+ * print plan if debugging
+ * ----------------
+ */
+ if (DebugPrintPlan == true)
+ {
+ printf("\n---- plan is :\n");
+ nodeDisplay(plan);
+ printf("\n");
+ }
#endif
-
- /* ----------------
- * execute the plan
- *
- */
- if (ShowExecutorStats)
- ResetUsage();
-
- for (j = 0; j < _exec_repeat_; j++) {
- if (! Quiet) {
- time(&tim);
- printf("\tProcessQuery() at %s\n", ctime(&tim));
- }
- ProcessQuery(querytree, plan, argv, typev, nargs, dest);
- }
-
- if (ShowExecutorStats) {
- fprintf(stderr, "! Executor Stats:\n");
- ShowUsage();
- }
- }
- /*
- * In a query block, we want to increment the command counter
- * between queries so that the effects of early queries are
- * visible to subsequent ones.
- */
-
- if (querytree_list)
- CommandCounterIncrement();
- }
-
- free(querytree_list->qtrees);
- free(querytree_list);
+
+ /* ----------------
+ * execute the plan
+ *
+ */
+ if (ShowExecutorStats)
+ ResetUsage();
+
+ for (j = 0; j < _exec_repeat_; j++)
+ {
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tProcessQuery() at %s\n", ctime(&tim));
+ }
+ ProcessQuery(querytree, plan, argv, typev, nargs, dest);
+ }
+
+ if (ShowExecutorStats)
+ {
+ fprintf(stderr, "! Executor Stats:\n");
+ ShowUsage();
+ }
+ }
+
+ /*
+ * In a query block, we want to increment the command counter
+ * between queries so that the effects of early queries are
+ * visible to subsequent ones.
+ */
+
+ if (querytree_list)
+ CommandCounterIncrement();
+ }
+
+ free(querytree_list->qtrees);
+ free(querytree_list);
}
/* --------------------------------
- * signal handler routines used in PostgresMain()
+ * signal handler routines used in PostgresMain()
*
- * handle_warn() is used to catch kill(getpid(),1) which
- * occurs when elog(WARN) is called.
+ * handle_warn() is used to catch kill(getpid(),1) which
+ * occurs when elog(WARN) is called.
*
- * quickdie() occurs when signalled by the postmaster, some backend
- * has bought the farm we need to stop what we're doing and exit.
+ * quickdie() occurs when signalled by the postmaster, some backend
+ * has bought the farm we need to stop what we're doing and exit.
*
- * die() preforms an orderly cleanup via ExitPostgres()
+ * die() preforms an orderly cleanup via ExitPostgres()
* --------------------------------
*/
void
handle_warn(SIGNAL_ARGS)
{
- siglongjmp(Warn_restart, 1);
+ siglongjmp(Warn_restart, 1);
}
static void
quickdie(SIGNAL_ARGS)
{
- elog(NOTICE, "I have been signalled by the postmaster.");
- elog(NOTICE, "Some backend process has died unexpectedly and possibly");
- elog(NOTICE, "corrupted shared memory. The current transaction was");
- elog(NOTICE, "aborted, and I am going to exit. Please resend the");
- elog(NOTICE, "last query. -- The postgres backend");
-
- /*
- * DO NOT ExitPostgres(0) -- we're here because shared memory may be
- * corrupted, so we don't want to flush any shared state to stable
- * storage. Just nail the windows shut and get out of town.
- */
-
- exit (0);
+ elog(NOTICE, "I have been signalled by the postmaster.");
+ elog(NOTICE, "Some backend process has died unexpectedly and possibly");
+ elog(NOTICE, "corrupted shared memory. The current transaction was");
+ elog(NOTICE, "aborted, and I am going to exit. Please resend the");
+ elog(NOTICE, "last query. -- The postgres backend");
+
+ /*
+ * DO NOT ExitPostgres(0) -- we're here because shared memory may be
+ * corrupted, so we don't want to flush any shared state to stable
+ * storage. Just nail the windows shut and get out of town.
+ */
+
+ exit(0);
}
void
die(SIGNAL_ARGS)
{
- ExitPostgres(0);
+ ExitPostgres(0);
}
/* signal handler for floating point exception */
static void
FloatExceptionHandler(SIGNAL_ARGS)
{
- elog(WARN, "floating point exception! the last floating point operation eit\
+ elog(WARN, "floating point exception! the last floating point operation eit\
her exceeded legal ranges or was a divide by zero");
}
-static void usage(char* progname)
+static void
+usage(char *progname)
{
- fprintf(stderr,
- "Usage: %s [-B nbufs] [-d lvl] ] [-f plantype] \t[-m portno] [\t -o filename]\n",
- progname);
- fprintf(stderr,"\t[-P portno] [-t tracetype] [-x opttype] [-bCEiLFNopQSs] [dbname]\n");
- fprintf(stderr, " b: consider bushy plan trees during optimization\n");
- fprintf(stderr, " B: set number of buffers in buffer pool\n");
- fprintf(stderr, " C: supress version info\n");
- fprintf(stderr, " d: set debug level\n");
- fprintf(stderr, " E: echo query before execution\n");
- fprintf(stderr, " e turn on European date format\n");
- fprintf(stderr, " F: turn off fsync\n");
- fprintf(stderr, " f: forbid plantype generation\n");
- fprintf(stderr, " i: don't execute the query, just show the plan tree\n");
+ fprintf(stderr,
+ "Usage: %s [-B nbufs] [-d lvl] ] [-f plantype] \t[-m portno] [\t -o filename]\n",
+ progname);
+ fprintf(stderr, "\t[-P portno] [-t tracetype] [-x opttype] [-bCEiLFNopQSs] [dbname]\n");
+ fprintf(stderr, " b: consider bushy plan trees during optimization\n");
+ fprintf(stderr, " B: set number of buffers in buffer pool\n");
+ fprintf(stderr, " C: supress version info\n");
+ fprintf(stderr, " d: set debug level\n");
+ fprintf(stderr, " E: echo query before execution\n");
+ fprintf(stderr, " e turn on European date format\n");
+ fprintf(stderr, " F: turn off fsync\n");
+ fprintf(stderr, " f: forbid plantype generation\n");
+ fprintf(stderr, " i: don't execute the query, just show the plan tree\n");
#ifdef LOCK_MGR_DEBUG
- fprintf(stderr, " K: set locking debug level [0|1|2]\n");
+ fprintf(stderr, " K: set locking debug level [0|1|2]\n");
#endif
- fprintf(stderr, " L: turn off locking\n");
- fprintf(stderr, " m: set up a listening backend at portno to support multiple front-ends\n");
- fprintf(stderr, " M: start as postmaster\n");
- fprintf(stderr, " N: don't use newline as query delimiter\n");
- fprintf(stderr, " o: send stdout and stderr to given filename \n");
- fprintf(stderr, " p: backend started by postmaster\n");
- fprintf(stderr, " P: set port file descriptor\n");
- fprintf(stderr, " Q: suppress informational messages\n");
- fprintf(stderr, " S: set amount of sort memory available\n");
- fprintf(stderr, " s: show stats after each query\n");
- fprintf(stderr, " t: trace component execution times\n");
- fprintf(stderr, " T: execute all possible plans for each query\n");
- fprintf(stderr, " x: control expensive function optimization\n");
+ fprintf(stderr, " L: turn off locking\n");
+ fprintf(stderr, " m: set up a listening backend at portno to support multiple front-ends\n");
+ fprintf(stderr, " M: start as postmaster\n");
+ fprintf(stderr, " N: don't use newline as query delimiter\n");
+ fprintf(stderr, " o: send stdout and stderr to given filename \n");
+ fprintf(stderr, " p: backend started by postmaster\n");
+ fprintf(stderr, " P: set port file descriptor\n");
+ fprintf(stderr, " Q: suppress informational messages\n");
+ fprintf(stderr, " S: set amount of sort memory available\n");
+ fprintf(stderr, " s: show stats after each query\n");
+ fprintf(stderr, " t: trace component execution times\n");
+ fprintf(stderr, " T: execute all possible plans for each query\n");
+ fprintf(stderr, " x: control expensive function optimization\n");
}
/* ----------------------------------------------------------------
- * PostgresMain
- * postgres main loop
- * all backends, interactive or otherwise start here
+ * PostgresMain
+ * postgres main loop
+ * all backends, interactive or otherwise start here
* ----------------------------------------------------------------
*/
int
PostgresMain(int argc, char *argv[])
{
- int flagC;
- int flagQ;
- int flagE;
- int flagEu;
- int flag;
-
- char *DBName = NULL;
- int errs = 0;
-
- char firstchar;
- char parser_input[MAX_PARSE_BUFFER];
- char *userName;
-
- bool multiplexedBackend;
- char* hostName; /* the host name of the backend server */
- char hostbuf[MAXHOSTNAMELEN];
- int serverSock;
- int serverPortnum = 0;
- int nSelected; /* number of descriptors ready from select(); */
- int maxFd = 0; /* max file descriptor + 1 */
- fd_set rmask, basemask;
- FrontEnd *newFE, *currentFE = NULL;
- int numFE = 0; /* keep track of number of active frontends */
- Port *newPort;
- int newFd;
- Dlelem *curr;
- int status;
-
- extern int optind;
- extern char *optarg;
- extern short DebugLvl;
-
- /* ----------------
- * register signal handlers.
- * ----------------
- */
- pqsignal(SIGINT, die);
-
- pqsignal(SIGHUP, die);
- pqsignal(SIGTERM, die);
- pqsignal(SIGPIPE, die);
- pqsignal(SIGUSR1, quickdie);
- pqsignal(SIGUSR2, Async_NotifyHandler);
- pqsignal(SIGFPE, FloatExceptionHandler);
-
- /* --------------------
- * initialize globals
- * -------------------
- */
-
- MasterPid = getpid();
-
- /* ----------------
- * parse command line arguments
- * ----------------
- */
- flagC = flagQ = flagE = flagEu = ShowStats = 0;
- ShowParserStats = ShowPlannerStats = ShowExecutorStats = 0;
+ int flagC;
+ int flagQ;
+ int flagE;
+ int flagEu;
+ int flag;
+
+ char *DBName = NULL;
+ int errs = 0;
+
+ char firstchar;
+ char parser_input[MAX_PARSE_BUFFER];
+ char *userName;
+
+ bool multiplexedBackend;
+ char *hostName; /* the host name of the backend server */
+ char hostbuf[MAXHOSTNAMELEN];
+ int serverSock;
+ int serverPortnum = 0;
+ int nSelected; /* number of descriptors ready from
+ * select(); */
+ int maxFd = 0; /* max file descriptor + 1 */
+ fd_set rmask,
+ basemask;
+ FrontEnd *newFE,
+ *currentFE = NULL;
+ int numFE = 0; /* keep track of number of active
+ * frontends */
+ Port *newPort;
+ int newFd;
+ Dlelem *curr;
+ int status;
+
+ extern int optind;
+ extern char *optarg;
+ extern short DebugLvl;
+
+ /* ----------------
+ * register signal handlers.
+ * ----------------
+ */
+ pqsignal(SIGINT, die);
+
+ pqsignal(SIGHUP, die);
+ pqsignal(SIGTERM, die);
+ pqsignal(SIGPIPE, die);
+ pqsignal(SIGUSR1, quickdie);
+ pqsignal(SIGUSR2, Async_NotifyHandler);
+ pqsignal(SIGFPE, FloatExceptionHandler);
+
+ /* --------------------
+ * initialize globals
+ * -------------------
+ */
+
+ MasterPid = getpid();
+
+ /* ----------------
+ * parse command line arguments
+ * ----------------
+ */
+ flagC = flagQ = flagE = flagEu = ShowStats = 0;
+ ShowParserStats = ShowPlannerStats = ShowExecutorStats = 0;
#ifdef LOCK_MGR_DEBUG
- lockDebug = 0;
+ lockDebug = 0;
#endif
- /* get hostname is either the environment variable PGHOST
- or 'localhost' */
- if (!(hostName = getenv("PGHOST"))) {
- if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
- strcpy(hostbuf, "localhost");
- hostName = hostbuf;
- }
-
- DataDir = getenv("PGDATA"); /* default */
- multiplexedBackend = false; /* default */
-
- while ((flag = getopt(argc, argv, "B:bCD:d:Eef:iK:Lm:MNo:P:pQSst:x:F"))
- != EOF)
- switch (flag) {
-
- case 'b':
- /* ----------------
- * set BushyPlanFlag to true.
- * ----------------
- */
- BushyPlanFlag = 1;
- break;
- case 'B':
- /* ----------------
- * specify the size of buffer pool
- * ----------------
- */
- NBuffers = atoi(optarg);
- break;
-
- case 'C':
- /* ----------------
- * don't print version string (don't know why this is 'C' --mao)
- * ----------------
- */
- flagC = 1;
- break;
-
- case 'D': /* PGDATA directory */
- DataDir = optarg;
-
- case 'd': /* debug level */
- flagQ = 0;
- DebugLvl = (short)atoi(optarg);
- if (DebugLvl > 1)
- DebugPrintQuery = true;
- if (DebugLvl > 2)
- {
- DebugPrintParse = true;
- DebugPrintPlan = true;
- DebugPrintRewrittenParsetree = true;
- }
- break;
-
- case 'E':
- /* ----------------
- * E - echo the query the user entered
- * ----------------
- */
- flagE = 1;
- break;
-
- case 'e':
- /* --------------------------
- * Use european date formats.
- * --------------------------
- */
- flagEu = 1;
- break;
-
- case 'F':
- /* --------------------
- * turn off fsync
- * --------------------
- */
- fsyncOff = 1;
- break;
-
- case 'f':
- /* -----------------
- * f - forbid generation of certain plans
- * -----------------
- */
- switch (optarg[0]) {
- case 's': /* seqscan */
- _enable_seqscan_ = false;
- break;
- case 'i': /* indexscan */
- _enable_indexscan_ = false;
- break;
- case 'n': /* nestloop */
- _enable_nestloop_ = false;
- break;
- case 'm': /* mergejoin */
- _enable_mergesort_ = false;
- break;
- case 'h': /* hashjoin */
- _enable_hashjoin_ = false;
- break;
- default:
- errs++;
- }
- break;
-
- case 'i':
- dontExecute = 1;
- break;
-
- case 'K':
+ /*
+ * get hostname is either the environment variable PGHOST or
+ * 'localhost'
+ */
+ if (!(hostName = getenv("PGHOST")))
+ {
+ if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
+ strcpy(hostbuf, "localhost");
+ hostName = hostbuf;
+ }
+
+ DataDir = getenv("PGDATA"); /* default */
+ multiplexedBackend = false; /* default */
+
+ while ((flag = getopt(argc, argv, "B:bCD:d:Eef:iK:Lm:MNo:P:pQSst:x:F"))
+ != EOF)
+ switch (flag)
+ {
+
+ case 'b':
+ /* ----------------
+ * set BushyPlanFlag to true.
+ * ----------------
+ */
+ BushyPlanFlag = 1;
+ break;
+ case 'B':
+ /* ----------------
+ * specify the size of buffer pool
+ * ----------------
+ */
+ NBuffers = atoi(optarg);
+ break;
+
+ case 'C':
+ /* ----------------
+ * don't print version string (don't know why this is 'C' --mao)
+ * ----------------
+ */
+ flagC = 1;
+ break;
+
+ case 'D': /* PGDATA directory */
+ DataDir = optarg;
+
+ case 'd': /* debug level */
+ flagQ = 0;
+ DebugLvl = (short) atoi(optarg);
+ if (DebugLvl > 1)
+ DebugPrintQuery = true;
+ if (DebugLvl > 2)
+ {
+ DebugPrintParse = true;
+ DebugPrintPlan = true;
+ DebugPrintRewrittenParsetree = true;
+ }
+ break;
+
+ case 'E':
+ /* ----------------
+ * E - echo the query the user entered
+ * ----------------
+ */
+ flagE = 1;
+ break;
+
+ case 'e':
+ /* --------------------------
+ * Use european date formats.
+ * --------------------------
+ */
+ flagEu = 1;
+ break;
+
+ case 'F':
+ /* --------------------
+ * turn off fsync
+ * --------------------
+ */
+ fsyncOff = 1;
+ break;
+
+ case 'f':
+ /* -----------------
+ * f - forbid generation of certain plans
+ * -----------------
+ */
+ switch (optarg[0])
+ {
+ case 's': /* seqscan */
+ _enable_seqscan_ = false;
+ break;
+ case 'i': /* indexscan */
+ _enable_indexscan_ = false;
+ break;
+ case 'n': /* nestloop */
+ _enable_nestloop_ = false;
+ break;
+ case 'm': /* mergejoin */
+ _enable_mergesort_ = false;
+ break;
+ case 'h': /* hashjoin */
+ _enable_hashjoin_ = false;
+ break;
+ default:
+ errs++;
+ }
+ break;
+
+ case 'i':
+ dontExecute = 1;
+ break;
+
+ case 'K':
#ifdef LOCK_MGR_DEBUG
- lockDebug = atoi(optarg);
+ lockDebug = atoi(optarg);
#else
- fprintf(stderr, "Lock debug not compiled in\n");
+ fprintf(stderr, "Lock debug not compiled in\n");
#endif
- break;
-
- case 'L':
- /* --------------------
- * turn off locking
- * --------------------
- */
- lockingOff = 1;
- break;
-
- case 'm':
- /* start up a listening backend that can respond to
- multiple front-ends. (Note: all the front-end connections
- are still connected to a single-threaded backend. Requests
- are FCFS. Everything is in one transaction
- */
- multiplexedBackend = true;
- serverPortnum = atoi(optarg);
- break;
- case 'M':
- exit(PostmasterMain(argc, argv));
- break;
- case 'N':
- /* ----------------
- * N - Don't use newline as a query delimiter
- * ----------------
- */
- UseNewLine = 0;
- break;
-
- case 'o':
- /* ----------------
- * o - send output (stdout and stderr) to the given file
- * ----------------
- */
- strNcpy(OutputFileName, optarg, MAXPGPATH);
- break;
-
- case 'p': /* started by postmaster */
- /* ----------------
- * p - special flag passed if backend was forked
- * by a postmaster.
- * ----------------
- */
- IsUnderPostmaster = true;
- break;
-
- case 'P':
- /* ----------------
- * P - Use the passed file descriptor number as the port
- * on which to communicate with the user. This is ONLY
- * useful for debugging when fired up by the postmaster.
- * ----------------
- */
- Portfd = atoi(optarg);
- break;
-
- case 'Q':
- /* ----------------
- * Q - set Quiet mode (reduce debugging output)
- * ----------------
- */
- flagQ = 1;
- break;
-
- case 'S':
- /* ----------------
- * S - amount of sort memory to use in 1k bytes
- * ----------------
- */
- SortMem = atoi(optarg);
- break;
-
- case 's':
- /* ----------------
- * s - report usage statistics (timings) after each query
- * ----------------
- */
- ShowStats = 1;
- StatFp = stderr;
- break;
-
- case 't':
- /* ----------------
- * tell postgres to report usage statistics (timings) for
- * each query
- *
- * -tpa[rser] = print stats for parser time of each query
- * -tpl[anner] = print stats for planner time of each query
- * -te[xecutor] = print stats for executor time of each query
- * caution: -s can not be used together with -t.
- * ----------------
- */
- StatFp = stderr;
- switch (optarg[0]) {
- case 'p': if (optarg[1] == 'a')
- ShowParserStats = 1;
- else if (optarg[1] == 'l')
- ShowPlannerStats = 1;
- else
- errs++;
- break;
- case 'e': ShowExecutorStats = 1; break;
- default: errs++; break;
- }
- break;
-
- case 'x':
-#if 0 /* planner/xfunc.h */
- /* control joey hellerstein's expensive function optimization */
- if (XfuncMode != 0)
- {
- fprintf(stderr, "only one -x flag is allowed\n");
- errs++;
- break;
- }
- if (strcmp(optarg, "off") == 0)
- XfuncMode = XFUNC_OFF;
- else if (strcmp(optarg, "nor") == 0)
- XfuncMode = XFUNC_NOR;
- else if (strcmp(optarg, "nopull") == 0)
- XfuncMode = XFUNC_NOPULL;
- else if (strcmp(optarg, "nopm") == 0)
- XfuncMode = XFUNC_NOPM;
- else if (strcmp(optarg, "pullall") == 0)
- XfuncMode = XFUNC_PULLALL;
- else if (strcmp(optarg, "wait") == 0)
- XfuncMode = XFUNC_WAIT;
- else {
- fprintf(stderr, "use -x {off,nor,nopull,nopm,pullall,wait}\n");
- errs++;
- }
+ break;
+
+ case 'L':
+ /* --------------------
+ * turn off locking
+ * --------------------
+ */
+ lockingOff = 1;
+ break;
+
+ case 'm':
+
+ /*
+ * start up a listening backend that can respond to multiple
+ * front-ends. (Note: all the front-end connections are
+ * still connected to a single-threaded backend. Requests are
+ * FCFS. Everything is in one transaction
+ */
+ multiplexedBackend = true;
+ serverPortnum = atoi(optarg);
+ break;
+ case 'M':
+ exit(PostmasterMain(argc, argv));
+ break;
+ case 'N':
+ /* ----------------
+ * N - Don't use newline as a query delimiter
+ * ----------------
+ */
+ UseNewLine = 0;
+ break;
+
+ case 'o':
+ /* ----------------
+ * o - send output (stdout and stderr) to the given file
+ * ----------------
+ */
+ strNcpy(OutputFileName, optarg, MAXPGPATH);
+ break;
+
+ case 'p': /* started by postmaster */
+ /* ----------------
+ * p - special flag passed if backend was forked
+ * by a postmaster.
+ * ----------------
+ */
+ IsUnderPostmaster = true;
+ break;
+
+ case 'P':
+ /* ----------------
+ * P - Use the passed file descriptor number as the port
+ * on which to communicate with the user. This is ONLY
+ * useful for debugging when fired up by the postmaster.
+ * ----------------
+ */
+ Portfd = atoi(optarg);
+ break;
+
+ case 'Q':
+ /* ----------------
+ * Q - set Quiet mode (reduce debugging output)
+ * ----------------
+ */
+ flagQ = 1;
+ break;
+
+ case 'S':
+ /* ----------------
+ * S - amount of sort memory to use in 1k bytes
+ * ----------------
+ */
+ SortMem = atoi(optarg);
+ break;
+
+ case 's':
+ /* ----------------
+ * s - report usage statistics (timings) after each query
+ * ----------------
+ */
+ ShowStats = 1;
+ StatFp = stderr;
+ break;
+
+ case 't':
+ /* ----------------
+ * tell postgres to report usage statistics (timings) for
+ * each query
+ *
+ * -tpa[rser] = print stats for parser time of each query
+ * -tpl[anner] = print stats for planner time of each query
+ * -te[xecutor] = print stats for executor time of each query
+ * caution: -s can not be used together with -t.
+ * ----------------
+ */
+ StatFp = stderr;
+ switch (optarg[0])
+ {
+ case 'p':
+ if (optarg[1] == 'a')
+ ShowParserStats = 1;
+ else if (optarg[1] == 'l')
+ ShowPlannerStats = 1;
+ else
+ errs++;
+ break;
+ case 'e':
+ ShowExecutorStats = 1;
+ break;
+ default:
+ errs++;
+ break;
+ }
+ break;
+
+ case 'x':
+#if 0 /* planner/xfunc.h */
+ /* control joey hellerstein's expensive function optimization */
+ if (XfuncMode != 0)
+ {
+ fprintf(stderr, "only one -x flag is allowed\n");
+ errs++;
+ break;
+ }
+ if (strcmp(optarg, "off") == 0)
+ XfuncMode = XFUNC_OFF;
+ else if (strcmp(optarg, "nor") == 0)
+ XfuncMode = XFUNC_NOR;
+ else if (strcmp(optarg, "nopull") == 0)
+ XfuncMode = XFUNC_NOPULL;
+ else if (strcmp(optarg, "nopm") == 0)
+ XfuncMode = XFUNC_NOPM;
+ else if (strcmp(optarg, "pullall") == 0)
+ XfuncMode = XFUNC_PULLALL;
+ else if (strcmp(optarg, "wait") == 0)
+ XfuncMode = XFUNC_WAIT;
+ else
+ {
+ fprintf(stderr, "use -x {off,nor,nopull,nopm,pullall,wait}\n");
+ errs++;
+ }
#endif
- break;
-
- default:
- /* ----------------
- * default: bad command line option
- * ----------------
- */
- errs++;
- }
-
- /* ----------------
- * get user name and pathname and check command line validity
- * ----------------
- */
- SetPgUserName();
- userName = GetPgUserName();
-
- if (FindBackend(pg_pathname, argv[0]) < 0)
- elog(FATAL, "%s: could not locate executable, bailing out...",
- argv[0]);
-
- if (errs || argc - optind > 1) {
- usage (argv[0]);
- exitpg(1);
- } else if (argc - optind == 1) {
- DBName = argv[optind];
- } else if ((DBName = userName) == NULL) {
- fprintf(stderr, "%s: USER undefined and no database specified\n",
- argv[0]);
- exitpg(1);
- }
-
- if (ShowStats &&
- (ShowParserStats || ShowPlannerStats || ShowExecutorStats)) {
- fprintf(stderr, "-s can not be used together with -t.\n");
- exitpg(1);
- }
-
- if (!DataDir) {
- fprintf(stderr, "%s does not know where to find the database system "
- "data. You must specify the directory that contains the "
- "database system either by specifying the -D invocation "
- "option or by setting the PGDATA environment variable.\n\n",
- argv[0]);
- exitpg(1);
- }
-
- Noversion = flagC;
- Quiet = flagQ;
- EchoQuery = flagE;
- EuroDates = flagEu;
-
- /* ----------------
- * print flags
- * ----------------
- */
- if (! Quiet) {
- puts("\t---debug info---");
- printf("\tQuiet = %c\n", Quiet ? 't' : 'f');
- printf("\tNoversion = %c\n", Noversion ? 't' : 'f');
- printf("\ttimings = %c\n", ShowStats ? 't' : 'f');
- printf("\tdates = %s\n", EuroDates ? "European" : "Normal");
- printf("\tbufsize = %d\n", NBuffers);
- printf("\tsortmem = %d\n", SortMem);
-
- printf("\tquery echo = %c\n", EchoQuery ? 't' : 'f');
- printf("\tmultiplexed backend? = %c\n", multiplexedBackend ? 't' : 'f');
- printf("\tDatabaseName = [%s]\n", DBName);
- puts("\t----------------\n");
- }
-
- /* ----------------
- * initialize portal file descriptors
- * ----------------
- */
- if (IsUnderPostmaster == true) {
- if (Portfd < 0) {
- fprintf(stderr,
- "Postmaster flag set: no port number specified, use /dev/null\n");
- Portfd = open(NULL_DEV, O_RDWR, 0666);
- }
- pq_init(Portfd);
- }
-
- if (multiplexedBackend) {
- if (serverPortnum == 0 ||
- StreamServerPort(hostName, serverPortnum, &serverSock) != STATUS_OK)
- {
- fprintf(stderr, "Postgres: cannot create stream port %d\n", serverPortnum);
- exit(1);
- }
+ break;
+
+ default:
+ /* ----------------
+ * default: bad command line option
+ * ----------------
+ */
+ errs++;
+ }
+
+ /* ----------------
+ * get user name and pathname and check command line validity
+ * ----------------
+ */
+ SetPgUserName();
+ userName = GetPgUserName();
+
+ if (FindBackend(pg_pathname, argv[0]) < 0)
+ elog(FATAL, "%s: could not locate executable, bailing out...",
+ argv[0]);
+
+ if (errs || argc - optind > 1)
+ {
+ usage(argv[0]);
+ exitpg(1);
+ }
+ else if (argc - optind == 1)
+ {
+ DBName = argv[optind];
+ }
+ else if ((DBName = userName) == NULL)
+ {
+ fprintf(stderr, "%s: USER undefined and no database specified\n",
+ argv[0]);
+ exitpg(1);
+ }
+
+ if (ShowStats &&
+ (ShowParserStats || ShowPlannerStats || ShowExecutorStats))
+ {
+ fprintf(stderr, "-s can not be used together with -t.\n");
+ exitpg(1);
+ }
+
+ if (!DataDir)
+ {
+ fprintf(stderr, "%s does not know where to find the database system "
+ "data. You must specify the directory that contains the "
+ "database system either by specifying the -D invocation "
+ "option or by setting the PGDATA environment variable.\n\n",
+ argv[0]);
+ exitpg(1);
+ }
+
+ Noversion = flagC;
+ Quiet = flagQ;
+ EchoQuery = flagE;
+ EuroDates = flagEu;
+
+ /* ----------------
+ * print flags
+ * ----------------
+ */
+ if (!Quiet)
+ {
+ puts("\t---debug info---");
+ printf("\tQuiet = %c\n", Quiet ? 't' : 'f');
+ printf("\tNoversion = %c\n", Noversion ? 't' : 'f');
+ printf("\ttimings = %c\n", ShowStats ? 't' : 'f');
+ printf("\tdates = %s\n", EuroDates ? "European" : "Normal");
+ printf("\tbufsize = %d\n", NBuffers);
+ printf("\tsortmem = %d\n", SortMem);
+
+ printf("\tquery echo = %c\n", EchoQuery ? 't' : 'f');
+ printf("\tmultiplexed backend? = %c\n", multiplexedBackend ? 't' : 'f');
+ printf("\tDatabaseName = [%s]\n", DBName);
+ puts("\t----------------\n");
+ }
+
+ /* ----------------
+ * initialize portal file descriptors
+ * ----------------
+ */
+ if (IsUnderPostmaster == true)
+ {
+ if (Portfd < 0)
+ {
+ fprintf(stderr,
+ "Postmaster flag set: no port number specified, use /dev/null\n");
+ Portfd = open(NULL_DEV, O_RDWR, 0666);
+ }
+ pq_init(Portfd);
+ }
+
+ if (multiplexedBackend)
+ {
+ if (serverPortnum == 0 ||
+ StreamServerPort(hostName, serverPortnum, &serverSock) != STATUS_OK)
+ {
+ fprintf(stderr, "Postgres: cannot create stream port %d\n", serverPortnum);
+ exit(1);
+ }
/*
{
- char buf[100];
- sprintf(buf, "stream port %d created, socket = %d\n", serverPortnum, serverSock);
- puts(buf);
+ char buf[100];
+ sprintf(buf, "stream port %d created, socket = %d\n", serverPortnum, serverSock);
+ puts(buf);
}
*/
- FD_ZERO(&rmask);
- FD_ZERO(&basemask);
- FD_SET(serverSock, &basemask);
-
- frontendList = DLNewList();
- /* add the original FrontEnd to the list */
- if (IsUnderPostmaster == true) {
- FrontEnd *fe = malloc(sizeof(FrontEnd));
-
- FD_SET(Portfd, &basemask);
- maxFd = Max(serverSock,Portfd) + 1;
-
- fe->fn_connected = true;
- fe->fn_Pfin = Pfin;
- fe->fn_Pfout = Pfout;
- fe->fn_done = false;
- (fe->fn_port).sock = Portfd;
- DLAddHead(frontendList, DLNewElem(fe));
- numFE++;
- } else {
- numFE = 1;
- maxFd = serverSock + 1;
- }
- }
-
- if (IsUnderPostmaster || multiplexedBackend)
- whereToSendOutput = Remote;
- else
- whereToSendOutput = Debug;
-
- SetProcessingMode(InitProcessing);
-
- /* initialize */
- if (! Quiet) {
- puts("\tInitPostgres()..");
- }
-
- InitPostgres(DBName);
-
- /* ----------------
- * if an exception is encountered, processing resumes here
- * so we abort the current transaction and start a new one.
- * This must be done after we initialize the slave backends
- * so that the slaves signal the master to abort the transaction
- * rather than calling AbortCurrentTransaction() themselves.
- *
- * Note: elog(WARN) causes a kill(getpid(),1) to occur sending
- * us back here.
- * ----------------
- */
-
- pqsignal(SIGHUP, handle_warn);
-
- if (sigsetjmp(Warn_restart, 1) != 0) {
- InWarn = 1;
-
- time(&tim);
-
- if (! Quiet)
- printf("\tAbortCurrentTransaction() at %s\n", ctime(&tim));
-
- memset(parser_input, 0, MAX_PARSE_BUFFER);
-
- AbortCurrentTransaction();
- }
- InWarn = 0;
-
- /* ----------------
- * POSTGRES main processing loop begins here
- * ----------------
- */
- if (IsUnderPostmaster == false) {
- puts("\nPOSTGRES backend interactive interface");
- puts("$Revision: 1.42 $ $Date: 1997/08/19 21:34:04 $");
- }
-
- /* ----------------
- * if stable main memory is assumed (-S(old) flag is set), it is necessary
- * to flush all dirty shared buffers before exit
- * plai 8/7/90
- * ----------------
- */
- if (!TransactionFlushEnabled())
- on_exitpg(FlushBufferPool, (caddr_t) 0);
-
- for (;;) {
-
- if (multiplexedBackend) {
- if (numFE == 0)
- break;
-
- memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
- nSelected = select(maxFd, &rmask,0,0,0);
-
- if (nSelected < 0) {
-
- if (errno == EINTR) continue;
- fprintf(stderr,"postgres: multiplexed backend select failed\n");
- exitpg(1);
- }
- if (FD_ISSET(serverSock, &rmask)) {
- /* new connection pending on our well-known port's socket */
- newFE = (FrontEnd*) malloc (sizeof(FrontEnd));
- memset(newFE, 0, sizeof(FrontEnd));
- newFE->fn_connected = false;
- newFE->fn_done = false;
- newPort = &(newFE->fn_port);
- if (StreamConnection(serverSock,newPort) != STATUS_OK) {
- StreamClose(newPort->sock);
- newFd = -1;
- }
- else {
- DLAddHead(frontendList, DLNewElem(newFE));
- numFE++;
- newFd = newPort->sock;
- if (newFd >= maxFd) maxFd = newFd + 1;
- FD_SET(newFd, &rmask);
- FD_SET(newFd, &basemask);
- --nSelected;
- FD_CLR(serverSock, &rmask);
- }
- continue;
- } /* if FD_ISSET(serverSock) */
-
- /* if we get here, it means that the serverSocket was not the one
- selected. Instead, one of the front ends was selected.
- find which one */
- curr = DLGetHead(frontendList);
- while (curr) {
- FrontEnd *fe = (FrontEnd*)DLE_VAL(curr);
- Port *port = &(fe->fn_port);
-
- /* this is lifted from postmaster.c */
- if (FD_ISSET(port->sock, &rmask)) {
- if (fe->fn_connected == false) {
- /* we have a message from a new frontEnd */
- status = PacketReceive(port, &port->buf, NON_BLOCKING);
- if (status == STATUS_OK) {
- fe->fn_connected = true;
- pq_init(port->sock);
- fe->fn_Pfin = Pfin;
- fe->fn_Pfout = Pfout;
- }
- else
- fprintf(stderr,"Multiplexed backend: error in reading packets from %d\n", port->sock);
- }
- else /* we have a query from an existing, active FrontEnd */
- {
- Pfin = fe->fn_Pfin;
- Pfout = fe->fn_Pfout;
- currentFE = fe;
- }
- if (fe->fn_done)
- {
- Dlelem *c = curr;
- curr = DLGetSucc(curr);
- DLRemove(c);
- }
- break;
- }
- else
- curr = DLGetSucc(curr);
- }
- }
- /* ----------------
- * (1) read a command.
- * ----------------
- */
- memset(parser_input, 0, MAX_PARSE_BUFFER);
-
- firstchar = ReadCommand(parser_input, multiplexedBackend);
- /* process the command */
- switch (firstchar) {
- /* ----------------
- * 'F' indicates a fastpath call.
- * XXX HandleFunctionRequest
- * ----------------
- */
- case 'F':
- IsEmptyQuery = false;
-
- /* start an xact for this function invocation */
- if (! Quiet) {
- time(&tim);
- printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
- }
-
- StartTransactionCommand();
- HandleFunctionRequest();
- break;
-
- /* ----------------
- * 'Q' indicates a user query
- * ----------------
- */
- case 'Q':
- fflush(stdout);
-
- if ( strspn(parser_input," \t\n") == strlen(parser_input)) {
- /* ----------------
- * if there is nothing in the input buffer, don't bother
- * trying to parse and execute anything..
- * ----------------
- */
- IsEmptyQuery = true;
- } else {
- /* ----------------
- * otherwise, process the input string.
- * ----------------
- */
- IsEmptyQuery = false;
- if (ShowStats)
- ResetUsage();
-
- /* start an xact for this query */
- if (! Quiet) {
- time(&tim);
- printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
- }
- StartTransactionCommand();
-
- pg_eval(parser_input, (char **) NULL, (Oid *) NULL, 0);
-
- if (ShowStats)
- ShowUsage();
- }
- break;
-
- /* ----------------
- * 'X' means that the frontend is closing down the socket
- * ----------------
- */
- case 'X':
- IsEmptyQuery = true;
- if (multiplexedBackend) {
- FD_CLR(currentFE->fn_port.sock, &basemask);
- currentFE->fn_done = true;
- numFE--;
- }
- pq_close();
- break;
-
- default:
- elog(WARN,"unknown frontend message was recieved");
- }
-
- /* ----------------
- * (3) commit the current transaction
- *
- * Note: if we had an empty input buffer, then we didn't
- * call pg_eval, so we don't bother to commit this transaction.
- * ----------------
- */
- if (! IsEmptyQuery) {
- if (! Quiet) {
- time(&tim);
- printf("\tCommitTransactionCommand() at %s\n", ctime(&tim));
- }
- CommitTransactionCommand();
-
- } else {
- if (IsUnderPostmaster || multiplexedBackend)
- NullCommand(Remote);
- }
-
-} /* infinite for-loop */
- exitpg(0);
- return 1;
+ FD_ZERO(&rmask);
+ FD_ZERO(&basemask);
+ FD_SET(serverSock, &basemask);
+
+ frontendList = DLNewList();
+ /* add the original FrontEnd to the list */
+ if (IsUnderPostmaster == true)
+ {
+ FrontEnd *fe = malloc(sizeof(FrontEnd));
+
+ FD_SET(Portfd, &basemask);
+ maxFd = Max(serverSock, Portfd) + 1;
+
+ fe->fn_connected = true;
+ fe->fn_Pfin = Pfin;
+ fe->fn_Pfout = Pfout;
+ fe->fn_done = false;
+ (fe->fn_port).sock = Portfd;
+ DLAddHead(frontendList, DLNewElem(fe));
+ numFE++;
+ }
+ else
+ {
+ numFE = 1;
+ maxFd = serverSock + 1;
+ }
+ }
+
+ if (IsUnderPostmaster || multiplexedBackend)
+ whereToSendOutput = Remote;
+ else
+ whereToSendOutput = Debug;
+
+ SetProcessingMode(InitProcessing);
+
+ /* initialize */
+ if (!Quiet)
+ {
+ puts("\tInitPostgres()..");
+ }
+
+ InitPostgres(DBName);
+
+ /* ----------------
+ * if an exception is encountered, processing resumes here
+ * so we abort the current transaction and start a new one.
+ * This must be done after we initialize the slave backends
+ * so that the slaves signal the master to abort the transaction
+ * rather than calling AbortCurrentTransaction() themselves.
+ *
+ * Note: elog(WARN) causes a kill(getpid(),1) to occur sending
+ * us back here.
+ * ----------------
+ */
+
+ pqsignal(SIGHUP, handle_warn);
+
+ if (sigsetjmp(Warn_restart, 1) != 0)
+ {
+ InWarn = 1;
+
+ time(&tim);
+
+ if (!Quiet)
+ printf("\tAbortCurrentTransaction() at %s\n", ctime(&tim));
+
+ memset(parser_input, 0, MAX_PARSE_BUFFER);
+
+ AbortCurrentTransaction();
+ }
+ InWarn = 0;
+
+ /* ----------------
+ * POSTGRES main processing loop begins here
+ * ----------------
+ */
+ if (IsUnderPostmaster == false)
+ {
+ puts("\nPOSTGRES backend interactive interface");
+ puts("$Revision: 1.43 $ $Date: 1997/09/07 04:49:33 $");
+ }
+
+ /* ----------------
+ * if stable main memory is assumed (-S(old) flag is set), it is necessary
+ * to flush all dirty shared buffers before exit
+ * plai 8/7/90
+ * ----------------
+ */
+ if (!TransactionFlushEnabled())
+ on_exitpg(FlushBufferPool, (caddr_t) 0);
+
+ for (;;)
+ {
+
+ if (multiplexedBackend)
+ {
+ if (numFE == 0)
+ break;
+
+ memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
+ nSelected = select(maxFd, &rmask, 0, 0, 0);
+
+ if (nSelected < 0)
+ {
+
+ if (errno == EINTR)
+ continue;
+ fprintf(stderr, "postgres: multiplexed backend select failed\n");
+ exitpg(1);
+ }
+ if (FD_ISSET(serverSock, &rmask))
+ {
+ /* new connection pending on our well-known port's socket */
+ newFE = (FrontEnd *) malloc(sizeof(FrontEnd));
+ memset(newFE, 0, sizeof(FrontEnd));
+ newFE->fn_connected = false;
+ newFE->fn_done = false;
+ newPort = &(newFE->fn_port);
+ if (StreamConnection(serverSock, newPort) != STATUS_OK)
+ {
+ StreamClose(newPort->sock);
+ newFd = -1;
+ }
+ else
+ {
+ DLAddHead(frontendList, DLNewElem(newFE));
+ numFE++;
+ newFd = newPort->sock;
+ if (newFd >= maxFd)
+ maxFd = newFd + 1;
+ FD_SET(newFd, &rmask);
+ FD_SET(newFd, &basemask);
+ --nSelected;
+ FD_CLR(serverSock, &rmask);
+ }
+ continue;
+ } /* if FD_ISSET(serverSock) */
+
+ /*
+ * if we get here, it means that the serverSocket was not the
+ * one selected. Instead, one of the front ends was selected.
+ * find which one
+ */
+ curr = DLGetHead(frontendList);
+ while (curr)
+ {
+ FrontEnd *fe = (FrontEnd *) DLE_VAL(curr);
+ Port *port = &(fe->fn_port);
+
+ /* this is lifted from postmaster.c */
+ if (FD_ISSET(port->sock, &rmask))
+ {
+ if (fe->fn_connected == false)
+ {
+ /* we have a message from a new frontEnd */
+ status = PacketReceive(port, &port->buf, NON_BLOCKING);
+ if (status == STATUS_OK)
+ {
+ fe->fn_connected = true;
+ pq_init(port->sock);
+ fe->fn_Pfin = Pfin;
+ fe->fn_Pfout = Pfout;
+ }
+ else
+ fprintf(stderr, "Multiplexed backend: error in reading packets from %d\n", port->sock);
+ }
+ else
+/* we have a query from an existing, active FrontEnd */
+ {
+ Pfin = fe->fn_Pfin;
+ Pfout = fe->fn_Pfout;
+ currentFE = fe;
+ }
+ if (fe->fn_done)
+ {
+ Dlelem *c = curr;
+
+ curr = DLGetSucc(curr);
+ DLRemove(c);
+ }
+ break;
+ }
+ else
+ curr = DLGetSucc(curr);
+ }
+ }
+ /* ----------------
+ * (1) read a command.
+ * ----------------
+ */
+ memset(parser_input, 0, MAX_PARSE_BUFFER);
+
+ firstchar = ReadCommand(parser_input, multiplexedBackend);
+ /* process the command */
+ switch (firstchar)
+ {
+ /* ----------------
+ * 'F' indicates a fastpath call.
+ * XXX HandleFunctionRequest
+ * ----------------
+ */
+ case 'F':
+ IsEmptyQuery = false;
+
+ /* start an xact for this function invocation */
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
+ }
+
+ StartTransactionCommand();
+ HandleFunctionRequest();
+ break;
+
+ /* ----------------
+ * 'Q' indicates a user query
+ * ----------------
+ */
+ case 'Q':
+ fflush(stdout);
+
+ if (strspn(parser_input, " \t\n") == strlen(parser_input))
+ {
+ /* ----------------
+ * if there is nothing in the input buffer, don't bother
+ * trying to parse and execute anything..
+ * ----------------
+ */
+ IsEmptyQuery = true;
+ }
+ else
+ {
+ /* ----------------
+ * otherwise, process the input string.
+ * ----------------
+ */
+ IsEmptyQuery = false;
+ if (ShowStats)
+ ResetUsage();
+
+ /* start an xact for this query */
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
+ }
+ StartTransactionCommand();
+
+ pg_eval(parser_input, (char **) NULL, (Oid *) NULL, 0);
+
+ if (ShowStats)
+ ShowUsage();
+ }
+ break;
+
+ /* ----------------
+ * 'X' means that the frontend is closing down the socket
+ * ----------------
+ */
+ case 'X':
+ IsEmptyQuery = true;
+ if (multiplexedBackend)
+ {
+ FD_CLR(currentFE->fn_port.sock, &basemask);
+ currentFE->fn_done = true;
+ numFE--;
+ }
+ pq_close();
+ break;
+
+ default:
+ elog(WARN, "unknown frontend message was recieved");
+ }
+
+ /* ----------------
+ * (3) commit the current transaction
+ *
+ * Note: if we had an empty input buffer, then we didn't
+ * call pg_eval, so we don't bother to commit this transaction.
+ * ----------------
+ */
+ if (!IsEmptyQuery)
+ {
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tCommitTransactionCommand() at %s\n", ctime(&tim));
+ }
+ CommitTransactionCommand();
+
+ }
+ else
+ {
+ if (IsUnderPostmaster || multiplexedBackend)
+ NullCommand(Remote);
+ }
+
+ } /* infinite for-loop */
+ exitpg(0);
+ return 1;
}
#ifndef HAVE_GETRUSAGE
#include "rusagestub.h"
-#else /* HAVE_GETRUSAGE */
+#else /* HAVE_GETRUSAGE */
#include <sys/resource.h>
-#endif /* HAVE_GETRUSAGE */
+#endif /* HAVE_GETRUSAGE */
-struct rusage Save_r;
-struct timeval Save_t;
+struct rusage Save_r;
+struct timeval Save_t;
void
ResetUsage(void)
{
- struct timezone tz;
- getrusage(RUSAGE_SELF, &Save_r);
- gettimeofday(&Save_t, &tz);
- ResetBufferUsage();
-/* ResetTupleCount(); */
+ struct timezone tz;
+
+ getrusage(RUSAGE_SELF, &Save_r);
+ gettimeofday(&Save_t, &tz);
+ ResetBufferUsage();
+/* ResetTupleCount(); */
}
void
ShowUsage(void)
{
- struct timeval user, sys;
- struct timeval elapse_t;
- struct timezone tz;
- struct rusage r;
-
- getrusage(RUSAGE_SELF, &r);
- gettimeofday(&elapse_t, &tz);
- memmove((char *)&user, (char *)&r.ru_utime, sizeof(user));
- memmove((char *)&sys, (char *)&r.ru_stime,sizeof(sys));
- if (elapse_t.tv_usec < Save_t.tv_usec) {
- elapse_t.tv_sec--;
- elapse_t.tv_usec += 1000000;
- }
- if (r.ru_utime.tv_usec < Save_r.ru_utime.tv_usec) {
- r.ru_utime.tv_sec--;
- r.ru_utime.tv_usec += 1000000;
- }
- if (r.ru_stime.tv_usec < Save_r.ru_stime.tv_usec) {
- r.ru_stime.tv_sec--;
- r.ru_stime.tv_usec += 1000000;
- }
-
- /*
- * the only stats we don't show here are for memory usage -- i can't
- * figure out how to interpret the relevant fields in the rusage
- * struct, and they change names across o/s platforms, anyway.
- * if you can figure out what the entries mean, you can somehow
- * extract resident set size, shared text size, and unshared data
- * and stack sizes.
- */
-
- fprintf(StatFp, "! system usage stats:\n");
- fprintf(StatFp,
- "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n",
- (long int) elapse_t.tv_sec - Save_t.tv_sec,
- (long int) elapse_t.tv_usec - Save_t.tv_usec,
- (long int) r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec,
- (long int) r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec,
- (long int) r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec,
- (long int) r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec);
- fprintf(StatFp,
- "!\t[%ld.%06ld user %ld.%06ld sys total]\n",
- (long int) user.tv_sec,
- (long int) user.tv_usec,
- (long int) sys.tv_sec,
- (long int) sys.tv_usec);
+ struct timeval user,
+ sys;
+ struct timeval elapse_t;
+ struct timezone tz;
+ struct rusage r;
+
+ getrusage(RUSAGE_SELF, &r);
+ gettimeofday(&elapse_t, &tz);
+ memmove((char *) &user, (char *) &r.ru_utime, sizeof(user));
+ memmove((char *) &sys, (char *) &r.ru_stime, sizeof(sys));
+ if (elapse_t.tv_usec < Save_t.tv_usec)
+ {
+ elapse_t.tv_sec--;
+ elapse_t.tv_usec += 1000000;
+ }
+ if (r.ru_utime.tv_usec < Save_r.ru_utime.tv_usec)
+ {
+ r.ru_utime.tv_sec--;
+ r.ru_utime.tv_usec += 1000000;
+ }
+ if (r.ru_stime.tv_usec < Save_r.ru_stime.tv_usec)
+ {
+ r.ru_stime.tv_sec--;
+ r.ru_stime.tv_usec += 1000000;
+ }
+
+ /*
+ * the only stats we don't show here are for memory usage -- i can't
+ * figure out how to interpret the relevant fields in the rusage
+ * struct, and they change names across o/s platforms, anyway. if you
+ * can figure out what the entries mean, you can somehow extract
+ * resident set size, shared text size, and unshared data and stack
+ * sizes.
+ */
+
+ fprintf(StatFp, "! system usage stats:\n");
+ fprintf(StatFp,
+ "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n",
+ (long int) elapse_t.tv_sec - Save_t.tv_sec,
+ (long int) elapse_t.tv_usec - Save_t.tv_usec,
+ (long int) r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec,
+ (long int) r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec,
+ (long int) r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec,
+ (long int) r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec);
+ fprintf(StatFp,
+ "!\t[%ld.%06ld user %ld.%06ld sys total]\n",
+ (long int) user.tv_sec,
+ (long int) user.tv_usec,
+ (long int) sys.tv_sec,
+ (long int) sys.tv_usec);
#ifdef HAVE_GETRUSAGE
- fprintf(StatFp,
- "!\t%ld/%ld [%ld/%ld] filesystem blocks in/out\n",
- r.ru_inblock - Save_r.ru_inblock,
- /* they only drink coffee at dec */
- r.ru_oublock - Save_r.ru_oublock,
- r.ru_inblock, r.ru_oublock);
- fprintf(StatFp,
- "!\t%ld/%ld [%ld/%ld] page faults/reclaims, %ld [%ld] swaps\n",
- r.ru_majflt - Save_r.ru_majflt,
- r.ru_minflt - Save_r.ru_minflt,
- r.ru_majflt, r.ru_minflt,
- r.ru_nswap - Save_r.ru_nswap,
- r.ru_nswap);
- fprintf(StatFp,
- "!\t%ld [%ld] signals rcvd, %ld/%ld [%ld/%ld] messages rcvd/sent\n",
- r.ru_nsignals - Save_r.ru_nsignals,
- r.ru_nsignals,
- r.ru_msgrcv - Save_r.ru_msgrcv,
- r.ru_msgsnd - Save_r.ru_msgsnd,
- r.ru_msgrcv, r.ru_msgsnd);
- fprintf(StatFp,
- "!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n",
- r.ru_nvcsw - Save_r.ru_nvcsw,
- r.ru_nivcsw - Save_r.ru_nivcsw,
- r.ru_nvcsw, r.ru_nivcsw);
-#endif /* HAVE_GETRUSAGE */
- fprintf(StatFp, "! postgres usage stats:\n");
- PrintBufferUsage(StatFp);
-/* DisplayTupleCount(StatFp); */
+ fprintf(StatFp,
+ "!\t%ld/%ld [%ld/%ld] filesystem blocks in/out\n",
+ r.ru_inblock - Save_r.ru_inblock,
+ /* they only drink coffee at dec */
+ r.ru_oublock - Save_r.ru_oublock,
+ r.ru_inblock, r.ru_oublock);
+ fprintf(StatFp,
+ "!\t%ld/%ld [%ld/%ld] page faults/reclaims, %ld [%ld] swaps\n",
+ r.ru_majflt - Save_r.ru_majflt,
+ r.ru_minflt - Save_r.ru_minflt,
+ r.ru_majflt, r.ru_minflt,
+ r.ru_nswap - Save_r.ru_nswap,
+ r.ru_nswap);
+ fprintf(StatFp,
+ "!\t%ld [%ld] signals rcvd, %ld/%ld [%ld/%ld] messages rcvd/sent\n",
+ r.ru_nsignals - Save_r.ru_nsignals,
+ r.ru_nsignals,
+ r.ru_msgrcv - Save_r.ru_msgrcv,
+ r.ru_msgsnd - Save_r.ru_msgsnd,
+ r.ru_msgrcv, r.ru_msgsnd);
+ fprintf(StatFp,
+ "!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n",
+ r.ru_nvcsw - Save_r.ru_nvcsw,
+ r.ru_nivcsw - Save_r.ru_nivcsw,
+ r.ru_nvcsw, r.ru_nivcsw);
+#endif /* HAVE_GETRUSAGE */
+ fprintf(StatFp, "! postgres usage stats:\n");
+ PrintBufferUsage(StatFp);
+/* DisplayTupleCount(StatFp); */
}
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 1d11cbeae49..ca649291355 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* pquery.c--
- * POSTGRES process query command code
+ * POSTGRES process query command code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.7 1997/08/27 09:03:15 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.8 1997/09/07 04:49:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,332 +38,341 @@
#include "commands/command.h"
-static char* CreateOperationTag(int operationType);
-static void ProcessQueryDesc(QueryDesc *queryDesc);
+static char *CreateOperationTag(int operationType);
+static void ProcessQueryDesc(QueryDesc * queryDesc);
/* ----------------------------------------------------------------
- * CreateQueryDesc
+ * CreateQueryDesc
* ----------------------------------------------------------------
*/
-QueryDesc *
-CreateQueryDesc(Query *parsetree,
- Plan *plantree,
- CommandDest dest)
+QueryDesc *
+CreateQueryDesc(Query * parsetree,
+ Plan * plantree,
+ CommandDest dest)
{
- QueryDesc *qd = (QueryDesc *)palloc(sizeof(QueryDesc));
-
- qd->operation = parsetree->commandType; /* operation */
- qd->parsetree = parsetree; /* parse tree */
- qd->plantree = plantree; /* plan */
- qd->dest = dest; /* output dest */
- return qd;
+ QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
+
+ qd->operation = parsetree->commandType; /* operation */
+ qd->parsetree = parsetree; /* parse tree */
+ qd->plantree = plantree; /* plan */
+ qd->dest = dest; /* output dest */
+ return qd;
}
/* ----------------------------------------------------------------
- * CreateExecutorState
+ * CreateExecutorState
*
- * Note: this may someday take parameters -cim 9/18/89
+ * Note: this may someday take parameters -cim 9/18/89
* ----------------------------------------------------------------
*/
-EState *
+EState *
CreateExecutorState(void)
{
- EState *state;
- extern int NBuffers;
- long *refcount;
-
- /* ----------------
- * create a new executor state
- * ----------------
- */
- state = makeNode(EState);
-
- /* ----------------
- * initialize the Executor State structure
- * ----------------
- */
- state->es_direction = ForwardScanDirection;
- state->es_range_table = NIL;
-
- state->es_into_relation_descriptor = NULL;
- state->es_result_relation_info = NULL;
-
- state->es_param_list_info = NULL;
-
- state->es_BaseId = 0;
- state->es_tupleTable = NULL;
-
- state->es_junkFilter = NULL;
-
- refcount = (long *) palloc(NBuffers * sizeof(long));
- memset((char *) refcount, 0, NBuffers * sizeof(long));
- state->es_refcount = (int *) refcount;
-
- /* ----------------
- * return the executor state structure
- * ----------------
- */
- return state;
+ EState *state;
+ extern int NBuffers;
+ long *refcount;
+
+ /* ----------------
+ * create a new executor state
+ * ----------------
+ */
+ state = makeNode(EState);
+
+ /* ----------------
+ * initialize the Executor State structure
+ * ----------------
+ */
+ state->es_direction = ForwardScanDirection;
+ state->es_range_table = NIL;
+
+ state->es_into_relation_descriptor = NULL;
+ state->es_result_relation_info = NULL;
+
+ state->es_param_list_info = NULL;
+
+ state->es_BaseId = 0;
+ state->es_tupleTable = NULL;
+
+ state->es_junkFilter = NULL;
+
+ refcount = (long *) palloc(NBuffers * sizeof(long));
+ memset((char *) refcount, 0, NBuffers * sizeof(long));
+ state->es_refcount = (int *) refcount;
+
+ /* ----------------
+ * return the executor state structure
+ * ----------------
+ */
+ return state;
}
/* ----------------------------------------------------------------
- * CreateOperationTag
+ * CreateOperationTag
*
- * utility to get a string representation of the
- * query operation.
+ * utility to get a string representation of the
+ * query operation.
* ----------------------------------------------------------------
*/
-static char*
+static char *
CreateOperationTag(int operationType)
{
- char* tag;
-
- switch (operationType) {
- case CMD_SELECT:
- tag = "SELECT";
- break;
- case CMD_INSERT:
- tag = "INSERT";
- break;
- case CMD_DELETE:
- tag = "DELETE";
- break;
- case CMD_UPDATE:
- tag = "UPDATE";
- break;
- default:
- elog(DEBUG, "CreateOperationTag: unknown operation type %d",
- operationType);
- tag = NULL;
- break;
- }
-
- return tag;
+ char *tag;
+
+ switch (operationType)
+ {
+ case CMD_SELECT:
+ tag = "SELECT";
+ break;
+ case CMD_INSERT:
+ tag = "INSERT";
+ break;
+ case CMD_DELETE:
+ tag = "DELETE";
+ break;
+ case CMD_UPDATE:
+ tag = "UPDATE";
+ break;
+ default:
+ elog(DEBUG, "CreateOperationTag: unknown operation type %d",
+ operationType);
+ tag = NULL;
+ break;
+ }
+
+ return tag;
}
/* ----------------
- * ProcessPortal
+ * ProcessPortal
* ----------------
*/
void
-ProcessPortal(char* portalName,
- Query *parseTree,
- Plan *plan,
- EState *state,
- TupleDesc attinfo,
- CommandDest dest)
+ProcessPortal(char *portalName,
+ Query * parseTree,
+ Plan * plan,
+ EState * state,
+ TupleDesc attinfo,
+ CommandDest dest)
{
- Portal portal;
- MemoryContext portalContext;
-
- /* ----------------
- * convert the current blank portal into the user-specified
- * portal and initialize the state and query descriptor.
- * ----------------
- */
-
- if (PortalNameIsSpecial(portalName))
- elog(WARN,
- "The portal name %s is reserved for internal use",
- portalName);
-
- portal = BlankPortalAssignName(portalName);
-
- PortalSetQuery(portal,
- CreateQueryDesc(parseTree, plan, dest),
- attinfo,
- state,
- PortalCleanup);
-
- /* ----------------
- * now create a new blank portal and switch to it.
- * Otherwise, the new named portal will be cleaned.
- *
- * Note: portals will only be supported within a BEGIN...END
- * block in the near future. Later, someone will fix it to
- * do what is possible across transaction boundries. -hirohama
- * ----------------
- */
- portalContext = (MemoryContext)
- PortalGetHeapMemory(GetPortalByName(NULL));
-
- MemoryContextSwitchTo(portalContext);
-
- StartPortalAllocMode(DefaultAllocMode, 0);
+ Portal portal;
+ MemoryContext portalContext;
+
+ /* ----------------
+ * convert the current blank portal into the user-specified
+ * portal and initialize the state and query descriptor.
+ * ----------------
+ */
+
+ if (PortalNameIsSpecial(portalName))
+ elog(WARN,
+ "The portal name %s is reserved for internal use",
+ portalName);
+
+ portal = BlankPortalAssignName(portalName);
+
+ PortalSetQuery(portal,
+ CreateQueryDesc(parseTree, plan, dest),
+ attinfo,
+ state,
+ PortalCleanup);
+
+ /* ----------------
+ * now create a new blank portal and switch to it.
+ * Otherwise, the new named portal will be cleaned.
+ *
+ * Note: portals will only be supported within a BEGIN...END
+ * block in the near future. Later, someone will fix it to
+ * do what is possible across transaction boundries. -hirohama
+ * ----------------
+ */
+ portalContext = (MemoryContext)
+ PortalGetHeapMemory(GetPortalByName(NULL));
+
+ MemoryContextSwitchTo(portalContext);
+
+ StartPortalAllocMode(DefaultAllocMode, 0);
}
/* ----------------------------------------------------------------
- * ProcessQueryDesc
+ * ProcessQueryDesc
*
- * Read the comments for ProcessQuery() below...
+ * Read the comments for ProcessQuery() below...
* ----------------------------------------------------------------
*/
static void
-ProcessQueryDesc(QueryDesc *queryDesc)
+ProcessQueryDesc(QueryDesc * queryDesc)
{
- Query *parseTree;
- Plan *plan;
- int operation;
- char* tag;
- EState *state;
- TupleDesc attinfo;
-
- bool isRetrieveIntoPortal;
- bool isRetrieveIntoRelation;
- char* intoName = NULL;
- CommandDest dest;
-
- /* ----------------
- * get info from the query desc
- * ----------------
- */
- parseTree = queryDesc->parsetree;
- plan = queryDesc->plantree;
-
- operation = queryDesc->operation;
- tag = CreateOperationTag(operation);
- dest = queryDesc->dest;
-
- /* ----------------
- * initialize portal/into relation status
- * ----------------
- */
- isRetrieveIntoPortal = false;
- isRetrieveIntoRelation = false;
-
- if (operation == CMD_SELECT) {
- if (parseTree->isPortal) {
- isRetrieveIntoPortal = true;
- intoName = parseTree->into;
- if (parseTree->isBinary) {
- /*
- * For internal format portals, we change Remote
- * (externalized form) to RemoteInternal (internalized
- * form)
- */
- dest = queryDesc->dest = RemoteInternal;
- }
- } else if (parseTree->into != NULL) {
- /* select into table */
- isRetrieveIntoRelation = true;
+ Query *parseTree;
+ Plan *plan;
+ int operation;
+ char *tag;
+ EState *state;
+ TupleDesc attinfo;
+
+ bool isRetrieveIntoPortal;
+ bool isRetrieveIntoRelation;
+ char *intoName = NULL;
+ CommandDest dest;
+
+ /* ----------------
+ * get info from the query desc
+ * ----------------
+ */
+ parseTree = queryDesc->parsetree;
+ plan = queryDesc->plantree;
+
+ operation = queryDesc->operation;
+ tag = CreateOperationTag(operation);
+ dest = queryDesc->dest;
+
+ /* ----------------
+ * initialize portal/into relation status
+ * ----------------
+ */
+ isRetrieveIntoPortal = false;
+ isRetrieveIntoRelation = false;
+
+ if (operation == CMD_SELECT)
+ {
+ if (parseTree->isPortal)
+ {
+ isRetrieveIntoPortal = true;
+ intoName = parseTree->into;
+ if (parseTree->isBinary)
+ {
+
+ /*
+ * For internal format portals, we change Remote
+ * (externalized form) to RemoteInternal (internalized
+ * form)
+ */
+ dest = queryDesc->dest = RemoteInternal;
+ }
+ }
+ else if (parseTree->into != NULL)
+ {
+ /* select into table */
+ isRetrieveIntoRelation = true;
+ }
+
}
- }
-
- /* ----------------
- * when performing a retrieve into, we override the normal
- * communication destination during the processing of the
- * the query. This only affects the tuple-output function
- * - the correct destination will still see BeginCommand()
- * and EndCommand() messages.
- * ----------------
- */
- if (isRetrieveIntoRelation)
- queryDesc->dest = (int) None;
-
- /* ----------------
- * create a default executor state..
- * ----------------
- */
- state = CreateExecutorState();
-
- /* ----------------
- * call ExecStart to prepare the plan for execution
- * ----------------
- */
- attinfo = ExecutorStart(queryDesc, state);
-
- /* ----------------
- * report the query's result type information
- * back to the front end or to whatever destination
- * we're dealing with.
- * ----------------
- */
- BeginCommand(NULL,
- operation,
- attinfo,
- isRetrieveIntoRelation,
- isRetrieveIntoPortal,
- tag,
- dest);
-
- /* ----------------
- * Named portals do not do a "fetch all" initially, so now
- * we return since ExecMain has been called with EXEC_START
- * to initialize the query plan.
- *
- * Note: ProcessPortal transforms the current "blank" portal
- * into a named portal and creates a new blank portal so
- * everything we allocated in the current "blank" memory
- * context will be preserved across queries. -cim 2/22/91
- * ----------------
- */
- if (isRetrieveIntoPortal) {
- PortalExecutorHeapMemory = NULL;
-
- ProcessPortal(intoName,
- parseTree,
- plan,
- state,
- attinfo,
- dest);
-
+ /* ----------------
+ * when performing a retrieve into, we override the normal
+ * communication destination during the processing of the
+ * the query. This only affects the tuple-output function
+ * - the correct destination will still see BeginCommand()
+ * and EndCommand() messages.
+ * ----------------
+ */
+ if (isRetrieveIntoRelation)
+ queryDesc->dest = (int) None;
+
+ /* ----------------
+ * create a default executor state..
+ * ----------------
+ */
+ state = CreateExecutorState();
+
+ /* ----------------
+ * call ExecStart to prepare the plan for execution
+ * ----------------
+ */
+ attinfo = ExecutorStart(queryDesc, state);
+
+ /* ----------------
+ * report the query's result type information
+ * back to the front end or to whatever destination
+ * we're dealing with.
+ * ----------------
+ */
+ BeginCommand(NULL,
+ operation,
+ attinfo,
+ isRetrieveIntoRelation,
+ isRetrieveIntoPortal,
+ tag,
+ dest);
+
+ /* ----------------
+ * Named portals do not do a "fetch all" initially, so now
+ * we return since ExecMain has been called with EXEC_START
+ * to initialize the query plan.
+ *
+ * Note: ProcessPortal transforms the current "blank" portal
+ * into a named portal and creates a new blank portal so
+ * everything we allocated in the current "blank" memory
+ * context will be preserved across queries. -cim 2/22/91
+ * ----------------
+ */
+ if (isRetrieveIntoPortal)
+ {
+ PortalExecutorHeapMemory = NULL;
+
+ ProcessPortal(intoName,
+ parseTree,
+ plan,
+ state,
+ attinfo,
+ dest);
+
+ EndCommand(tag, dest);
+ return;
+ }
+
+ /* ----------------
+ * Now we get to the important call to ExecutorRun() where we
+ * actually run the plan..
+ * ----------------
+ */
+ ExecutorRun(queryDesc, state, EXEC_RUN, 0);
+
+ /* save infos for EndCommand */
+ UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
+
+ /* ----------------
+ * now, we close down all the scans and free allocated resources...
+ * with ExecutorEnd()
+ * ----------------
+ */
+ ExecutorEnd(queryDesc, state);
+
+ /* ----------------
+ * Notify the destination of end of processing.
+ * ----------------
+ */
EndCommand(tag, dest);
- return;
- }
-
- /* ----------------
- * Now we get to the important call to ExecutorRun() where we
- * actually run the plan..
- * ----------------
- */
- ExecutorRun(queryDesc, state, EXEC_RUN, 0);
-
- /* save infos for EndCommand */
- UpdateCommandInfo (operation, state->es_lastoid, state->es_processed);
-
- /* ----------------
- * now, we close down all the scans and free allocated resources...
- * with ExecutorEnd()
- * ----------------
- */
- ExecutorEnd(queryDesc, state);
-
- /* ----------------
- * Notify the destination of end of processing.
- * ----------------
- */
- EndCommand(tag, dest);
}
/* ----------------------------------------------------------------
- * ProcessQuery
+ * ProcessQuery
*
- * Execute a plan, the non-parallel version
+ * Execute a plan, the non-parallel version
* ----------------------------------------------------------------
*/
void
-ProcessQuery(Query *parsetree,
- Plan *plan,
- char *argv[],
- Oid *typev,
- int nargs,
- CommandDest dest)
+ProcessQuery(Query * parsetree,
+ Plan * plan,
+ char *argv[],
+ Oid * typev,
+ int nargs,
+ CommandDest dest)
{
- QueryDesc *queryDesc;
- extern int dontExecute; /* from postgres.c */
- extern void print_plan (Plan* p, Query* parsetree); /* from print.c */
+ QueryDesc *queryDesc;
+ extern int dontExecute;/* from postgres.c */
+ extern void print_plan(Plan * p, Query * parsetree); /* from print.c */
- queryDesc = CreateQueryDesc(parsetree, plan, dest);
+ queryDesc = CreateQueryDesc(parsetree, plan, dest);
- if (dontExecute) {
- /* don't execute it, just show the query plan */
- print_plan(plan, parsetree);
- } else
- ProcessQueryDesc(queryDesc);
+ if (dontExecute)
+ {
+ /* don't execute it, just show the query plan */
+ print_plan(plan, parsetree);
+ }
+ else
+ ProcessQueryDesc(queryDesc);
}
-
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 1edb41b46e0..d309ac69a27 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1,15 +1,15 @@
/*-------------------------------------------------------------------------
*
* 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.
+ * 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.21 1997/08/31 11:41:55 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.22 1997/09/07 04:49:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -47,7 +47,7 @@
#include "tcop/dest.h"
#include "tcop/variable.h"
#include "tcop/utility.h"
-#include "fmgr.h" /* For load_file() */
+#include "fmgr.h" /* For load_file() */
#include "storage/fd.h"
#ifndef NO_SECURITY
@@ -58,649 +58,673 @@
/* ----------------
- * CHECK_IF_ABORTED() is used to avoid doing unnecessary
- * processing within an aborted transaction block.
+ * 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; \
- } \
-
+ if (IsAbortedTransactionBlockState()) { \
+ elog(NOTICE, "(transaction aborted): %s", \
+ "queries ignored until END"); \
+ commandTag = "*ABORT STATE*"; \
+ break; \
+ } \
+
/* ----------------
- * general utility function invoker
+ * general utility function invoker
* ----------------
*/
void
-ProcessUtility(Node *parsetree,
- CommandDest dest)
+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;
- Relation rel;
-
- commandTag = "DROP";
- CHECK_IF_ABORTED();
-
- foreach (arg, args) {
- relname = strVal(lfirst(arg));
- if (IsSystemRelationName(relname))
- elog(WARN, "class \"%s\" is a system catalog",
- relname);
- rel = heap_openr (relname);
- if ( RelationIsValid (rel) )
- {
- if ( stmt->sequence &&
- rel->rd_rel->relkind != RELKIND_SEQUENCE )
- elog (WARN, "Use DROP TABLE to drop table '%s'",
- relname);
- if ( !(stmt->sequence) &&
- rel->rd_rel->relkind == RELKIND_SEQUENCE )
- elog (WARN, "Use DROP SEQUENCE to drop sequence '%s'",
- relname);
- heap_close (rel);
- }
-#ifndef NO_SECURITY
- if (!pg_ownercheck(userName, relname, RELNAME))
- elog(WARN, "you do not own class \"%s\"",
- 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;
-
- commandTag = "COPY";
- CHECK_IF_ABORTED();
-
- DoCopy(stmt->relname,
- stmt->binary,
- stmt->oids,
- (bool)(stmt->direction == FROM),
- (bool)(stmt->filename == NULL),
- /* null filename means copy to/from stdout/stdin,
- rather than to/from a file.
- */
- stmt->filename,
- stmt->delimiter);
- }
- 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:
+ char *commandTag = NULL;
+ char *relname;
+ char *relationName;
+ char *userName;
+
+ userName = GetPgUserName();
+
+ switch (nodeTag(parsetree))
{
- 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
+
+ /*
+ * ******************************** transactions ********************************
*
- * 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
- * ----------------
+ 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 ********************************
+ *
*/
- 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;
+ 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;
+ Relation rel;
+
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+
+ foreach(arg, args)
+ {
+ relname = strVal(lfirst(arg));
+ if (IsSystemRelationName(relname))
+ elog(WARN, "class \"%s\" is a system catalog",
+ relname);
+ rel = heap_openr(relname);
+ if (RelationIsValid(rel))
+ {
+ if (stmt->sequence &&
+ rel->rd_rel->relkind != RELKIND_SEQUENCE)
+ elog(WARN, "Use DROP TABLE to drop table '%s'",
+ relname);
+ if (!(stmt->sequence) &&
+ rel->rd_rel->relkind == RELKIND_SEQUENCE)
+ elog(WARN, "Use DROP SEQUENCE to drop sequence '%s'",
+ relname);
+ heap_close(rel);
+ }
#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\"",
- relname);
- }
+ if (!pg_ownercheck(userName, relname, RELNAME))
+ elog(WARN, "you do not own class \"%s\"",
+ relname);
#endif
- foreach (i, stmt->relNames) {
- relname = strVal(lfirst(i));
- ChangeAcl(relname, aip, modechg);
- }
+ }
+ foreach(arg, args)
+ {
+ relname = strVal(lfirst(arg));
+ RemoveRelation(relname);
+ }
+ }
+ break;
- }
- break;
-
- /* ********************************
- * object creation / destruction
- * ********************************
- */
- case T_DefineStmt:
- {
- DefineStmt *stmt = (DefineStmt *)parsetree;
+ case T_PurgeStmt:
+ {
+ PurgeStmt *stmt = (PurgeStmt *) parsetree;
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
+ commandTag = "PURGE";
+ CHECK_IF_ABORTED();
- switch(stmt->defType) {
- case OPERATOR:
- DefineOperator(stmt->defname, /* operator name */
- stmt->definition); /* rest */
+ RelationPurge(stmt->relname,
+ stmt->beforeDate, /* absolute time string */
+ stmt->afterDate); /* relative time string */
+ }
break;
- case P_TYPE:
+
+ case T_CopyStmt:
{
- DefineType (stmt->defname, stmt->definition);
+ CopyStmt *stmt = (CopyStmt *) parsetree;
+
+ commandTag = "COPY";
+ CHECK_IF_ABORTED();
+
+ DoCopy(stmt->relname,
+ stmt->binary,
+ stmt->oids,
+ (bool) (stmt->direction == FROM),
+ (bool) (stmt->filename == NULL),
+
+ /*
+ * null filename means copy to/from stdout/stdin, rather than
+ * to/from a file.
+ */
+ stmt->filename,
+ stmt->delimiter);
}
break;
- case AGGREGATE:
- DefineAggregate(stmt->defname, /*aggregate name */
- stmt->definition); /* rest */
+
+ 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;
- }
- }
- break;
-
- case T_ViewStmt: /* CREATE VIEW */
- {
- ViewStmt *stmt = (ViewStmt *)parsetree;
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
- DefineView (stmt->viewname, stmt->query); /* retrieve parsetree */
- }
- break;
-
- case T_ProcedureStmt: /* CREATE FUNCTION */
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
- CreateFunction((ProcedureStmt *)parsetree, dest); /* everything */
- break;
-
- case T_IndexStmt: /* CREATE INDEX */
- {
- 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,
- stmt->unique,
- (Expr*)stmt->whereClause,
- stmt->rangetable);
- }
- break;
-
- case T_RuleStmt: /* CREATE RULE */
- {
- RuleStmt *stmt = (RuleStmt *)parsetree;
- int aclcheck_result;
+ /*
+ * 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
- relname = stmt->object->relname;
- aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
- if(aclcheck_result != ACLCHECK_OK)
- elog(WARN, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
-#endif
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
- DefineQueryRewrite(stmt);
- }
- break;
-
- case T_CreateSeqStmt:
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
-
- DefineSequence((CreateSeqStmt *)parsetree);
- 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 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, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
+ if (!pg_ownercheck(userName, relname, RELNAME))
+ elog(WARN, "you do not own class \"%s\"",
+ relname);
#endif
- RemoveIndex(relname);
+
+ /* ----------------
+ * 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 RULE:
+
+ case T_ChangeACLStmt:
{
- char *rulename = stmt->name;
- int aclcheck_result;
+ ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
+ List *i;
+ AclItem *aip;
+ unsigned modechg;
+
+ commandTag = "CHANGE";
+ CHECK_IF_ABORTED();
+
+ aip = stmt->aclitem;
+ modechg = stmt->modechg;
#ifndef NO_SECURITY
-
- relationName = RewriteGetRuleEventRel(rulename);
- aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
- if(aclcheck_result != ACLCHECK_OK) {
- elog(WARN, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
- }
+ foreach(i, stmt->relNames)
+ {
+ relname = strVal(lfirst(i));
+ if (!pg_ownercheck(userName, relname, RELNAME))
+ elog(WARN, "you do not own class \"%s\"",
+ relname);
+ }
#endif
- RemoveRewriteRule(rulename);
+ 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: /* CREATE VIEW */
+ {
+ ViewStmt *stmt = (ViewStmt *) parsetree;
+
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+ DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
+ }
+ break;
+
+ case T_ProcedureStmt: /* CREATE FUNCTION */
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+ CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */
+ break;
+
+ case T_IndexStmt: /* CREATE INDEX */
+ {
+ 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,
+ stmt->unique,
+ (Expr *) stmt->whereClause,
+ stmt->rangetable);
}
break;
- case P_TYPE:
+
+ case T_RuleStmt: /* CREATE RULE */
+ {
+ RuleStmt *stmt = (RuleStmt *) parsetree;
+ int aclcheck_result;
+
#ifndef NO_SECURITY
- /* XXX moved to remove.c */
+ relname = stmt->object->relname;
+ aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
+ if (aclcheck_result != ACLCHECK_OK)
+ elog(WARN, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
#endif
- RemoveType(stmt->name);
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+ DefineQueryRewrite(stmt);
+ }
+ break;
+
+ case T_CreateSeqStmt:
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+
+ DefineSequence((CreateSeqStmt *) parsetree);
+ 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 VIEW:
+
+ case T_RemoveStmt:
{
- char *viewName = stmt->name;
- char *ruleName;
+ RemoveStmt *stmt = (RemoveStmt *) parsetree;
+
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+
+ switch (stmt->removeType)
+ {
+ 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, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
+#endif
+ RemoveIndex(relname);
+ break;
+ case RULE:
+ {
+ char *rulename = stmt->name;
+ int aclcheck_result;
#ifndef NO_SECURITY
-
- ruleName = MakeRetrieveViewRuleName(viewName);
- relationName = RewriteGetRuleEventRel(ruleName);
- if (!pg_ownercheck(userName, relationName, RELNAME))
- elog(WARN, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
- pfree(ruleName);
+
+ relationName = RewriteGetRuleEventRel(rulename);
+ aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
+ if (aclcheck_result != ACLCHECK_OK)
+ {
+ elog(WARN, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
+ }
+#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;
+
+#ifndef NO_SECURITY
+
+ ruleName = MakeRetrieveViewRuleName(viewName);
+ relationName = RewriteGetRuleEventRel(ruleName);
+ if (!pg_ownercheck(userName, relationName, RELNAME))
+ elog(WARN, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
+ pfree(ruleName);
#endif
- RemoveView(viewName);
+ RemoveView(viewName);
+ }
+ break;
+ }
+ break;
}
break;
- }
- break;
- }
- break;
- case T_RemoveAggrStmt:
- {
- RemoveAggrStmt *stmt = (RemoveAggrStmt *)parsetree;
- commandTag = "DROP";
- CHECK_IF_ABORTED();
- RemoveAggregate(stmt->aggname, stmt->aggtype);
- }
- 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;
+ case T_RemoveAggrStmt:
+ {
+ RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
- commandTag = "CREATEDB";
- CHECK_IF_ABORTED();
- createdb(stmt->dbname);
- }
- break;
-
- case T_DestroydbStmt:
- {
- DestroydbStmt *stmt = (DestroydbStmt *)parsetree;
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+ RemoveAggregate(stmt->aggname, stmt->aggtype);
+ }
+ break;
- commandTag = "DESTROYDB";
- CHECK_IF_ABORTED();
- destroydb(stmt->dbname);
- }
- break;
-
- /* Query-level asynchronous notification */
- case T_NotifyStmt:
- {
- NotifyStmt *stmt = (NotifyStmt *)parsetree;
+ case T_RemoveFuncStmt:
+ {
+ RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
- commandTag = "NOTIFY";
- CHECK_IF_ABORTED();
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+ RemoveFunction(stmt->funcname,
+ length(stmt->args),
+ stmt->args);
+ }
+ break;
- Async_Notify(stmt->relname);
- }
- break;
-
- case T_ListenStmt:
- {
- ListenStmt *stmt = (ListenStmt *)parsetree;
+ 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;
- commandTag = "LISTEN";
- CHECK_IF_ABORTED();
+ case T_VersionStmt:
+ {
+ elog(WARN, "CREATE VERSION is not currently implemented");
+ }
+ break;
- Async_Listen(stmt->relname,MasterPid);
- }
- break;
-
- /* ********************************
- * dynamic loader
- * ********************************
- */
- case T_LoadStmt:
- {
- LoadStmt *stmt = (LoadStmt *)parsetree;
- FILE *fp;
- char *filename;
-
- commandTag = "LOAD";
- CHECK_IF_ABORTED();
-
- filename = stmt->filename;
- closeAllVfds();
- if ((fp = AllocateFile(filename, "r")) == NULL)
- elog(WARN, "LOAD: could not open file %s", filename);
- FreeFile(fp);
- load_file(filename);
- }
- break;
+ case T_CreatedbStmt:
+ {
+ CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
- case T_ClusterStmt:
- {
- ClusterStmt *stmt = (ClusterStmt *)parsetree;
+ commandTag = "CREATEDB";
+ CHECK_IF_ABORTED();
+ createdb(stmt->dbname);
+ }
+ break;
- commandTag = "CLUSTER";
- CHECK_IF_ABORTED();
+ case T_DestroydbStmt:
+ {
+ DestroydbStmt *stmt = (DestroydbStmt *) parsetree;
- cluster(stmt->relname, stmt->indexname);
- }
- break;
-
- case T_VacuumStmt:
- commandTag = "VACUUM";
- CHECK_IF_ABORTED();
- vacuum( ((VacuumStmt *) parsetree)->vacrel,
- ((VacuumStmt *) parsetree)->verbose,
- ((VacuumStmt *) parsetree)->analyze,
- ((VacuumStmt *) parsetree)->va_spec);
- break;
-
- case T_ExplainStmt:
- {
- ExplainStmt *stmt = (ExplainStmt *)parsetree;
+ commandTag = "DESTROYDB";
+ CHECK_IF_ABORTED();
+ destroydb(stmt->dbname);
+ }
+ break;
- commandTag = "EXPLAIN";
- CHECK_IF_ABORTED();
+ /* Query-level asynchronous notification */
+ case T_NotifyStmt:
+ {
+ NotifyStmt *stmt = (NotifyStmt *) parsetree;
- ExplainQuery(stmt->query, stmt->verbose, dest);
- }
- break;
-
- /* ********************************
- Tioga-related statements
- *********************************/
- case T_RecipeStmt:
- {
- RecipeStmt* stmt = (RecipeStmt*)parsetree;
- commandTag="EXECUTE RECIPE";
- CHECK_IF_ABORTED();
- beginRecipe(stmt);
- }
- break;
+ commandTag = "NOTIFY";
+ CHECK_IF_ABORTED();
- /* ********************************
- * set variable statements
- *********************************/
- case T_VariableSetStmt:
- {
- VariableSetStmt *n = (VariableSetStmt *) parsetree;
- SetPGVariable(n->name, n->value);
- commandTag = "SET VARIABLE";
- }
- break;
-
- case T_VariableShowStmt:
- {
- VariableShowStmt *n = (VariableShowStmt *) parsetree;
- GetPGVariable(n->name);
- commandTag = "SHOW VARIABLE";
- }
- break;
-
- case T_VariableResetStmt:
- {
- VariableResetStmt *n = (VariableResetStmt *) parsetree;
- ResetPGVariable(n->name);
- commandTag = "RESET VARIABLE";
+ 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;
+ char *filename;
+
+ commandTag = "LOAD";
+ CHECK_IF_ABORTED();
+
+ filename = stmt->filename;
+ closeAllVfds();
+ if ((fp = AllocateFile(filename, "r")) == NULL)
+ elog(WARN, "LOAD: could not open file %s", filename);
+ FreeFile(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,
+ ((VacuumStmt *) parsetree)->verbose,
+ ((VacuumStmt *) parsetree)->analyze,
+ ((VacuumStmt *) parsetree)->va_spec);
+ break;
+
+ case T_ExplainStmt:
+ {
+ ExplainStmt *stmt = (ExplainStmt *) parsetree;
+
+ commandTag = "EXPLAIN";
+ CHECK_IF_ABORTED();
+
+ ExplainQuery(stmt->query, stmt->verbose, dest);
+ }
+ break;
+
+ /*
+ * ******************************** Tioga-related statements *******************************
+ */
+ case T_RecipeStmt:
+ {
+ RecipeStmt *stmt = (RecipeStmt *) parsetree;
+
+ commandTag = "EXECUTE RECIPE";
+ CHECK_IF_ABORTED();
+ beginRecipe(stmt);
+ }
+ break;
+
+ /*
+ * ******************************** set variable statements *******************************
+ */
+ case T_VariableSetStmt:
+ {
+ VariableSetStmt *n = (VariableSetStmt *) parsetree;
+
+ SetPGVariable(n->name, n->value);
+ commandTag = "SET VARIABLE";
+ }
+ break;
+
+ case T_VariableShowStmt:
+ {
+ VariableShowStmt *n = (VariableShowStmt *) parsetree;
+
+ GetPGVariable(n->name);
+ commandTag = "SHOW VARIABLE";
+ }
+ break;
+
+ case T_VariableResetStmt:
+ {
+ VariableResetStmt *n = (VariableResetStmt *) parsetree;
+
+ ResetPGVariable(n->name);
+ commandTag = "RESET VARIABLE";
+ }
+ break;
+
+ /*
+ * ******************************** TRIGGER statements *******************************
+ */
+ case T_CreateTrigStmt:
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+
+ CreateTrigger((CreateTrigStmt *) parsetree);
+ break;
+
+ case T_DropTrigStmt:
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+
+ DropTrigger((DropTrigStmt *) parsetree);
+ break;
+
+ /*
+ * ******************************** default ********************************
+ *
+ */
+ default:
+ elog(WARN, "ProcessUtility: command #%d unsupported",
+ nodeTag(parsetree));
+ break;
}
- break;
-
- /* ********************************
- * TRIGGER statements
- *********************************/
- case T_CreateTrigStmt:
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
-
- CreateTrigger((CreateTrigStmt *)parsetree);
- break;
-
- case T_DropTrigStmt:
- commandTag = "DROP";
- CHECK_IF_ABORTED();
-
- DropTrigger((DropTrigStmt *)parsetree);
- break;
-
- /* ********************************
- * default
- * ********************************
+
+ /* ----------------
+ * tell fe/be or whatever that we're done.
+ * ----------------
*/
- default:
- elog(WARN, "ProcessUtility: command #%d unsupported",
- nodeTag(parsetree));
- break;
- }
-
- /* ----------------
- * tell fe/be or whatever that we're done.
- * ----------------
- */
- EndCommand(commandTag, dest);
+ EndCommand(commandTag, dest);
}
-
diff --git a/src/backend/tcop/variable.c b/src/backend/tcop/variable.c
index c2a2a754e95..d394881ab3a 100644
--- a/src/backend/tcop/variable.c
+++ b/src/backend/tcop/variable.c
@@ -2,7 +2,7 @@
* Routines for handling of 'SET var TO', 'SHOW var' and 'RESET var'
* statements.
*
- * $Id: variable.c,v 1.13 1997/08/12 20:15:50 momjian Exp $
+ * $Id: variable.c,v 1.14 1997/09/07 04:49:37 momjian Exp $
*
*/
@@ -15,421 +15,471 @@
#include "utils/builtins.h"
#include "optimizer/internal.h"
-extern Cost _cpu_page_wight_;
-extern Cost _cpu_index_page_wight_;
-extern bool _use_geqo_;
-extern int32 _use_geqo_rels_;
-extern bool _use_right_sided_plans_;
+extern Cost _cpu_page_wight_;
+extern Cost _cpu_index_page_wight_;
+extern bool _use_geqo_;
+extern int32 _use_geqo_rels_;
+extern bool _use_right_sided_plans_;
/*-----------------------------------------------------------------------*/
#if USE_EURODATES
-#define DATE_EURO TRUE
+#define DATE_EURO TRUE
#else
#define DATE_EURO FALSE
#endif
/*-----------------------------------------------------------------------*/
struct PGVariables PGVariables =
- {
- { DATE_EURO, Date_Postgres }
- };
+{
+ {DATE_EURO, Date_Postgres}
+};
/*-----------------------------------------------------------------------*/
-static const char *get_token(char **tok, char **val, const char *str)
+static const char *
+get_token(char **tok, char **val, const char *str)
{
- const char *start;
- int len = 0;
-
- *tok = NULL;
- if (val != NULL) *val = NULL;
-
- if ( !(*str) )
- return NULL;
-
- /* skip white spaces */
- while (isspace(*str)) str++;
- if ( *str == ',' || *str == '=' )
- elog(WARN, "Syntax error near (%s): empty setting", str);
-
- /* end of string? then return NULL */
- if ( !(*str) )
- return NULL;
-
- /* OK, at beginning of non-NULL string... */
- start = str;
-
- /*
- * count chars in token until we hit white space or comma
- * or '=' or end of string
- */
- while ( *str && (! isspace(*str))
- && *str != ',' && *str != '=' )
- {
- str++;
- len++;
- }
-
- *tok = (char*) PALLOC(len + 1);
- strNcpy (*tok, start, len);
-
- /* skip white spaces */
- while ( isspace(*str)) str++;
-
- /* end of string? */
- if ( !(*str) ) {
- return(str);
-
- /* delimiter? */
- } else if ( *str == ',' ) {
- return (++str);
-
- } else if ((val == NULL) || ( *str != '=' )) {
+ const char *start;
+ int len = 0;
+
+ *tok = NULL;
+ if (val != NULL)
+ *val = NULL;
+
+ if (!(*str))
+ return NULL;
+
+ /* skip white spaces */
+ while (isspace(*str))
+ str++;
+ if (*str == ',' || *str == '=')
+ elog(WARN, "Syntax error near (%s): empty setting", str);
+
+ /* end of string? then return NULL */
+ if (!(*str))
+ return NULL;
+
+ /* OK, at beginning of non-NULL string... */
+ start = str;
+
+ /*
+ * count chars in token until we hit white space or comma or '=' or
+ * end of string
+ */
+ while (*str && (!isspace(*str))
+ && *str != ',' && *str != '=')
+ {
+ str++;
+ len++;
+ }
+
+ *tok = (char *) PALLOC(len + 1);
+ strNcpy(*tok, start, len);
+
+ /* skip white spaces */
+ while (isspace(*str))
+ str++;
+
+ /* end of string? */
+ if (!(*str))
+ {
+ return (str);
+
+ /* delimiter? */
+ }
+ else if (*str == ',')
+ {
+ return (++str);
+
+ }
+ else if ((val == NULL) || (*str != '='))
+ {
+ elog(WARN, "Syntax error near (%s)", str);
+ };
+
+ str++; /* '=': get value */
+ len = 0;
+
+ /* skip white spaces */
+ while (isspace(*str))
+ str++;
+
+ if (*str == ',' || !(*str))
+ elog(WARN, "Syntax error near (=%s)", str);
+
+ start = str;
+
+ /*
+ * count chars in token's value until we hit white space or comma or
+ * end of string
+ */
+ while (*str && (!isspace(*str)) && *str != ',')
+ {
+ str++;
+ len++;
+ }
+
+ *val = (char *) PALLOC(len + 1);
+ strNcpy(*val, start, len);
+
+ /* skip white spaces */
+ while (isspace(*str))
+ str++;
+
+ if (!(*str))
+ return (NULL);
+ if (*str == ',')
+ return (++str);
+
elog(WARN, "Syntax error near (%s)", str);
- };
-
- str++; /* '=': get value */
- len = 0;
-
- /* skip white spaces */
- while ( isspace(*str)) str++;
-
- if ( *str == ',' || !(*str) )
- elog(WARN, "Syntax error near (=%s)", str);
-
- start = str;
-
- /*
- * count chars in token's value until we hit white space or comma
- * or end of string
- */
- while ( *str && (! isspace(*str)) && *str != ',' )
- {
- str++;
- len++;
- }
-
- *val = (char*) PALLOC(len + 1);
- strNcpy (*val, start, len);
-
- /* skip white spaces */
- while ( isspace(*str)) str++;
-
- if ( !(*str) )
- return (NULL);
- if ( *str == ',' )
- return (++str);
-
- elog(WARN, "Syntax error near (%s)", str);
-
- return str;
+
+ return str;
}
/*-----------------------------------------------------------------------*/
-static bool parse_null(const char *value)
- {
+static bool
+parse_null(const char *value)
+{
return TRUE;
- }
+}
-static bool show_null(const char *value)
- {
+static bool
+show_null(const char *value)
+{
return TRUE;
- }
+}
-static bool reset_null(const char *value)
- {
+static bool
+reset_null(const char *value)
+{
return TRUE;
- }
+}
-static bool parse_geqo (const char *value)
+static bool
+parse_geqo(const char *value)
{
- const char *rest;
- char *tok, *val;
-
- rest = get_token (&tok, &val, value);
- if ( tok == NULL )
- elog(WARN, "Value undefined");
-
- if (( rest ) && ( *rest != '\0' ))
- elog(WARN, "Unable to parse '%s'", value);
-
- if ( strcasecmp (tok, "on") == 0 )
- {
- int32 geqo_rels = GEQO_RELS;
-
- if ( val != NULL )
- {
- geqo_rels = pg_atoi (val, sizeof(int32), '\0');
- if ( geqo_rels <= 1 )
- elog(WARN, "Bad value for # of relations (%s)", val);
- PFREE(val);
- }
- _use_geqo_ = true;
- _use_geqo_rels_ = geqo_rels;
- }
- else if ( strcasecmp (tok, "off") == 0 )
- {
- if (( val != NULL ) && ( *val != '\0' ))
- elog(WARN, "%s does not allow a parameter",tok);
- _use_geqo_ = false;
- }
- else
- elog(WARN, "Bad value for GEQO (%s)", value);
-
- PFREE(tok);
- return TRUE;
+ const char *rest;
+ char *tok,
+ *val;
+
+ rest = get_token(&tok, &val, value);
+ if (tok == NULL)
+ elog(WARN, "Value undefined");
+
+ if ((rest) && (*rest != '\0'))
+ elog(WARN, "Unable to parse '%s'", value);
+
+ if (strcasecmp(tok, "on") == 0)
+ {
+ int32 geqo_rels = GEQO_RELS;
+
+ if (val != NULL)
+ {
+ geqo_rels = pg_atoi(val, sizeof(int32), '\0');
+ if (geqo_rels <= 1)
+ elog(WARN, "Bad value for # of relations (%s)", val);
+ PFREE(val);
+ }
+ _use_geqo_ = true;
+ _use_geqo_rels_ = geqo_rels;
+ }
+ else if (strcasecmp(tok, "off") == 0)
+ {
+ if ((val != NULL) && (*val != '\0'))
+ elog(WARN, "%s does not allow a parameter", tok);
+ _use_geqo_ = false;
+ }
+ else
+ elog(WARN, "Bad value for GEQO (%s)", value);
+
+ PFREE(tok);
+ return TRUE;
}
-static bool show_geqo ()
+static bool
+show_geqo()
{
- if ( _use_geqo_ )
- elog (NOTICE, "GEQO is ON beginning with %d relations", _use_geqo_rels_);
- else
- elog (NOTICE, "GEQO is OFF");
- return TRUE;
+ if (_use_geqo_)
+ elog(NOTICE, "GEQO is ON beginning with %d relations", _use_geqo_rels_);
+ else
+ elog(NOTICE, "GEQO is OFF");
+ return TRUE;
}
-static bool reset_geqo ()
+static bool
+reset_geqo()
{
#ifdef GEQO
- _use_geqo_ = true;
+ _use_geqo_ = true;
#else
- _use_geqo_ = false;
+ _use_geqo_ = false;
#endif
- _use_geqo_rels_ = GEQO_RELS;
- return TRUE;
+ _use_geqo_rels_ = GEQO_RELS;
+ return TRUE;
}
-static bool parse_r_plans (const char *value)
+static bool
+parse_r_plans(const char *value)
{
- if ( strcasecmp (value, "on") == 0 )
- _use_right_sided_plans_ = true;
- else if ( strcasecmp (value, "off") == 0 )
- _use_right_sided_plans_ = false;
- else
- elog(WARN, "Bad value for Right-sided Plans (%s)", value);
-
- return TRUE;
+ if (strcasecmp(value, "on") == 0)
+ _use_right_sided_plans_ = true;
+ else if (strcasecmp(value, "off") == 0)
+ _use_right_sided_plans_ = false;
+ else
+ elog(WARN, "Bad value for Right-sided Plans (%s)", value);
+
+ return TRUE;
}
-static bool show_r_plans ()
+static bool
+show_r_plans()
{
- if ( _use_right_sided_plans_ )
- elog (NOTICE, "Right-sided Plans are ON");
- else
- elog (NOTICE, "Right-sided Plans are OFF");
- return TRUE;
+ if (_use_right_sided_plans_)
+ elog(NOTICE, "Right-sided Plans are ON");
+ else
+ elog(NOTICE, "Right-sided Plans are OFF");
+ return TRUE;
}
-static bool reset_r_plans ()
+static bool
+reset_r_plans()
{
#ifdef USE_RIGHT_SIDED_PLANS
- _use_right_sided_plans_ = true;
+ _use_right_sided_plans_ = true;
#else
- _use_right_sided_plans_ = false;
+ _use_right_sided_plans_ = false;
#endif
- return TRUE;
+ return TRUE;
}
-static bool parse_cost_heap (const char *value)
+static bool
+parse_cost_heap(const char *value)
{
- float32 res = float4in ((char*)value);
-
- _cpu_page_wight_ = *res;
-
- return TRUE;
+ float32 res = float4in((char *) value);
+
+ _cpu_page_wight_ = *res;
+
+ return TRUE;
}
-static bool show_cost_heap ()
+static bool
+show_cost_heap()
{
- elog (NOTICE, "COST_HEAP is %f", _cpu_page_wight_);
- return TRUE;
+ elog(NOTICE, "COST_HEAP is %f", _cpu_page_wight_);
+ return TRUE;
}
-static bool reset_cost_heap ()
+static bool
+reset_cost_heap()
{
- _cpu_page_wight_ = _CPU_PAGE_WEIGHT_;
- return TRUE;
+ _cpu_page_wight_ = _CPU_PAGE_WEIGHT_;
+ return TRUE;
}
-static bool parse_cost_index (const char *value)
+static bool
+parse_cost_index(const char *value)
{
- float32 res = float4in ((char*)value);
-
- _cpu_index_page_wight_ = *res;
-
- return TRUE;
+ float32 res = float4in((char *) value);
+
+ _cpu_index_page_wight_ = *res;
+
+ return TRUE;
}
-static bool show_cost_index ()
+static bool
+show_cost_index()
{
- elog (NOTICE, "COST_INDEX is %f", _cpu_index_page_wight_);
- return TRUE;
+ elog(NOTICE, "COST_INDEX is %f", _cpu_index_page_wight_);
+ return TRUE;
}
-static bool reset_cost_index ()
+static bool
+reset_cost_index()
{
- _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_;
- return TRUE;
+ _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_;
+ return TRUE;
}
-static bool parse_date(const char *value)
+static bool
+parse_date(const char *value)
{
- char *tok;
- int dcnt = 0, ecnt = 0;
+ char *tok;
+ int dcnt = 0,
+ ecnt = 0;
- while((value = get_token(&tok, NULL, value)) != 0)
+ while ((value = get_token(&tok, NULL, value)) != 0)
{
/* Ugh. Somebody ought to write a table driven version -- mjl */
- if(!strcasecmp(tok, "iso"))
- {
+ if (!strcasecmp(tok, "iso"))
+ {
DateStyle = USE_ISO_DATES;
dcnt++;
- }
- else if(!strcasecmp(tok, "sql"))
- {
+ }
+ else if (!strcasecmp(tok, "sql"))
+ {
DateStyle = USE_SQL_DATES;
dcnt++;
- }
- else if(!strcasecmp(tok, "postgres"))
- {
+ }
+ else if (!strcasecmp(tok, "postgres"))
+ {
DateStyle = USE_POSTGRES_DATES;
dcnt++;
- }
- else if(!strncasecmp(tok, "euro", 4))
- {
+ }
+ else if (!strncasecmp(tok, "euro", 4))
+ {
EuroDates = TRUE;
ecnt++;
- }
- else if((!strcasecmp(tok, "us"))
- || (!strncasecmp(tok, "noneuro", 7)))
- {
+ }
+ else if ((!strcasecmp(tok, "us"))
+ || (!strncasecmp(tok, "noneuro", 7)))
+ {
EuroDates = FALSE;
ecnt++;
- }
- else if(!strcasecmp(tok, "default"))
- {
+ }
+ else if (!strcasecmp(tok, "default"))
+ {
DateStyle = USE_POSTGRES_DATES;
EuroDates = FALSE;
ecnt++;
- }
+ }
else
- {
+ {
elog(WARN, "Bad value for date style (%s)", tok);
- }
+ }
PFREE(tok);
}
- if(dcnt > 1 || ecnt > 1)
+ if (dcnt > 1 || ecnt > 1)
elog(NOTICE, "Conflicting settings for date");
return TRUE;
}
-static bool show_date()
- {
- char buf[64];
+static bool
+show_date()
+{
+ char buf[64];
- strcpy( buf, "DateStyle is ");
- switch (DateStyle) {
+ strcpy(buf, "DateStyle is ");
+ switch (DateStyle)
+ {
case USE_ISO_DATES:
- strcat( buf, "ISO");
+ strcat(buf, "ISO");
break;
case USE_SQL_DATES:
- strcat( buf, "SQL");
+ strcat(buf, "SQL");
break;
default:
- strcat( buf, "Postgres");
+ strcat(buf, "Postgres");
break;
};
- strcat( buf, " with ");
- strcat( buf, ((EuroDates)? "European": "US (NonEuropean)"));
- strcat( buf, " conventions");
+ strcat(buf, " with ");
+ strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)"));
+ strcat(buf, " conventions");
elog(NOTICE, buf, NULL);
return TRUE;
- }
+}
-static bool reset_date()
- {
+static bool
+reset_date()
+{
DateStyle = USE_POSTGRES_DATES;
EuroDates = FALSE;
return TRUE;
- }
+}
/*-----------------------------------------------------------------------*/
struct VariableParsers
+{
+ const char *name;
+ bool(*parser) (const char *);
+ bool(*show) ();
+ bool(*reset) ();
+} VariableParsers[] =
+
+{
{
- const char *name;
- bool (*parser)(const char *);
- bool (*show)();
- bool (*reset)();
- } VariableParsers[] =
+ "datestyle", parse_date, show_date, reset_date
+ },
{
- { "datestyle", parse_date, show_date, reset_date },
- { "timezone", parse_null, show_null, reset_null },
- { "cost_heap", parse_cost_heap,
- show_cost_heap, reset_cost_heap },
- { "cost_index", parse_cost_index,
- show_cost_index, reset_cost_index },
- { "geqo", parse_geqo, show_geqo, reset_geqo },
- { "r_plans", parse_r_plans, show_r_plans, reset_r_plans },
- { NULL, NULL, NULL }
- };
+ "timezone", parse_null, show_null, reset_null
+ },
+ {
+ "cost_heap", parse_cost_heap,
+ show_cost_heap, reset_cost_heap
+ },
+ {
+ "cost_index", parse_cost_index,
+ show_cost_index, reset_cost_index
+ },
+ {
+ "geqo", parse_geqo, show_geqo, reset_geqo
+ },
+ {
+ "r_plans", parse_r_plans, show_r_plans, reset_r_plans
+ },
+ {
+ NULL, NULL, NULL
+ }
+};
/*-----------------------------------------------------------------------*/
-bool SetPGVariable(const char *name, const char *value)
- {
+bool
+SetPGVariable(const char *name, const char *value)
+{
struct VariableParsers *vp;
- for(vp = VariableParsers; vp->name; vp++)
- {
- if(!strcasecmp(vp->name, name))
- return (vp->parser)(value);
- }
+ for (vp = VariableParsers; vp->name; vp++)
+ {
+ if (!strcasecmp(vp->name, name))
+ return (vp->parser) (value);
+ }
elog(NOTICE, "Unrecognized variable %s", name);
return TRUE;
- }
+}
/*-----------------------------------------------------------------------*/
-bool GetPGVariable(const char *name)
- {
+bool
+GetPGVariable(const char *name)
+{
struct VariableParsers *vp;
- for(vp = VariableParsers; vp->name; vp++)
- {
- if(!strcasecmp(vp->name, name))
- return (vp->show)();
- }
+ for (vp = VariableParsers; vp->name; vp++)
+ {
+ if (!strcasecmp(vp->name, name))
+ return (vp->show) ();
+ }
elog(NOTICE, "Unrecognized variable %s", name);
return TRUE;
- }
+}
/*-----------------------------------------------------------------------*/
-bool ResetPGVariable(const char *name)
- {
+bool
+ResetPGVariable(const char *name)
+{
struct VariableParsers *vp;
- for(vp = VariableParsers; vp->name; vp++)
- {
- if(!strcasecmp(vp->name, name))
- return (vp->reset)();
- }
+ for (vp = VariableParsers; vp->name; vp++)
+ {
+ if (!strcasecmp(vp->name, name))
+ return (vp->reset) ();
+ }
elog(NOTICE, "Unrecognized variable %s", name);
return TRUE;
- }
+}