From e7889b83b7059e776f0a3d76bbbdd98687f4592c Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 3 Sep 2007 18:46:30 +0000 Subject: [PATCH] Support SET FROM CURRENT in CREATE/ALTER FUNCTION, ALTER DATABASE, ALTER ROLE. (Actually, it works as a plain statement too, but I didn't document that because it seems a bit useless.) Unify VariableResetStmt with VariableSetStmt, and clean up some ancient cruft in the representation of same. --- doc/src/sgml/ref/alter_database.sgml | 98 +++++++------- doc/src/sgml/ref/alter_function.sgml | 14 +- doc/src/sgml/ref/alter_role.sgml | 8 +- doc/src/sgml/ref/alter_user.sgml | 4 +- doc/src/sgml/ref/create_function.sgml | 8 +- src/backend/commands/dbcommands.c | 20 +-- src/backend/commands/functioncmds.c | 33 ++--- src/backend/commands/user.c | 22 +-- src/backend/nodes/copyfuncs.c | 22 +-- src/backend/nodes/equalfuncs.c | 20 +-- src/backend/parser/gram.y | 188 +++++++++++++------------- src/backend/tcop/pquery.c | 3 +- src/backend/tcop/utility.c | 80 +++-------- src/backend/utils/misc/guc.c | 131 ++++++++++++++---- src/include/nodes/nodes.h | 3 +- src/include/nodes/parsenodes.h | 81 ++++++----- src/include/utils/guc.h | 7 +- 17 files changed, 382 insertions(+), 360 deletions(-) diff --git a/doc/src/sgml/ref/alter_database.sgml b/doc/src/sgml/ref/alter_database.sgml index 8ddff97e02..d16cc2fdad 100644 --- a/doc/src/sgml/ref/alter_database.sgml +++ b/doc/src/sgml/ref/alter_database.sgml @@ -1,5 +1,5 @@ @@ -26,12 +26,14 @@ where option can be: CONNECTION LIMIT connlimit -ALTER DATABASE name SET parameter { TO | = } { value | DEFAULT } -ALTER DATABASE name RESET parameter - ALTER DATABASE name RENAME TO newname ALTER DATABASE name OWNER TO new_owner + +ALTER DATABASE name SET configuration_parameter { TO | = } { value | DEFAULT } +ALTER DATABASE name SET configuration_parameter FROM CURRENT +ALTER DATABASE name RESET configuration_parameter +ALTER DATABASE name RESET ALL @@ -49,7 +51,24 @@ ALTER DATABASE name OWNER TO - The second and third forms change the session default for a run-time + The second form changes the name of the database. Only the database + owner or a superuser can rename a database; non-superuser owners must + also have the + CREATEDB privilege. The current database cannot + be renamed. (Connect to a different database if you need to do + that.) + + + + The third form changes the owner of the database. + To alter the owner, you must own the database and also be a direct or + indirect member of the new owning role, and you must have the + CREATEDB privilege. + (Note that superusers have all these privileges automatically.) + + + + The remaining forms change the session default for a run-time configuration variable for a PostgreSQL database. Whenever a new session is subsequently started in that database, the specified value becomes the session default value. @@ -60,23 +79,6 @@ ALTER DATABASE name OWNER TO - - - The fourth form changes the name of the database. Only the database - owner or a superuser can rename a database; non-superuser owners must - also have the - CREATEDB privilege. The current database cannot - be renamed. (Connect to a different database if you need to do - that.) - - - - The fifth form changes the owner of the database. - To alter the owner, you must own the database and also be a direct or - indirect member of the new owning role, and you must have the - CREATEDB privilege. - (Note that superusers have all these privileges automatically.) - @@ -102,28 +104,6 @@ ALTER DATABASE name OWNER TO - - parameter - value - - - Set this database's session default for the specified configuration - parameter to the given value. If - value is DEFAULT - or, equivalently, RESET is used, the - database-specific setting is removed, so the system-wide default - setting will be inherited in new sessions. Use RESET - ALL to clear all database-specific settings. - - - - See and - for more information about allowed parameter names - and values. - - - - newname @@ -141,6 +121,30 @@ ALTER DATABASE name OWNER TO + + + configuration_parameter + value + + + Set this database's session default for the specified configuration + parameter to the given value. If + value is DEFAULT + or, equivalently, RESET is used, the + database-specific setting is removed, so the system-wide default + setting will be inherited in new sessions. Use RESET + ALL to clear all database-specific settings. + SET FROM CURRENT saves the session's current value of + the parameter as the database-specific value. + + + + See and + for more information about allowed parameter names + and values. + + + @@ -148,10 +152,10 @@ ALTER DATABASE name OWNER TO Notes - It is also possible to tie a session default to a specific user + It is also possible to tie a session default to a specific role rather than to a database; see - . - User-specific settings override database-specific + . + Role-specific settings override database-specific ones if there is a conflict. diff --git a/doc/src/sgml/ref/alter_function.sgml b/doc/src/sgml/ref/alter_function.sgml index 964603b067..bee2f6f439 100644 --- a/doc/src/sgml/ref/alter_function.sgml +++ b/doc/src/sgml/ref/alter_function.sgml @@ -1,5 +1,5 @@ @@ -21,7 +21,7 @@ PostgreSQL documentation ALTER FUNCTION name ( [ [ argmode ] [ argname ] argtype [, ...] ] ) - action [, ... ] [ RESTRICT ] + action [ ... ] [ RESTRICT ] ALTER FUNCTION name ( [ [ argmode ] [ argname ] argtype [, ...] ] ) RENAME TO new_name ALTER FUNCTION name ( [ [ argmode ] [ argname ] argtype [, ...] ] ) @@ -36,8 +36,10 @@ where action is one of: [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER COST execution_cost ROWS result_rows - SET parameter { TO | = } { value | DEFAULT } - RESET parameter + SET configuration_parameter { TO | = } { value | DEFAULT } + SET configuration_parameter FROM CURRENT + RESET configuration_parameter + RESET ALL @@ -215,7 +217,7 @@ where action is one of: - parameter + configuration_parameter value @@ -226,6 +228,8 @@ where action is one of: setting is removed, so that the function executes with the value present in its environment. Use RESET ALL to clear all function-local settings. + SET FROM CURRENT saves the session's current value of + the parameter as the value to be applied when the function is entered. diff --git a/doc/src/sgml/ref/alter_role.sgml b/doc/src/sgml/ref/alter_role.sgml index ce28f2ad59..a471095e49 100644 --- a/doc/src/sgml/ref/alter_role.sgml +++ b/doc/src/sgml/ref/alter_role.sgml @@ -1,5 +1,5 @@ @@ -37,7 +37,9 @@ where option can be: ALTER ROLE name RENAME TO newname ALTER ROLE name SET configuration_parameter { TO | = } { value | DEFAULT } +ALTER ROLE name SET configuration_parameter FROM CURRENT ALTER ROLE name RESET configuration_parameter +ALTER ROLE name RESET ALL @@ -77,7 +79,7 @@ ALTER ROLE name RESET - The third and the fourth variant change a role's session default for + The remaining variants change a role's session default for a specified configuration variable. Whenever the role subsequently starts a new session, the specified value becomes the session default, overriding whatever setting is present in postgresql.conf @@ -155,6 +157,8 @@ ALTER ROLE name RESET role-specific variable setting is removed, so the role will inherit the system-wide default setting in new sessions. Use RESET ALL to clear all role-specific settings. + SET FROM CURRENT saves the session's current value of + the parameter as the role-specific value. diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml index 8f41a35e7a..f989651d6f 100644 --- a/doc/src/sgml/ref/alter_user.sgml +++ b/doc/src/sgml/ref/alter_user.sgml @@ -1,5 +1,5 @@ @@ -37,7 +37,9 @@ where option can be: ALTER USER name RENAME TO newname ALTER USER name SET configuration_parameter { TO | = } { value | DEFAULT } +ALTER USER name SET configuration_parameter FROM CURRENT ALTER USER name RESET configuration_parameter +ALTER USER name RESET ALL diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml index 7aff876d37..b0cfe84db1 100644 --- a/doc/src/sgml/ref/create_function.sgml +++ b/doc/src/sgml/ref/create_function.sgml @@ -1,5 +1,5 @@ @@ -28,7 +28,7 @@ CREATE [ OR REPLACE ] FUNCTION | [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | COST execution_cost | ROWS result_rows - | SET parameter { TO | = } { value | DEFAULT } + | SET configuration_parameter { TO value | = value | FROM CURRENT } | AS 'definition' | AS 'obj_file', 'link_symbol' } ... @@ -324,13 +324,15 @@ CREATE [ OR REPLACE ] FUNCTION - parameter + configuration_parameter value The SET clause causes the specified configuration parameter to be set to the specified value when the function is entered, and then restored to its prior value when the function exits. + SET FROM CURRENT saves the session's current value of + the parameter as the value to be applied when the function is entered. diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 34b6da99df..f627480362 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.197 2007/08/01 22:45:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.198 2007/09/03 18:46:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -886,7 +886,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) char repl_null[Natts_pg_database]; char repl_repl[Natts_pg_database]; - valuestr = flatten_set_variable_args(stmt->variable, stmt->value); + valuestr = ExtractSetVariableArgs(stmt->setstmt); /* * Get the old tuple. We don't need a lock on the database per se, @@ -910,12 +910,12 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, stmt->dbname); - MemSet(repl_repl, ' ', sizeof(repl_repl)); + memset(repl_repl, ' ', sizeof(repl_repl)); repl_repl[Anum_pg_database_datconfig - 1] = 'r'; - if (strcmp(stmt->variable, "all") == 0 && valuestr == NULL) + if (stmt->setstmt->kind == VAR_RESET_ALL) { - /* RESET ALL */ + /* RESET ALL, so just set datconfig to null */ repl_null[Anum_pg_database_datconfig - 1] = 'n'; repl_val[Anum_pg_database_datconfig - 1] = (Datum) 0; } @@ -927,15 +927,16 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) repl_null[Anum_pg_database_datconfig - 1] = ' '; + /* Extract old value of datconfig */ datum = heap_getattr(tuple, Anum_pg_database_datconfig, RelationGetDescr(rel), &isnull); - a = isnull ? NULL : DatumGetArrayTypeP(datum); + /* Update (valuestr is NULL in RESET cases) */ if (valuestr) - a = GUCArrayAdd(a, stmt->variable, valuestr); + a = GUCArrayAdd(a, stmt->setstmt->name, valuestr); else - a = GUCArrayDelete(a, stmt->variable); + a = GUCArrayDelete(a, stmt->setstmt->name); if (a) repl_val[Anum_pg_database_datconfig - 1] = PointerGetDatum(a); @@ -943,7 +944,8 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) repl_null[Anum_pg_database_datconfig - 1] = 'n'; } - newtuple = heap_modifytuple(tuple, RelationGetDescr(rel), repl_val, repl_null, repl_repl); + newtuple = heap_modifytuple(tuple, RelationGetDescr(rel), + repl_val, repl_null, repl_repl); simple_heap_update(rel, &tuple->t_self, newtuple); /* Update indexes */ diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index a6768ab83c..9e5d0b1095 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.84 2007/09/03 00:39:15 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.85 2007/09/03 18:46:29 tgl Exp $ * * DESCRIPTION * These routines take the parse tree and pick out the @@ -354,7 +354,7 @@ interpret_func_volatility(DefElem *defel) } /* - * Update a proconfig value according to a list of SET and RESET items. + * Update a proconfig value according to a list of VariableSetStmt items. * * The input and result may be NULL to signify a null entry. */ @@ -365,33 +365,20 @@ update_proconfig_value(ArrayType *a, List *set_items) foreach(l, set_items) { - Node *sitem = (Node *) lfirst(l); + VariableSetStmt *sstmt = (VariableSetStmt *) lfirst(l); - if (IsA(sitem, VariableSetStmt)) + Assert(IsA(sstmt, VariableSetStmt)); + if (sstmt->kind == VAR_RESET_ALL) + a = NULL; + else { - VariableSetStmt *sstmt = (VariableSetStmt *) sitem; + char *valuestr = ExtractSetVariableArgs(sstmt); - if (sstmt->args) - { - char *valuestr; - - valuestr = flatten_set_variable_args(sstmt->name, sstmt->args); + if (valuestr) a = GUCArrayAdd(a, sstmt->name, valuestr); - } - else /* SET TO DEFAULT */ + else /* RESET */ a = GUCArrayDelete(a, sstmt->name); } - else if (IsA(sitem, VariableResetStmt)) - { - VariableResetStmt *rstmt = (VariableResetStmt *) sitem; - - if (strcmp(rstmt->name, "all") == 0) - a = NULL; /* RESET ALL */ - else - a = GUCArrayDelete(a, rstmt->name); - } - else - elog(ERROR, "unexpected node type: %d", nodeTag(sitem)); } return a; diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index cbbc31ca6f..ccf34178a0 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.176 2007/02/01 19:10:26 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.177 2007/09/03 18:46:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -721,9 +721,8 @@ AlterRoleSet(AlterRoleSetStmt *stmt) Datum repl_val[Natts_pg_authid]; char repl_null[Natts_pg_authid]; char repl_repl[Natts_pg_authid]; - int i; - valuestr = flatten_set_variable_args(stmt->variable, stmt->value); + valuestr = ExtractSetVariableArgs(stmt->setstmt); rel = heap_open(AuthIdRelationId, RowExclusiveLock); oldtuple = SearchSysCache(AUTHNAME, @@ -754,14 +753,14 @@ AlterRoleSet(AlterRoleSetStmt *stmt) errmsg("permission denied"))); } - for (i = 0; i < Natts_pg_authid; i++) - repl_repl[i] = ' '; - + memset(repl_repl, ' ', sizeof(repl_repl)); repl_repl[Anum_pg_authid_rolconfig - 1] = 'r'; - if (strcmp(stmt->variable, "all") == 0 && valuestr == NULL) + + if (stmt->setstmt->kind == VAR_RESET_ALL) { - /* RESET ALL */ + /* RESET ALL, so just set rolconfig to null */ repl_null[Anum_pg_authid_rolconfig - 1] = 'n'; + repl_val[Anum_pg_authid_rolconfig - 1] = (Datum) 0; } else { @@ -771,15 +770,16 @@ AlterRoleSet(AlterRoleSetStmt *stmt) repl_null[Anum_pg_authid_rolconfig - 1] = ' '; + /* Extract old value of rolconfig */ datum = SysCacheGetAttr(AUTHNAME, oldtuple, Anum_pg_authid_rolconfig, &isnull); - array = isnull ? NULL : DatumGetArrayTypeP(datum); + /* Update (valuestr is NULL in RESET cases) */ if (valuestr) - array = GUCArrayAdd(array, stmt->variable, valuestr); + array = GUCArrayAdd(array, stmt->setstmt->name, valuestr); else - array = GUCArrayDelete(array, stmt->variable); + array = GUCArrayDelete(array, stmt->setstmt->name); if (array) repl_val[Anum_pg_authid_rolconfig - 1] = PointerGetDatum(array); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 932da9f4d2..b6c6331d17 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.381 2007/08/31 01:44:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.382 2007/09/03 18:46:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2525,8 +2525,7 @@ _copyAlterDatabaseSetStmt(AlterDatabaseSetStmt *from) AlterDatabaseSetStmt *newnode = makeNode(AlterDatabaseSetStmt); COPY_STRING_FIELD(dbname); - COPY_STRING_FIELD(variable); - COPY_NODE_FIELD(value); + COPY_NODE_FIELD(setstmt); return newnode; } @@ -2597,6 +2596,7 @@ _copyVariableSetStmt(VariableSetStmt *from) { VariableSetStmt *newnode = makeNode(VariableSetStmt); + COPY_SCALAR_FIELD(kind); COPY_STRING_FIELD(name); COPY_NODE_FIELD(args); COPY_SCALAR_FIELD(is_local); @@ -2614,16 +2614,6 @@ _copyVariableShowStmt(VariableShowStmt *from) return newnode; } -static VariableResetStmt * -_copyVariableResetStmt(VariableResetStmt *from) -{ - VariableResetStmt *newnode = makeNode(VariableResetStmt); - - COPY_STRING_FIELD(name); - - return newnode; -} - static DiscardStmt * _copyDiscardStmt(DiscardStmt *from) { @@ -2746,8 +2736,7 @@ _copyAlterRoleSetStmt(AlterRoleSetStmt *from) AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt); COPY_STRING_FIELD(role); - COPY_STRING_FIELD(variable); - COPY_NODE_FIELD(value); + COPY_NODE_FIELD(setstmt); return newnode; } @@ -3428,9 +3417,6 @@ copyObject(void *from) case T_VariableShowStmt: retval = _copyVariableShowStmt(from); break; - case T_VariableResetStmt: - retval = _copyVariableResetStmt(from); - break; case T_DiscardStmt: retval = _copyDiscardStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 68a5035476..a12351ae28 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.312 2007/08/31 01:44:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.313 2007/09/03 18:46:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1325,8 +1325,7 @@ static bool _equalAlterDatabaseSetStmt(AlterDatabaseSetStmt *a, AlterDatabaseSetStmt *b) { COMPARE_STRING_FIELD(dbname); - COMPARE_STRING_FIELD(variable); - COMPARE_NODE_FIELD(value); + COMPARE_NODE_FIELD(setstmt); return true; } @@ -1385,6 +1384,7 @@ _equalAlterSeqStmt(AlterSeqStmt *a, AlterSeqStmt *b) static bool _equalVariableSetStmt(VariableSetStmt *a, VariableSetStmt *b) { + COMPARE_SCALAR_FIELD(kind); COMPARE_STRING_FIELD(name); COMPARE_NODE_FIELD(args); COMPARE_SCALAR_FIELD(is_local); @@ -1400,14 +1400,6 @@ _equalVariableShowStmt(VariableShowStmt *a, VariableShowStmt *b) return true; } -static bool -_equalVariableResetStmt(VariableResetStmt *a, VariableResetStmt *b) -{ - COMPARE_STRING_FIELD(name); - - return true; -} - static bool _equalDiscardStmt(DiscardStmt *a, DiscardStmt *b) { @@ -1511,8 +1503,7 @@ static bool _equalAlterRoleSetStmt(AlterRoleSetStmt *a, AlterRoleSetStmt *b) { COMPARE_STRING_FIELD(role); - COMPARE_STRING_FIELD(variable); - COMPARE_NODE_FIELD(value); + COMPARE_NODE_FIELD(setstmt); return true; } @@ -2356,9 +2347,6 @@ equal(void *a, void *b) case T_VariableShowStmt: retval = _equalVariableShowStmt(a, b); break; - case T_VariableResetStmt: - retval = _equalVariableResetStmt(a, b); - break; case T_DiscardStmt: retval = _equalDiscardStmt(a, b); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 9f9f644168..a7521eca52 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.601 2007/09/03 00:39:16 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.602 2007/09/03 18:46:30 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -292,7 +292,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) %type insert_rest -%type set_rest +%type set_rest SetResetClause %type TableElement ConstraintElem TableFuncElement %type columnDef @@ -330,7 +330,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) %type Iconst SignedIconst %type Sconst comment_text %type RoleId opt_granted_by opt_boolean ColId_or_Sconst -%type var_list var_list_or_default +%type var_list %type ColId ColLabel var_name type_function_name param_name %type var_value zone_value @@ -796,20 +796,11 @@ AlterRoleStmt: ; AlterRoleSetStmt: - ALTER ROLE RoleId SET set_rest + ALTER ROLE RoleId SetResetClause { AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); n->role = $3; - n->variable = $5->name; - n->value = $5->args; - $$ = (Node *)n; - } - | ALTER ROLE RoleId VariableResetStmt - { - AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); - n->role = $3; - n->variable = ((VariableResetStmt *)$4)->name; - n->value = NIL; + n->setstmt = $4; $$ = (Node *)n; } ; @@ -834,20 +825,11 @@ AlterUserStmt: AlterUserSetStmt: - ALTER USER RoleId SET set_rest + ALTER USER RoleId SetResetClause { AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); n->role = $3; - n->variable = $5->name; - n->value = $5->args; - $$ = (Node *)n; - } - | ALTER USER RoleId VariableResetStmt - { - AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); - n->role = $3; - n->variable = ((VariableResetStmt *)$4)->name; - n->value = NIL; + n->setstmt = $4; $$ = (Node *)n; } ; @@ -1056,31 +1038,60 @@ VariableSetStmt: } ; -set_rest: var_name TO var_list_or_default +set_rest: /* Generic SET syntaxes: */ + var_name TO var_list { VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_VALUE; n->name = $1; n->args = $3; $$ = n; } - | var_name '=' var_list_or_default + | var_name '=' var_list { VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_VALUE; n->name = $1; n->args = $3; $$ = n; } + | var_name TO DEFAULT + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_DEFAULT; + n->name = $1; + $$ = n; + } + | var_name '=' DEFAULT + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_DEFAULT; + n->name = $1; + $$ = n; + } + | var_name FROM CURRENT_P + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_CURRENT; + n->name = $1; + $$ = n; + } + /* Special syntaxes mandated by SQL standard: */ | TIME ZONE zone_value { VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_VALUE; n->name = "timezone"; if ($3 != NULL) n->args = list_make1($3); + else + n->kind = VAR_SET_DEFAULT; $$ = n; } | TRANSACTION transaction_mode_list { VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_MULTI; n->name = "TRANSACTION"; n->args = $2; $$ = n; @@ -1088,6 +1099,7 @@ set_rest: var_name TO var_list_or_default | SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list { VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_MULTI; n->name = "SESSION CHARACTERISTICS"; n->args = $5; $$ = n; @@ -1095,14 +1107,18 @@ set_rest: var_name TO var_list_or_default | NAMES opt_encoding { VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_VALUE; n->name = "client_encoding"; if ($2 != NULL) n->args = list_make1(makeStringConst($2, NULL)); + else + n->kind = VAR_SET_DEFAULT; $$ = n; } | ROLE ColId_or_Sconst { VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_VALUE; n->name = "role"; n->args = list_make1(makeStringConst($2, NULL)); $$ = n; @@ -1110,6 +1126,7 @@ set_rest: var_name TO var_list_or_default | SESSION AUTHORIZATION ColId_or_Sconst { VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_VALUE; n->name = "session_authorization"; n->args = list_make1(makeStringConst($3, NULL)); $$ = n; @@ -1117,37 +1134,28 @@ set_rest: var_name TO var_list_or_default | SESSION AUTHORIZATION DEFAULT { VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_DEFAULT; n->name = "session_authorization"; - n->args = NIL; $$ = n; } | XML_P OPTION document_or_content { VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_VALUE; n->name = "xmloption"; n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", NULL)); $$ = n; } ; -var_name: - ColId { $$ = $1; } +var_name: ColId { $$ = $1; } | var_name '.' ColId { - int qLen = strlen($1); - char* qualName = palloc(qLen + strlen($3) + 2); - strcpy(qualName, $1); - qualName[qLen] = '.'; - strcpy(qualName + qLen + 1, $3); - $$ = qualName; + $$ = palloc(strlen($1) + strlen($3) + 2); + sprintf($$, "%s.%s", $1, $3); } ; -var_list_or_default: - var_list { $$ = $1; } - | DEFAULT { $$ = NIL; } - ; - var_list: var_value { $$ = list_make1($1); } | var_list ',' var_value { $$ = lappend($1, $3); } ; @@ -1231,6 +1239,49 @@ ColId_or_Sconst: | SCONST { $$ = $1; } ; +VariableResetStmt: + RESET var_name + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_RESET; + n->name = $2; + $$ = (Node *) n; + } + | RESET TIME ZONE + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_RESET; + n->name = "timezone"; + $$ = (Node *) n; + } + | RESET TRANSACTION ISOLATION LEVEL + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_RESET; + n->name = "transaction_isolation"; + $$ = (Node *) n; + } + | RESET SESSION AUTHORIZATION + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_RESET; + n->name = "session_authorization"; + $$ = (Node *) n; + } + | RESET ALL + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_RESET_ALL; + $$ = (Node *) n; + } + ; + +/* SetResetClause allows SET or RESET without LOCAL */ +SetResetClause: + SET set_rest { $$ = $2; } + | VariableResetStmt { $$ = (VariableSetStmt *) $1; } + ; + VariableShowStmt: SHOW var_name @@ -1265,39 +1316,6 @@ VariableShowStmt: } ; -VariableResetStmt: - RESET var_name - { - VariableResetStmt *n = makeNode(VariableResetStmt); - n->name = $2; - $$ = (Node *) n; - } - | RESET TIME ZONE - { - VariableResetStmt *n = makeNode(VariableResetStmt); - n->name = "timezone"; - $$ = (Node *) n; - } - | RESET TRANSACTION ISOLATION LEVEL - { - VariableResetStmt *n = makeNode(VariableResetStmt); - n->name = "transaction_isolation"; - $$ = (Node *) n; - } - | RESET SESSION AUTHORIZATION - { - VariableResetStmt *n = makeNode(VariableResetStmt); - n->name = "session_authorization"; - $$ = (Node *) n; - } - | RESET ALL - { - VariableResetStmt *n = makeNode(VariableResetStmt); - n->name = "all"; - $$ = (Node *) n; - } - ; - ConstraintsSetStmt: SET CONSTRAINTS constraints_set_list constraints_set_mode @@ -4270,15 +4288,10 @@ common_func_opt_item: { $$ = makeDefElem("rows", (Node *)$2); } - | SET set_rest + | SetResetClause { /* we abuse the normal content of a DefElem here */ - $$ = makeDefElem("set", (Node *)$2); - } - | VariableResetStmt - { - /* we abuse the normal content of a DefElem here */ - $$ = makeDefElem("set", $1); + $$ = makeDefElem("set", (Node *)$1); } ; @@ -5391,20 +5404,11 @@ AlterDatabaseStmt: ; AlterDatabaseSetStmt: - ALTER DATABASE database_name SET set_rest + ALTER DATABASE database_name SetResetClause { AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt); n->dbname = $3; - n->variable = $5->name; - n->value = $5->args; - $$ = (Node *)n; - } - | ALTER DATABASE database_name VariableResetStmt - { - AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt); - n->dbname = $3; - n->variable = ((VariableResetStmt *)$4)->name; - n->value = NIL; + n->setstmt = $4; $$ = (Node *)n; } ; diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index 58ed351c59..15b2cd4c2c 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.116 2007/04/27 22:05:49 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.117 2007/09/03 18:46:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1159,7 +1159,6 @@ PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel, IsA(utilityStmt, LockStmt) || IsA(utilityStmt, VariableSetStmt) || IsA(utilityStmt, VariableShowStmt) || - IsA(utilityStmt, VariableResetStmt) || IsA(utilityStmt, ConstraintsSetStmt) || /* efficiency hacks from here down */ IsA(utilityStmt, FetchStmt) || diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index c38647db32..d0b23d8d29 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.285 2007/08/21 01:11:17 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.286 2007/09/03 18:46:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1041,48 +1041,7 @@ ProcessUtility(Node *parsetree, break; case T_VariableSetStmt: - { - VariableSetStmt *n = (VariableSetStmt *) parsetree; - - /* - * Special cases for special SQL syntax that effectively sets - * more than one variable per statement. - */ - if (strcmp(n->name, "TRANSACTION") == 0) - { - ListCell *head; - - foreach(head, n->args) - { - DefElem *item = (DefElem *) lfirst(head); - - if (strcmp(item->defname, "transaction_isolation") == 0) - SetPGVariable("transaction_isolation", - list_make1(item->arg), n->is_local); - else if (strcmp(item->defname, "transaction_read_only") == 0) - SetPGVariable("transaction_read_only", - list_make1(item->arg), n->is_local); - } - } - else if (strcmp(n->name, "SESSION CHARACTERISTICS") == 0) - { - ListCell *head; - - foreach(head, n->args) - { - DefElem *item = (DefElem *) lfirst(head); - - if (strcmp(item->defname, "transaction_isolation") == 0) - SetPGVariable("default_transaction_isolation", - list_make1(item->arg), n->is_local); - else if (strcmp(item->defname, "transaction_read_only") == 0) - SetPGVariable("default_transaction_read_only", - list_make1(item->arg), n->is_local); - } - } - else - SetPGVariable(n->name, n->args, n->is_local); - } + ExecSetVariableStmt((VariableSetStmt *) parsetree); break; case T_VariableShowStmt: @@ -1093,14 +1052,6 @@ ProcessUtility(Node *parsetree, } break; - case T_VariableResetStmt: - { - VariableResetStmt *n = (VariableResetStmt *) parsetree; - - ResetPGVariable(n->name, isTopLevel); - } - break; - case T_DiscardStmt: DiscardCommand((DiscardStmt *) parsetree, isTopLevel); break; @@ -1924,19 +1875,30 @@ CreateCommandTag(Node *parsetree) break; case T_VariableSetStmt: - tag = "SET"; + switch (((VariableSetStmt *) parsetree)->kind) + { + case VAR_SET_VALUE: + case VAR_SET_CURRENT: + case VAR_SET_DEFAULT: + case VAR_SET_MULTI: + tag = "SET"; + break; + case VAR_RESET: + case VAR_RESET_ALL: + tag = "RESET"; + break; + default: + tag = "???"; + } break; case T_VariableShowStmt: tag = "SHOW"; break; - case T_VariableResetStmt: - tag = "RESET"; - break; - case T_DiscardStmt: - switch (((DiscardStmt *) parsetree)->target) { + switch (((DiscardStmt *) parsetree)->target) + { case DISCARD_ALL: tag = "DISCARD ALL"; break; @@ -2402,10 +2364,6 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_ALL; break; - case T_VariableResetStmt: - lev = LOGSTMT_ALL; - break; - case T_CreateTrigStmt: lev = LOGSTMT_DDL; break; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index b8c7b85494..60f7ed5ca3 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.415 2007/09/03 00:39:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.416 2007/09/03 18:46:30 tgl Exp $ * *-------------------------------------------------------------------- */ @@ -4870,10 +4870,10 @@ IsSuperuserConfigOption(const char *name) * We need to be told the name of the variable the args are for, because * the flattening rules vary (ugh). * - * The result is NULL if input is NIL (ie, SET ... TO DEFAULT), otherwise + * The result is NULL if args is NIL (ie, SET ... TO DEFAULT), otherwise * a palloc'd string. */ -char * +static char * flatten_set_variable_args(const char *name, List *args) { struct config_generic *record; @@ -4881,10 +4881,7 @@ flatten_set_variable_args(const char *name, List *args) StringInfoData buf; ListCell *l; - /* - * Fast path if just DEFAULT. We do not check the variable name in this - * case --- necessary for RESET ALL to work correctly. - */ + /* Fast path if just DEFAULT */ if (args == NIL) return NULL; @@ -4979,6 +4976,108 @@ flatten_set_variable_args(const char *name, List *args) * SET command */ void +ExecSetVariableStmt(VariableSetStmt *stmt) +{ + switch (stmt->kind) + { + case VAR_SET_VALUE: + case VAR_SET_CURRENT: + set_config_option(stmt->name, + ExtractSetVariableArgs(stmt), + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, + stmt->is_local, + true); + break; + case VAR_SET_MULTI: + /* + * Special case for special SQL syntax that effectively sets + * more than one variable per statement. + */ + if (strcmp(stmt->name, "TRANSACTION") == 0) + { + ListCell *head; + + foreach(head, stmt->args) + { + DefElem *item = (DefElem *) lfirst(head); + + if (strcmp(item->defname, "transaction_isolation") == 0) + SetPGVariable("transaction_isolation", + list_make1(item->arg), stmt->is_local); + else if (strcmp(item->defname, "transaction_read_only") == 0) + SetPGVariable("transaction_read_only", + list_make1(item->arg), stmt->is_local); + else + elog(ERROR, "unexpected SET TRANSACTION element: %s", + item->defname); + } + } + else if (strcmp(stmt->name, "SESSION CHARACTERISTICS") == 0) + { + ListCell *head; + + foreach(head, stmt->args) + { + DefElem *item = (DefElem *) lfirst(head); + + if (strcmp(item->defname, "transaction_isolation") == 0) + SetPGVariable("default_transaction_isolation", + list_make1(item->arg), stmt->is_local); + else if (strcmp(item->defname, "transaction_read_only") == 0) + SetPGVariable("default_transaction_read_only", + list_make1(item->arg), stmt->is_local); + else + elog(ERROR, "unexpected SET SESSION element: %s", + item->defname); + } + } + else + elog(ERROR, "unexpected SET MULTI element: %s", + stmt->name); + break; + case VAR_SET_DEFAULT: + case VAR_RESET: + set_config_option(stmt->name, + NULL, + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, + stmt->is_local, + true); + break; + case VAR_RESET_ALL: + ResetAllOptions(); + break; + } +} + +/* + * Get the value to assign for a VariableSetStmt, or NULL if it's RESET. + * The result is palloc'd. + * + * This is exported for use by actions such as ALTER ROLE SET. + */ +char * +ExtractSetVariableArgs(VariableSetStmt *stmt) +{ + switch (stmt->kind) + { + case VAR_SET_VALUE: + return flatten_set_variable_args(stmt->name, stmt->args); + case VAR_SET_CURRENT: + return GetConfigOptionByName(stmt->name, NULL); + default: + return NULL; + } +} + +/* + * SetPGVariable - SET command exported as an easily-C-callable function. + * + * This provides access to SET TO value, as well as SET TO DEFAULT (expressed + * by passing args == NIL), but not SET FROM CURRENT functionality. + */ +void SetPGVariable(const char *name, List *args, bool is_local) { char *argstring = flatten_set_variable_args(name, args); @@ -5045,6 +5144,7 @@ set_config_by_name(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(result_text); } + static void define_custom_variable(struct config_generic * variable) { @@ -5283,23 +5383,6 @@ GetPGVariableResultDesc(const char *name) return tupdesc; } -/* - * RESET command - */ -void -ResetPGVariable(const char *name, bool isTopLevel) -{ - if (pg_strcasecmp(name, "all") == 0) - ResetAllOptions(); - else - set_config_option(name, - NULL, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, - false, - true); -} - /* * SHOW command diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 7f6a08f450..fa9d318509 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.203 2007/08/21 01:11:27 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.204 2007/09/03 18:46:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -275,7 +275,6 @@ typedef enum NodeTag T_AlterSeqStmt, T_VariableSetStmt, T_VariableShowStmt, - T_VariableResetStmt, T_DiscardStmt, T_CreateTrigStmt, T_DropPropertyStmt, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 79449c5584..412fadac54 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.352 2007/08/22 05:13:50 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.353 2007/09/03 18:46:30 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1050,6 +1050,42 @@ typedef struct CopyStmt List *options; /* List of DefElem nodes */ } CopyStmt; +/* ---------------------- + * SET Statement (includes RESET) + * + * "SET var TO DEFAULT" and "RESET var" are semantically equivalent, but we + * preserve the distinction in VariableSetKind for CreateCommandTag(). + * ---------------------- + */ +typedef enum +{ + VAR_SET_VALUE, /* SET var = value */ + VAR_SET_DEFAULT, /* SET var TO DEFAULT */ + VAR_SET_CURRENT, /* SET var FROM CURRENT */ + VAR_SET_MULTI, /* special case for SET TRANSACTION ... */ + VAR_RESET, /* RESET var */ + VAR_RESET_ALL /* RESET ALL */ +} VariableSetKind; + +typedef struct VariableSetStmt +{ + NodeTag type; + VariableSetKind kind; + char *name; /* variable to be set */ + List *args; /* List of A_Const nodes */ + bool is_local; /* SET LOCAL? */ +} VariableSetStmt; + +/* ---------------------- + * Show Statement + * ---------------------- + */ +typedef struct VariableShowStmt +{ + NodeTag type; + char *name; +} VariableShowStmt; + /* ---------------------- * Create Table Statement * @@ -1264,8 +1300,7 @@ typedef struct AlterRoleSetStmt { NodeTag type; char *role; /* role name */ - char *variable; /* GUC variable name */ - List *value; /* value for variable, or NIL for Reset */ + VariableSetStmt *setstmt; /* SET or RESET subcommand */ } AlterRoleSetStmt; typedef struct DropRoleStmt @@ -1781,9 +1816,8 @@ typedef struct AlterDatabaseStmt typedef struct AlterDatabaseSetStmt { NodeTag type; - char *dbname; - char *variable; - List *value; + char *dbname; /* database name */ + VariableSetStmt *setstmt; /* SET or RESET subcommand */ } AlterDatabaseSetStmt; /* ---------------------- @@ -1848,41 +1882,6 @@ typedef struct CheckPointStmt NodeTag type; } CheckPointStmt; -/* ---------------------- - * Set Statement - * ---------------------- - */ - -typedef struct VariableSetStmt -{ - NodeTag type; - char *name; - List *args; - bool is_local; /* SET LOCAL */ -} VariableSetStmt; - -/* ---------------------- - * Show Statement - * ---------------------- - */ - -typedef struct VariableShowStmt -{ - NodeTag type; - char *name; -} VariableShowStmt; - -/* ---------------------- - * Reset Statement - * ---------------------- - */ - -typedef struct VariableResetStmt -{ - NodeTag type; - char *name; -} VariableResetStmt; - /* ---------------------- * Discard Statement * ---------------------- diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 5dd06ee7a1..d8fafff559 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -7,12 +7,13 @@ * Copyright (c) 2000-2007, PostgreSQL Global Development Group * Written by Peter Eisentraut . * - * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.84 2007/09/03 00:39:25 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.85 2007/09/03 18:46:30 tgl Exp $ *-------------------------------------------------------------------- */ #ifndef GUC_H #define GUC_H +#include "nodes/parsenodes.h" #include "tcop/dest.h" #include "utils/array.h" @@ -203,9 +204,9 @@ extern int GetNumConfigOptions(void); extern void SetPGVariable(const char *name, List *args, bool is_local); extern void GetPGVariable(const char *name, DestReceiver *dest); extern TupleDesc GetPGVariableResultDesc(const char *name); -extern void ResetPGVariable(const char *name, bool isTopLevel); -extern char *flatten_set_variable_args(const char *name, List *args); +extern void ExecSetVariableStmt(VariableSetStmt *stmt); +extern char *ExtractSetVariableArgs(VariableSetStmt *stmt); extern void ProcessGUCArray(ArrayType *array, GucContext context, GucSource source, bool isLocal);