diff options
author | Bruce Momjian <bruce@momjian.us> | 1997-09-07 05:04:48 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 1997-09-07 05:04:48 +0000 |
commit | 1ccd423235a48739d6f7a4d7889705b5f9ecc69b (patch) | |
tree | 8001c4e839dfad8f29ceda7f8c5f5dbb8759b564 /src/backend/tcop | |
parent | 8fecd4febf8357f3cc20383ed29ced484877d5ac (diff) | |
download | postgresql-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.c | 952 | ||||
-rw-r--r-- | src/backend/tcop/dest.c | 502 | ||||
-rw-r--r-- | src/backend/tcop/fastpath.c | 520 | ||||
-rw-r--r-- | src/backend/tcop/postgres.c | 2789 | ||||
-rw-r--r-- | src/backend/tcop/pquery.c | 563 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 1212 | ||||
-rw-r--r-- | src/backend/tcop/variable.c | 598 |
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; - } +} |