From 9db64857e0bd31eee463e90c21aba52be8174726 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Mon, 5 Jan 1998 18:43:18 +0000 Subject: Move variable.c to commands/ and aclchk.c to catalog/. --- src/backend/catalog/Makefile | 4 +- src/backend/catalog/aclchk.c | 666 ++++++++++++++++++++++++++++++++++++++++ src/backend/commands/Makefile | 5 +- src/backend/commands/variable.c | 612 ++++++++++++++++++++++++++++++++++++ src/backend/tcop/Makefile | 4 +- src/backend/tcop/aclchk.c | 666 ---------------------------------------- src/backend/tcop/utility.c | 4 +- src/backend/tcop/variable.c | 612 ------------------------------------ src/include/utils/acl.h | 3 +- 9 files changed, 1288 insertions(+), 1288 deletions(-) create mode 100644 src/backend/catalog/aclchk.c create mode 100644 src/backend/commands/variable.c delete mode 100644 src/backend/tcop/aclchk.c delete mode 100644 src/backend/tcop/variable.c (limited to 'src') diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index a8f3159256..050c93c8e8 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -4,7 +4,7 @@ # Makefile for catalog # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/catalog/Makefile,v 1.7 1997/12/20 00:23:26 scrappy Exp $ +# $Header: /cvsroot/pgsql/src/backend/catalog/Makefile,v 1.8 1998/01/05 18:42:39 momjian Exp $ # #------------------------------------------------------------------------- @@ -15,7 +15,7 @@ INCLUDE_OPT = -I.. CFLAGS+=$(INCLUDE_OPT) -OBJS = catalog.o heap.o index.o indexing.o \ +OBJS = catalog.o heap.o index.o indexing.o aclchk.o \ pg_aggregate.o pg_operator.o pg_proc.o pg_type.o all: SUBSYS.o global1.bki.source local1_template1.bki.source \ diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c new file mode 100644 index 0000000000..752399e761 --- /dev/null +++ b/src/backend/catalog/aclchk.c @@ -0,0 +1,666 @@ +/*------------------------------------------------------------------------- + * + * aclchk.c-- + * Routines to check access control permissions. + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.1 1998/01/05 18:42:40 momjian Exp $ + * + * NOTES + * See acl.h. + * + *------------------------------------------------------------------------- + */ +#include +#include "postgres.h" + +#include "utils/acl.h" /* where declarations for this file go */ +#include "access/heapam.h" +#include "access/htup.h" +#include "access/tupmacs.h" +#include "utils/builtins.h" +#include "utils/memutils.h" +#include "utils/palloc.h" +#include "catalog/indexing.h" +#include "catalog/catalog.h" +#include "catalog/catname.h" +#include "catalog/pg_group.h" +#include "catalog/pg_operator.h" +#include "catalog/pg_aggregate.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_type.h" +#include "catalog/pg_user.h" +#include "parser/parse_agg.h" +#include "parser/parse_func.h" +#include "utils/syscache.h" +#include "utils/tqual.h" +#include "fmgr.h" + +static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode); + +/* + * Enable use of user relations in place of real system catalogs. + */ +/*#define ACLDEBUG*/ + +#ifdef ACLDEBUG +/* + * Fool the code below into thinking that "pgacls" is pg_class. + * relname and relowner are in the same place, happily. + */ +#undef Anum_pg_class_relacl +#define Anum_pg_class_relacl 3 +#undef Natts_pg_class +#define Natts_pg_class 3 +#undef Name_pg_class +#define Name_pg_class "pgacls" +#undef Name_pg_group +#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." +}; + +#ifdef ACLDEBUG_TRACE +static +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)); +} + +#endif + +/* + * + */ +void +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(ERROR, "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, + false, + (unsigned) 1, + relkey); + htp = heap_getnext(hsdp, 0, &buffer); + if (!HeapTupleIsValid(htp)) + { + heap_endscan(hsdp); + heap_close(relation); + elog(ERROR, "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"); +#endif +/* old_acl = acldefault(((Form_pg_class) GETSTRUCT(htp))->relowner); */ + old_acl = acldefault(); + free_old_acl = 1; + } + +#ifdef ACLDEBUG_TRACE + dumpacl(old_acl); +#endif + new_acl = aclinsert3(old_acl, mod_aip, modechg); +#ifdef ACLDEBUG_TRACE + 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); +} + +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(ERROR, "non-existent group \"%s\"", groname); + } + return (id); +} + +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); +} + +static int32 +in_group(AclId uid, AclId gid) +{ + Relation relation; + HeapTuple htp; + Acl *tmp; + unsigned i, + num; + AclId *aidp; + int32 found = 0; + + relation = heap_openr(GroupRelationName); + if (!RelationIsValid(relation)) + { + elog(NOTICE, "in_group: could not open \"%s\"??", + GroupRelationName); + return (0); + } + htp = SearchSysCacheTuple(GROSYSID, ObjectIdGetDatum(gid), + 0, 0, 0); + if (HeapTupleIsValid(htp) && + !heap_attisnull(htp, Anum_pg_group_grolist)) + { + tmp = (IdList *) heap_getattr(htp, InvalidBuffer, + 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) + { + found = 1; + break; + } + } + else + { + elog(NOTICE, "in_group: group %d not found", gid); + } + heap_close(relation); + return (found); +} + +/* + * aclcheck + * 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) +{ + 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"); +#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) + { +#ifdef ACLDEBUG_TRACE + 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; + } + } + } + if (found_group) + { +#ifdef ACLDEBUG_TRACE + 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) + { +#ifdef ACLDEBUG_TRACE + elog(DEBUG, "aclcheck: found %d/%d", + aip->ai_id, aip->ai_mode); +#endif + return ((aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV); + } + } + break; + case ACL_IDTYPE_WORLD: + break; + default: + elog(ERROR, "aclcheck: bogus ACL id type: %d", idtype); + break; + } + +#ifdef ACLDEBUG_TRACE + elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode); +#endif + 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(ERROR, "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); +#endif + return ACLCHECK_OK; + } + +#ifndef ACLDEBUG + htp = SearchSysCacheTuple(RELNAME, PointerGetDatum(relname), + 0, 0, 0); + if (!HeapTupleIsValid(htp)) + { + elog(ERROR, "pg_aclcheck: class \"%s\" not found", + relname); + /* an elog(ERROR) 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; + + 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, false, 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); + } +#endif + result = aclcheck(acl, id, (AclIdType) ACL_IDTYPE_UID, mode); + if (acl) + pfree(acl); + return (result); +} + +int32 +pg_ownercheck(char *usename, + char *value, + int cacheid) +{ + HeapTuple htp; + AclId user_id, + owner_id = 0; + + htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename), + 0, 0, 0); + if (!HeapTupleIsValid(htp)) + elog(ERROR, "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); +#endif + return (1); + } + + htp = SearchSysCacheTuple(cacheid, PointerGetDatum(value), + 0, 0, 0); + switch (cacheid) + { + case OPROID: + if (!HeapTupleIsValid(htp)) + elog(ERROR, "pg_ownercheck: operator %ld not found", + PointerGetDatum(value)); + owner_id = ((OperatorTupleForm) GETSTRUCT(htp))->oprowner; + break; + case PRONAME: + if (!HeapTupleIsValid(htp)) + elog(ERROR, "pg_ownercheck: function \"%s\" not found", + value); + owner_id = ((Form_pg_proc) GETSTRUCT(htp))->proowner; + break; + case RELNAME: + if (!HeapTupleIsValid(htp)) + elog(ERROR, "pg_ownercheck: class \"%s\" not found", + value); + owner_id = ((Form_pg_class) GETSTRUCT(htp))->relowner; + break; + case TYPNAME: + if (!HeapTupleIsValid(htp)) + elog(ERROR, "pg_ownercheck: type \"%s\" not found", + value); + owner_id = ((TypeTupleForm) GETSTRUCT(htp))->typowner; + break; + default: + elog(ERROR, "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) +{ + HeapTuple htp; + AclId user_id, + owner_id; + + htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename), + 0, 0, 0); + if (!HeapTupleIsValid(htp)) + elog(ERROR, "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); +#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); +} + +int32 +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(ERROR, "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); +#endif + return (1); + } + + htp = SearchSysCacheTuple(AGGNAME, + PointerGetDatum(aggname), + PointerGetDatum(basetypeID), + 0, + 0); + + if (!HeapTupleIsValid(htp)) + agg_error("pg_aggr_ownercheck", aggname, basetypeID); + + owner_id = ((Form_pg_aggregate) GETSTRUCT(htp))->aggowner; + + return (user_id == owner_id); +} diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile index 97bb016339..a0ed959437 100644 --- a/src/backend/commands/Makefile +++ b/src/backend/commands/Makefile @@ -4,7 +4,7 @@ # Makefile for commands # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.10 1997/12/20 00:23:32 scrappy Exp $ +# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.11 1998/01/05 18:42:45 momjian Exp $ # #------------------------------------------------------------------------- @@ -17,7 +17,8 @@ CFLAGS+=$(INCLUDE_OPT) OBJS = async.o creatinh.o command.o copy.o defind.o define.o \ remove.o rename.o vacuum.o version.o view.o cluster.o \ - recipe.o explain.o sequence.o trigger.o user.o proclang.o dbcommands.o + recipe.o explain.o sequence.o trigger.o user.o proclang.o \ + dbcommands.o variable.o all: SUBSYS.o diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c new file mode 100644 index 0000000000..8ee7e777af --- /dev/null +++ b/src/backend/commands/variable.c @@ -0,0 +1,612 @@ +/* + * Routines for handling of 'SET var TO', + * 'SHOW var' and 'RESET var' statements. + * + * $Id: variable.c,v 1.1 1998/01/05 18:42:50 momjian Exp $ + * + */ + +#include +#include +#include +#include +#include "postgres.h" +#include "miscadmin.h" +#include "commands/variable.h" +#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_; + +/*-----------------------------------------------------------------------*/ +#if USE_EURODATES +#define DATE_EURO TRUE +#else +#define DATE_EURO FALSE +#endif + +/*-----------------------------------------------------------------------*/ +struct PGVariables PGVariables = +{ + {DATE_EURO, Date_Postgres} +}; + +/*-----------------------------------------------------------------------*/ +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(ERROR, "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+1); + + /* 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(ERROR, "Syntax error near (%s)", str); + }; + + str++; /* '=': get value */ + len = 0; + + /* skip white spaces */ + while (isspace(*str)) + str++; + + if (*str == ',' || !(*str)) + elog(ERROR, "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+1); + + /* skip white spaces */ + while (isspace(*str)) + str++; + + if (!(*str)) + return (NULL); + if (*str == ',') + return (++str); + + elog(ERROR, "Syntax error near (%s)", str); + + return str; +} + +/*-----------------------------------------------------------------------*/ +#if FALSE +static bool +parse_null(const char *value) +{ + return TRUE; +} + +static bool +show_null(const char *value) +{ + return TRUE; +} + +static bool +reset_null(const char *value) +{ + return TRUE; +} +#endif + +bool +parse_geqo(const char *value) +{ + const char *rest; + char *tok, + *val; + + if (value == NULL) + { + reset_geqo(); + return TRUE; + } + + rest = get_token(&tok, &val, value); + if (tok == NULL) + elog(ERROR, "Value undefined"); + + if ((rest) && (*rest != '\0')) + elog(ERROR, "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(ERROR, "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(ERROR, "%s does not allow a parameter", tok); + _use_geqo_ = false; + } + else + elog(ERROR, "Bad value for GEQO (%s)", value); + + PFREE(tok); + return TRUE; +} + +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; +} + +bool +reset_geqo(void) +{ + +#ifdef GEQO + _use_geqo_ = true; +#else + _use_geqo_ = false; +#endif + _use_geqo_rels_ = GEQO_RELS; + return TRUE; +} + +bool +parse_r_plans(const char *value) +{ + if (value == NULL) + { + reset_r_plans(); + 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(ERROR, "Bad value for Right-sided Plans (%s)", value); + + return TRUE; +} + +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; +} + +bool +reset_r_plans() +{ + +#ifdef USE_RIGHT_SIDED_PLANS + _use_right_sided_plans_ = true; +#else + _use_right_sided_plans_ = false; +#endif + return TRUE; +} + +bool +parse_cost_heap(const char *value) +{ + float32 res; + + if (value == NULL) + { + reset_cost_heap(); + return TRUE; + } + + res = float4in((char *) value); + _cpu_page_wight_ = *res; + + return TRUE; +} + +bool +show_cost_heap() +{ + + elog(NOTICE, "COST_HEAP is %f", _cpu_page_wight_); + return TRUE; +} + +bool +reset_cost_heap() +{ + _cpu_page_wight_ = _CPU_PAGE_WEIGHT_; + return TRUE; +} + +bool +parse_cost_index(const char *value) +{ + float32 res; + + if (value == NULL) + { + reset_cost_index(); + return TRUE; + } + + res = float4in((char *) value); + _cpu_index_page_wight_ = *res; + + return TRUE; +} + +bool +show_cost_index() +{ + + elog(NOTICE, "COST_INDEX is %f", _cpu_index_page_wight_); + return TRUE; +} + +bool +reset_cost_index() +{ + _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_; + return TRUE; +} + +bool +parse_date(const char *value) +{ + char *tok; + int dcnt = 0, + ecnt = 0; + + if (value == NULL) + { + reset_date(); + return TRUE; + } + + while ((value = get_token(&tok, NULL, value)) != 0) + { + /* Ugh. Somebody ought to write a table driven version -- mjl */ + + if (!strcasecmp(tok, "ISO")) + { + DateStyle = USE_ISO_DATES; + dcnt++; + } + else if (!strcasecmp(tok, "SQL")) + { + DateStyle = USE_SQL_DATES; + dcnt++; + } + else if (!strcasecmp(tok, "POSTGRES")) + { + DateStyle = USE_POSTGRES_DATES; + dcnt++; + } + else if (!strcasecmp(tok, "GERMAN")) + { + DateStyle = USE_GERMAN_DATES; + dcnt++; + EuroDates = TRUE; + if ((ecnt > 0) && (! EuroDates)) ecnt++; + } + else if (!strncasecmp(tok, "EURO", 4)) + { + EuroDates = TRUE; + if ((dcnt <= 0) || (DateStyle != USE_GERMAN_DATES)) ecnt++; + } + else if ((!strcasecmp(tok, "US")) + || (!strncasecmp(tok, "NONEURO", 7))) + { + EuroDates = FALSE; + if ((dcnt <= 0) || (DateStyle == USE_GERMAN_DATES)) ecnt++; + } + else if (!strcasecmp(tok, "DEFAULT")) + { + DateStyle = USE_POSTGRES_DATES; + EuroDates = FALSE; + ecnt++; + } + else + { + elog(ERROR, "Bad value for date style (%s)", tok); + } + PFREE(tok); + } + + if (dcnt > 1 || ecnt > 1) + elog(NOTICE, "Conflicting settings for date"); + + return TRUE; +} + +bool +show_date() +{ + char buf[64]; + + strcpy(buf, "DateStyle is "); + switch (DateStyle) + { + case USE_ISO_DATES: + strcat(buf, "ISO"); + break; + case USE_SQL_DATES: + strcat(buf, "SQL"); + break; + case USE_GERMAN_DATES: + strcat(buf, "German"); + break; + default: + strcat(buf, "Postgres"); + break; + }; + strcat(buf, " with "); + strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)")); + strcat(buf, " conventions"); + + elog(NOTICE, buf, NULL); + + return TRUE; +} + +bool +reset_date() +{ + DateStyle = USE_POSTGRES_DATES; + EuroDates = FALSE; + + return TRUE; +} + +/* Timezone support + * Working storage for strings is allocated with an arbitrary size of 64 bytes. + */ + +static char *defaultTZ = NULL; +static char TZvalue[64]; +static char tzbuf[64]; + +/* parse_timezone() + * Handle SET TIME ZONE... + * Try to save existing TZ environment variable for later use in RESET TIME ZONE. + * - thomas 1997-11-10 + */ +bool +parse_timezone(const char *value) +{ + char *tok; + + if (value == NULL) + { + reset_timezone(); + return TRUE; + } + + while ((value = get_token(&tok, NULL, value)) != 0) + { + /* Not yet tried to save original value from environment? */ + if (defaultTZ == NULL) + { + /* found something? then save it for later */ + if (getenv("TZ") != NULL) + { + defaultTZ = getenv("TZ"); + if (defaultTZ == NULL) + defaultTZ = (char *) -1; + else + strcpy(TZvalue, defaultTZ); + } + /* found nothing so mark with an invalid pointer */ + else + { + defaultTZ = (char *) -1; + } + } + + strcpy(tzbuf, "TZ="); + strcat(tzbuf, tok); + if (putenv(tzbuf) != 0) + elog(ERROR, "Unable to set TZ environment variable to %s", tok); + + tzset(); + PFREE(tok); + } + + return TRUE; +} /* parse_timezone() */ + +bool +show_timezone() +{ + char *tz; + + tz = getenv("TZ"); + + elog(NOTICE, "Time zone is %s", ((tz != NULL)? tz: "unknown")); + + return TRUE; +} /* show_timezone() */ + +/* reset_timezone() + * Set TZ environment variable to original value. + * Note that if TZ was originally not set, TZ should be cleared. + * unsetenv() works fine, but is BSD, not POSIX, and is not available + * under Solaris, among others. Apparently putenv() called as below + * clears the process-specific environment variables. + * Other reasonable arguments to putenv() (e.g. "TZ=", "TZ", "") result + * in a core dump (under Linux anyway). + */ +bool +reset_timezone() +{ + if ((defaultTZ != NULL) && (defaultTZ != (char *) -1)) + { + strcpy(tzbuf, "TZ="); + strcat(tzbuf, TZvalue); + if (putenv(tzbuf) != 0) + elog(ERROR, "Unable to set TZ environment variable to %s", TZvalue); + } + else + { + strcpy(tzbuf, "="); + if (putenv(tzbuf) != 0) + elog(ERROR, "Unable to clear TZ environment variable", NULL); + } + tzset(); + + return TRUE; +} /* reset_timezone() */ + +/*-----------------------------------------------------------------------*/ +struct VariableParsers +{ + const char *name; + bool (*parser) (const char *); + bool (*show) (); + bool (*reset) (); +} VariableParsers[] = + +{ + { "datestyle", parse_date, show_date, reset_date }, + { "timezone", parse_timezone, show_timezone, reset_timezone }, + { "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, NULL } +}; + +/*-----------------------------------------------------------------------*/ +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); + } + + elog(NOTICE, "Unrecognized variable %s", name); + + return TRUE; +} + +/*-----------------------------------------------------------------------*/ +bool +GetPGVariable(const char *name) +{ + struct VariableParsers *vp; + + 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) +{ + struct VariableParsers *vp; + + for (vp = VariableParsers; vp->name; vp++) + { + if (!strcasecmp(vp->name, name)) + return (vp->reset) (); + } + + elog(NOTICE, "Unrecognized variable %s", name); + + return TRUE; +} diff --git a/src/backend/tcop/Makefile b/src/backend/tcop/Makefile index f756a13312..908160fae1 100644 --- a/src/backend/tcop/Makefile +++ b/src/backend/tcop/Makefile @@ -4,7 +4,7 @@ # Makefile for tcop # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/tcop/Makefile,v 1.14 1997/12/20 00:28:06 scrappy Exp $ +# $Header: /cvsroot/pgsql/src/backend/tcop/Makefile,v 1.15 1998/01/05 18:42:59 momjian Exp $ # #------------------------------------------------------------------------- @@ -19,7 +19,7 @@ ifeq ($(CC), gcc) CFLAGS+= -Wno-error endif -OBJS= aclchk.o dest.o fastpath.o postgres.o pquery.o utility.o variable.o +OBJS= dest.o fastpath.o postgres.o pquery.o utility.o all: SUBSYS.o diff --git a/src/backend/tcop/aclchk.c b/src/backend/tcop/aclchk.c deleted file mode 100644 index 8064a316d5..0000000000 --- a/src/backend/tcop/aclchk.c +++ /dev/null @@ -1,666 +0,0 @@ -/*------------------------------------------------------------------------- - * - * aclchk.c-- - * 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.22 1998/01/05 16:39:30 momjian Exp $ - * - * NOTES - * See acl.h. - * - *------------------------------------------------------------------------- - */ -#include -#include "postgres.h" - -#include "utils/acl.h" /* where declarations for this file go */ -#include "access/heapam.h" -#include "access/htup.h" -#include "access/tupmacs.h" -#include "utils/builtins.h" -#include "utils/memutils.h" -#include "utils/palloc.h" -#include "catalog/indexing.h" -#include "catalog/catalog.h" -#include "catalog/catname.h" -#include "catalog/pg_group.h" -#include "catalog/pg_operator.h" -#include "catalog/pg_aggregate.h" -#include "catalog/pg_proc.h" -#include "catalog/pg_type.h" -#include "catalog/pg_user.h" -#include "parser/parse_agg.h" -#include "parser/parse_func.h" -#include "utils/syscache.h" -#include "utils/tqual.h" -#include "fmgr.h" - -static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode); - -/* - * Enable use of user relations in place of real system catalogs. - */ -/*#define ACLDEBUG*/ - -#ifdef ACLDEBUG -/* - * Fool the code below into thinking that "pgacls" is pg_class. - * relname and relowner are in the same place, happily. - */ -#undef Anum_pg_class_relacl -#define Anum_pg_class_relacl 3 -#undef Natts_pg_class -#define Natts_pg_class 3 -#undef Name_pg_class -#define Name_pg_class "pgacls" -#undef Name_pg_group -#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." -}; - -#ifdef ACLDEBUG_TRACE -static -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)); -} - -#endif - -/* - * - */ -void -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(ERROR, "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, - false, - (unsigned) 1, - relkey); - htp = heap_getnext(hsdp, 0, &buffer); - if (!HeapTupleIsValid(htp)) - { - heap_endscan(hsdp); - heap_close(relation); - elog(ERROR, "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"); -#endif -/* old_acl = acldefault(((Form_pg_class) GETSTRUCT(htp))->relowner); */ - old_acl = acldefault(); - free_old_acl = 1; - } - -#ifdef ACLDEBUG_TRACE - dumpacl(old_acl); -#endif - new_acl = aclinsert3(old_acl, mod_aip, modechg); -#ifdef ACLDEBUG_TRACE - 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); -} - -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(ERROR, "non-existent group \"%s\"", groname); - } - return (id); -} - -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); -} - -static int32 -in_group(AclId uid, AclId gid) -{ - Relation relation; - HeapTuple htp; - Acl *tmp; - unsigned i, - num; - AclId *aidp; - int32 found = 0; - - relation = heap_openr(GroupRelationName); - if (!RelationIsValid(relation)) - { - elog(NOTICE, "in_group: could not open \"%s\"??", - GroupRelationName); - return (0); - } - htp = SearchSysCacheTuple(GROSYSID, ObjectIdGetDatum(gid), - 0, 0, 0); - if (HeapTupleIsValid(htp) && - !heap_attisnull(htp, Anum_pg_group_grolist)) - { - tmp = (IdList *) heap_getattr(htp, InvalidBuffer, - 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) - { - found = 1; - break; - } - } - else - { - elog(NOTICE, "in_group: group %d not found", gid); - } - heap_close(relation); - return (found); -} - -/* - * aclcheck - * 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) -{ - 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"); -#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) - { -#ifdef ACLDEBUG_TRACE - 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; - } - } - } - if (found_group) - { -#ifdef ACLDEBUG_TRACE - 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) - { -#ifdef ACLDEBUG_TRACE - elog(DEBUG, "aclcheck: found %d/%d", - aip->ai_id, aip->ai_mode); -#endif - return ((aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV); - } - } - break; - case ACL_IDTYPE_WORLD: - break; - default: - elog(ERROR, "aclcheck: bogus ACL id type: %d", idtype); - break; - } - -#ifdef ACLDEBUG_TRACE - elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode); -#endif - 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(ERROR, "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); -#endif - return ACLCHECK_OK; - } - -#ifndef ACLDEBUG - htp = SearchSysCacheTuple(RELNAME, PointerGetDatum(relname), - 0, 0, 0); - if (!HeapTupleIsValid(htp)) - { - elog(ERROR, "pg_aclcheck: class \"%s\" not found", - relname); - /* an elog(ERROR) 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; - - 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, false, 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); - } -#endif - result = aclcheck(acl, id, (AclIdType) ACL_IDTYPE_UID, mode); - if (acl) - pfree(acl); - return (result); -} - -int32 -pg_ownercheck(char *usename, - char *value, - int cacheid) -{ - HeapTuple htp; - AclId user_id, - owner_id = 0; - - htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename), - 0, 0, 0); - if (!HeapTupleIsValid(htp)) - elog(ERROR, "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); -#endif - return (1); - } - - htp = SearchSysCacheTuple(cacheid, PointerGetDatum(value), - 0, 0, 0); - switch (cacheid) - { - case OPROID: - if (!HeapTupleIsValid(htp)) - elog(ERROR, "pg_ownercheck: operator %ld not found", - PointerGetDatum(value)); - owner_id = ((OperatorTupleForm) GETSTRUCT(htp))->oprowner; - break; - case PRONAME: - if (!HeapTupleIsValid(htp)) - elog(ERROR, "pg_ownercheck: function \"%s\" not found", - value); - owner_id = ((Form_pg_proc) GETSTRUCT(htp))->proowner; - break; - case RELNAME: - if (!HeapTupleIsValid(htp)) - elog(ERROR, "pg_ownercheck: class \"%s\" not found", - value); - owner_id = ((Form_pg_class) GETSTRUCT(htp))->relowner; - break; - case TYPNAME: - if (!HeapTupleIsValid(htp)) - elog(ERROR, "pg_ownercheck: type \"%s\" not found", - value); - owner_id = ((TypeTupleForm) GETSTRUCT(htp))->typowner; - break; - default: - elog(ERROR, "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) -{ - HeapTuple htp; - AclId user_id, - owner_id; - - htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename), - 0, 0, 0); - if (!HeapTupleIsValid(htp)) - elog(ERROR, "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); -#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); -} - -int32 -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(ERROR, "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); -#endif - return (1); - } - - htp = SearchSysCacheTuple(AGGNAME, - PointerGetDatum(aggname), - PointerGetDatum(basetypeID), - 0, - 0); - - if (!HeapTupleIsValid(htp)) - agg_error("pg_aggr_ownercheck", aggname, basetypeID); - - owner_id = ((Form_pg_aggregate) GETSTRUCT(htp))->aggowner; - - return (user_id == owner_id); -} diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index ad484390ae..74cd794f01 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.35 1998/01/05 16:39:32 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.36 1998/01/05 18:43:09 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -35,6 +35,7 @@ #include "commands/explain.h" #include "commands/trigger.h" #include "commands/proclang.h" +#include "commands/variable.h" #include "nodes/parsenodes.h" #include "../backend/parser/parse.h" @@ -45,7 +46,6 @@ #include "rewrite/rewriteDefine.h" #include "tcop/tcopdebug.h" #include "tcop/dest.h" -#include "tcop/variable.h" #include "tcop/utility.h" #include "fmgr.h" /* For load_file() */ #include "storage/fd.h" diff --git a/src/backend/tcop/variable.c b/src/backend/tcop/variable.c deleted file mode 100644 index 82bd737c41..0000000000 --- a/src/backend/tcop/variable.c +++ /dev/null @@ -1,612 +0,0 @@ -/* - * Routines for handling of 'SET var TO', - * 'SHOW var' and 'RESET var' statements. - * - * $Id: variable.c,v 1.26 1998/01/05 16:39:35 momjian Exp $ - * - */ - -#include -#include -#include -#include -#include "postgres.h" -#include "miscadmin.h" -#include "tcop/variable.h" -#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_; - -/*-----------------------------------------------------------------------*/ -#if USE_EURODATES -#define DATE_EURO TRUE -#else -#define DATE_EURO FALSE -#endif - -/*-----------------------------------------------------------------------*/ -struct PGVariables PGVariables = -{ - {DATE_EURO, Date_Postgres} -}; - -/*-----------------------------------------------------------------------*/ -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(ERROR, "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+1); - - /* 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(ERROR, "Syntax error near (%s)", str); - }; - - str++; /* '=': get value */ - len = 0; - - /* skip white spaces */ - while (isspace(*str)) - str++; - - if (*str == ',' || !(*str)) - elog(ERROR, "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+1); - - /* skip white spaces */ - while (isspace(*str)) - str++; - - if (!(*str)) - return (NULL); - if (*str == ',') - return (++str); - - elog(ERROR, "Syntax error near (%s)", str); - - return str; -} - -/*-----------------------------------------------------------------------*/ -#if FALSE -static bool -parse_null(const char *value) -{ - return TRUE; -} - -static bool -show_null(const char *value) -{ - return TRUE; -} - -static bool -reset_null(const char *value) -{ - return TRUE; -} -#endif - -bool -parse_geqo(const char *value) -{ - const char *rest; - char *tok, - *val; - - if (value == NULL) - { - reset_geqo(); - return TRUE; - } - - rest = get_token(&tok, &val, value); - if (tok == NULL) - elog(ERROR, "Value undefined"); - - if ((rest) && (*rest != '\0')) - elog(ERROR, "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(ERROR, "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(ERROR, "%s does not allow a parameter", tok); - _use_geqo_ = false; - } - else - elog(ERROR, "Bad value for GEQO (%s)", value); - - PFREE(tok); - return TRUE; -} - -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; -} - -bool -reset_geqo(void) -{ - -#ifdef GEQO - _use_geqo_ = true; -#else - _use_geqo_ = false; -#endif - _use_geqo_rels_ = GEQO_RELS; - return TRUE; -} - -bool -parse_r_plans(const char *value) -{ - if (value == NULL) - { - reset_r_plans(); - 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(ERROR, "Bad value for Right-sided Plans (%s)", value); - - return TRUE; -} - -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; -} - -bool -reset_r_plans() -{ - -#ifdef USE_RIGHT_SIDED_PLANS - _use_right_sided_plans_ = true; -#else - _use_right_sided_plans_ = false; -#endif - return TRUE; -} - -bool -parse_cost_heap(const char *value) -{ - float32 res; - - if (value == NULL) - { - reset_cost_heap(); - return TRUE; - } - - res = float4in((char *) value); - _cpu_page_wight_ = *res; - - return TRUE; -} - -bool -show_cost_heap() -{ - - elog(NOTICE, "COST_HEAP is %f", _cpu_page_wight_); - return TRUE; -} - -bool -reset_cost_heap() -{ - _cpu_page_wight_ = _CPU_PAGE_WEIGHT_; - return TRUE; -} - -bool -parse_cost_index(const char *value) -{ - float32 res; - - if (value == NULL) - { - reset_cost_index(); - return TRUE; - } - - res = float4in((char *) value); - _cpu_index_page_wight_ = *res; - - return TRUE; -} - -bool -show_cost_index() -{ - - elog(NOTICE, "COST_INDEX is %f", _cpu_index_page_wight_); - return TRUE; -} - -bool -reset_cost_index() -{ - _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_; - return TRUE; -} - -bool -parse_date(const char *value) -{ - char *tok; - int dcnt = 0, - ecnt = 0; - - if (value == NULL) - { - reset_date(); - return TRUE; - } - - while ((value = get_token(&tok, NULL, value)) != 0) - { - /* Ugh. Somebody ought to write a table driven version -- mjl */ - - if (!strcasecmp(tok, "ISO")) - { - DateStyle = USE_ISO_DATES; - dcnt++; - } - else if (!strcasecmp(tok, "SQL")) - { - DateStyle = USE_SQL_DATES; - dcnt++; - } - else if (!strcasecmp(tok, "POSTGRES")) - { - DateStyle = USE_POSTGRES_DATES; - dcnt++; - } - else if (!strcasecmp(tok, "GERMAN")) - { - DateStyle = USE_GERMAN_DATES; - dcnt++; - EuroDates = TRUE; - if ((ecnt > 0) && (! EuroDates)) ecnt++; - } - else if (!strncasecmp(tok, "EURO", 4)) - { - EuroDates = TRUE; - if ((dcnt <= 0) || (DateStyle != USE_GERMAN_DATES)) ecnt++; - } - else if ((!strcasecmp(tok, "US")) - || (!strncasecmp(tok, "NONEURO", 7))) - { - EuroDates = FALSE; - if ((dcnt <= 0) || (DateStyle == USE_GERMAN_DATES)) ecnt++; - } - else if (!strcasecmp(tok, "DEFAULT")) - { - DateStyle = USE_POSTGRES_DATES; - EuroDates = FALSE; - ecnt++; - } - else - { - elog(ERROR, "Bad value for date style (%s)", tok); - } - PFREE(tok); - } - - if (dcnt > 1 || ecnt > 1) - elog(NOTICE, "Conflicting settings for date"); - - return TRUE; -} - -bool -show_date() -{ - char buf[64]; - - strcpy(buf, "DateStyle is "); - switch (DateStyle) - { - case USE_ISO_DATES: - strcat(buf, "ISO"); - break; - case USE_SQL_DATES: - strcat(buf, "SQL"); - break; - case USE_GERMAN_DATES: - strcat(buf, "German"); - break; - default: - strcat(buf, "Postgres"); - break; - }; - strcat(buf, " with "); - strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)")); - strcat(buf, " conventions"); - - elog(NOTICE, buf, NULL); - - return TRUE; -} - -bool -reset_date() -{ - DateStyle = USE_POSTGRES_DATES; - EuroDates = FALSE; - - return TRUE; -} - -/* Timezone support - * Working storage for strings is allocated with an arbitrary size of 64 bytes. - */ - -static char *defaultTZ = NULL; -static char TZvalue[64]; -static char tzbuf[64]; - -/* parse_timezone() - * Handle SET TIME ZONE... - * Try to save existing TZ environment variable for later use in RESET TIME ZONE. - * - thomas 1997-11-10 - */ -bool -parse_timezone(const char *value) -{ - char *tok; - - if (value == NULL) - { - reset_timezone(); - return TRUE; - } - - while ((value = get_token(&tok, NULL, value)) != 0) - { - /* Not yet tried to save original value from environment? */ - if (defaultTZ == NULL) - { - /* found something? then save it for later */ - if (getenv("TZ") != NULL) - { - defaultTZ = getenv("TZ"); - if (defaultTZ == NULL) - defaultTZ = (char *) -1; - else - strcpy(TZvalue, defaultTZ); - } - /* found nothing so mark with an invalid pointer */ - else - { - defaultTZ = (char *) -1; - } - } - - strcpy(tzbuf, "TZ="); - strcat(tzbuf, tok); - if (putenv(tzbuf) != 0) - elog(ERROR, "Unable to set TZ environment variable to %s", tok); - - tzset(); - PFREE(tok); - } - - return TRUE; -} /* parse_timezone() */ - -bool -show_timezone() -{ - char *tz; - - tz = getenv("TZ"); - - elog(NOTICE, "Time zone is %s", ((tz != NULL)? tz: "unknown")); - - return TRUE; -} /* show_timezone() */ - -/* reset_timezone() - * Set TZ environment variable to original value. - * Note that if TZ was originally not set, TZ should be cleared. - * unsetenv() works fine, but is BSD, not POSIX, and is not available - * under Solaris, among others. Apparently putenv() called as below - * clears the process-specific environment variables. - * Other reasonable arguments to putenv() (e.g. "TZ=", "TZ", "") result - * in a core dump (under Linux anyway). - */ -bool -reset_timezone() -{ - if ((defaultTZ != NULL) && (defaultTZ != (char *) -1)) - { - strcpy(tzbuf, "TZ="); - strcat(tzbuf, TZvalue); - if (putenv(tzbuf) != 0) - elog(ERROR, "Unable to set TZ environment variable to %s", TZvalue); - } - else - { - strcpy(tzbuf, "="); - if (putenv(tzbuf) != 0) - elog(ERROR, "Unable to clear TZ environment variable", NULL); - } - tzset(); - - return TRUE; -} /* reset_timezone() */ - -/*-----------------------------------------------------------------------*/ -struct VariableParsers -{ - const char *name; - bool (*parser) (const char *); - bool (*show) (); - bool (*reset) (); -} VariableParsers[] = - -{ - { "datestyle", parse_date, show_date, reset_date }, - { "timezone", parse_timezone, show_timezone, reset_timezone }, - { "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, NULL } -}; - -/*-----------------------------------------------------------------------*/ -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); - } - - elog(NOTICE, "Unrecognized variable %s", name); - - return TRUE; -} - -/*-----------------------------------------------------------------------*/ -bool -GetPGVariable(const char *name) -{ - struct VariableParsers *vp; - - 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) -{ - struct VariableParsers *vp; - - for (vp = VariableParsers; vp->name; vp++) - { - if (!strcasecmp(vp->name, name)) - return (vp->reset) (); - } - - elog(NOTICE, "Unrecognized variable %s", name); - - return TRUE; -} diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index b35dbd199a..8e0ebc84b6 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: acl.h,v 1.11 1997/09/08 21:54:47 momjian Exp $ + * $Id: acl.h,v 1.12 1998/01/05 18:43:18 momjian Exp $ * * NOTES * For backward-compatability purposes we have to allow there @@ -162,7 +162,6 @@ extern void ChangeAcl(char *relname, AclItem *mod_aip, unsigned modechg); extern AclId get_grosysid(char *groname); extern char *get_groname(AclId grosysid); -/* XXX move these elsewhere -pma */ extern int32 pg_aclcheck(char *relname, char *usename, AclMode mode); extern int32 pg_ownercheck(char *usename, char *value, int cacheid); extern int32 -- cgit v1.2.1