Skip to content

Commit 15c82ef

Browse files
committed
Refactor CREATE/ALTER DATABASE syntax so options need not be keywords.
Most of the existing option names are keywords anyway, but we can get rid of LC_COLLATE and LC_CTYPE as keywords known to the lexer/grammar. This immediately reduces the size of the grammar tables by about 8KB, and will save more when we add additional CREATE/ALTER DATABASE options in future. A side effect of the implementation is that the CONNECTION LIMIT option can now also be spelled CONNECTION_LIMIT. We choose not to document this, however. Vik Fearing, based on a suggestion by me; reviewed by Pavel Stehule
1 parent 2e8ce9a commit 15c82ef

File tree

3 files changed

+76
-103
lines changed

3 files changed

+76
-103
lines changed

src/backend/commands/dbcommands.c

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "catalog/pg_tablespace.h"
4040
#include "commands/comment.h"
4141
#include "commands/dbcommands.h"
42+
#include "commands/defrem.h"
4243
#include "commands/seclabel.h"
4344
#include "commands/tablespace.h"
4445
#include "mb/pg_wchar.h"
@@ -188,7 +189,7 @@ createdb(const CreatedbStmt *stmt)
188189
errmsg("conflicting or redundant options")));
189190
dctype = defel;
190191
}
191-
else if (strcmp(defel->defname, "connectionlimit") == 0)
192+
else if (strcmp(defel->defname, "connection_limit") == 0)
192193
{
193194
if (dconnlimit)
194195
ereport(ERROR,
@@ -204,21 +205,22 @@ createdb(const CreatedbStmt *stmt)
204205
errhint("Consider using tablespaces instead.")));
205206
}
206207
else
207-
elog(ERROR, "option \"%s\" not recognized",
208-
defel->defname);
208+
ereport(ERROR,
209+
(errcode(ERRCODE_SYNTAX_ERROR),
210+
errmsg("option \"%s\" not recognized", defel->defname)));
209211
}
210212

211213
if (downer && downer->arg)
212-
dbowner = strVal(downer->arg);
214+
dbowner = defGetString(downer);
213215
if (dtemplate && dtemplate->arg)
214-
dbtemplate = strVal(dtemplate->arg);
216+
dbtemplate = defGetString(dtemplate);
215217
if (dencoding && dencoding->arg)
216218
{
217219
const char *encoding_name;
218220

219221
if (IsA(dencoding->arg, Integer))
220222
{
221-
encoding = intVal(dencoding->arg);
223+
encoding = defGetInt32(dencoding);
222224
encoding_name = pg_encoding_to_char(encoding);
223225
if (strcmp(encoding_name, "") == 0 ||
224226
pg_valid_server_encoding(encoding_name) < 0)
@@ -227,28 +229,25 @@ createdb(const CreatedbStmt *stmt)
227229
errmsg("%d is not a valid encoding code",
228230
encoding)));
229231
}
230-
else if (IsA(dencoding->arg, String))
232+
else
231233
{
232-
encoding_name = strVal(dencoding->arg);
234+
encoding_name = defGetString(dencoding);
233235
encoding = pg_valid_server_encoding(encoding_name);
234236
if (encoding < 0)
235237
ereport(ERROR,
236238
(errcode(ERRCODE_UNDEFINED_OBJECT),
237239
errmsg("%s is not a valid encoding name",
238240
encoding_name)));
239241
}
240-
else
241-
elog(ERROR, "unrecognized node type: %d",
242-
nodeTag(dencoding->arg));
243242
}
244243
if (dcollate && dcollate->arg)
245-
dbcollate = strVal(dcollate->arg);
244+
dbcollate = defGetString(dcollate);
246245
if (dctype && dctype->arg)
247-
dbctype = strVal(dctype->arg);
246+
dbctype = defGetString(dctype);
248247

249248
if (dconnlimit && dconnlimit->arg)
250249
{
251-
dbconnlimit = intVal(dconnlimit->arg);
250+
dbconnlimit = defGetInt32(dconnlimit);
252251
if (dbconnlimit < -1)
253252
ereport(ERROR,
254253
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -379,7 +378,7 @@ createdb(const CreatedbStmt *stmt)
379378
char *tablespacename;
380379
AclResult aclresult;
381380

382-
tablespacename = strVal(dtablespacename->arg);
381+
tablespacename = defGetString(dtablespacename);
383382
dst_deftablespace = get_tablespace_oid(tablespacename, false);
384383
/* check permissions */
385384
aclresult = pg_tablespace_aclcheck(dst_deftablespace, GetUserId(),
@@ -1341,7 +1340,7 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
13411340
{
13421341
DefElem *defel = (DefElem *) lfirst(option);
13431342

1344-
if (strcmp(defel->defname, "connectionlimit") == 0)
1343+
if (strcmp(defel->defname, "connection_limit") == 0)
13451344
{
13461345
if (dconnlimit)
13471346
ereport(ERROR,
@@ -1358,23 +1357,32 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
13581357
dtablespace = defel;
13591358
}
13601359
else
1361-
elog(ERROR, "option \"%s\" not recognized",
1362-
defel->defname);
1360+
ereport(ERROR,
1361+
(errcode(ERRCODE_SYNTAX_ERROR),
1362+
errmsg("option \"%s\" not recognized", defel->defname)));
13631363
}
13641364

13651365
if (dtablespace)
13661366
{
1367-
/* currently, can't be specified along with any other options */
1368-
Assert(!dconnlimit);
1367+
/*
1368+
* While the SET TABLESPACE syntax doesn't allow any other options,
1369+
* somebody could write "WITH TABLESPACE ...". Forbid any other
1370+
* options from being specified in that case.
1371+
*/
1372+
if (list_length(stmt->options) != 1)
1373+
ereport(ERROR,
1374+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1375+
errmsg("option \"%s\" cannot be specified with other options",
1376+
dtablespace->defname)));
13691377
/* this case isn't allowed within a transaction block */
13701378
PreventTransactionChain(isTopLevel, "ALTER DATABASE SET TABLESPACE");
1371-
movedb(stmt->dbname, strVal(dtablespace->arg));
1379+
movedb(stmt->dbname, defGetString(dtablespace));
13721380
return InvalidOid;
13731381
}
13741382

1375-
if (dconnlimit)
1383+
if (dconnlimit && dconnlimit->arg)
13761384
{
1377-
connlimit = intVal(dconnlimit->arg);
1385+
connlimit = defGetInt32(dconnlimit);
13781386
if (connlimit < -1)
13791387
ereport(ERROR,
13801388
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),

src/backend/parser/gram.y

Lines changed: 45 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,10 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
264264

265265
%type <dbehavior> opt_drop_behavior
266266

267-
%type <list> createdb_opt_list alterdb_opt_list copy_opt_list
267+
%type <list> createdb_opt_list createdb_opt_items copy_opt_list
268268
transaction_mode_list
269269
create_extension_opt_list alter_extension_opt_list
270-
%type <defelt> createdb_opt_item alterdb_opt_item copy_opt_item
270+
%type <defelt> createdb_opt_item copy_opt_item
271271
transaction_mode_item
272272
create_extension_opt_item alter_extension_opt_item
273273

@@ -462,6 +462,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
462462
%type <list> var_list
463463
%type <str> ColId ColLabel var_name type_function_name param_name
464464
%type <str> NonReservedWord NonReservedWord_or_Sconst
465+
%type <str> createdb_opt_name
465466
%type <node> var_value zone_value
466467

467468
%type <keyword> unreserved_keyword type_func_name_keyword
@@ -564,7 +565,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
564565

565566
KEY
566567

567-
LABEL LANGUAGE LARGE_P LAST_P LATERAL_P LC_COLLATE_P LC_CTYPE_P
568+
LABEL LANGUAGE LARGE_P LAST_P LATERAL_P
568569
LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL
569570
LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P
570571

@@ -8320,77 +8321,51 @@ CreatedbStmt:
83208321
;
83218322

83228323
createdb_opt_list:
8323-
createdb_opt_list createdb_opt_item { $$ = lappend($1, $2); }
8324+
createdb_opt_items { $$ = $1; }
83248325
| /* EMPTY */ { $$ = NIL; }
83258326
;
83268327

8328+
createdb_opt_items:
8329+
createdb_opt_item { $$ = list_make1($1); }
8330+
| createdb_opt_items createdb_opt_item { $$ = lappend($1, $2); }
8331+
;
8332+
83278333
createdb_opt_item:
8328-
TABLESPACE opt_equal name
8329-
{
8330-
$$ = makeDefElem("tablespace", (Node *)makeString($3));
8331-
}
8332-
| TABLESPACE opt_equal DEFAULT
8333-
{
8334-
$$ = makeDefElem("tablespace", NULL);
8335-
}
8336-
| LOCATION opt_equal Sconst
8337-
{
8338-
$$ = makeDefElem("location", (Node *)makeString($3));
8339-
}
8340-
| LOCATION opt_equal DEFAULT
8341-
{
8342-
$$ = makeDefElem("location", NULL);
8343-
}
8344-
| TEMPLATE opt_equal name
8345-
{
8346-
$$ = makeDefElem("template", (Node *)makeString($3));
8347-
}
8348-
| TEMPLATE opt_equal DEFAULT
8349-
{
8350-
$$ = makeDefElem("template", NULL);
8351-
}
8352-
| ENCODING opt_equal Sconst
8353-
{
8354-
$$ = makeDefElem("encoding", (Node *)makeString($3));
8355-
}
8356-
| ENCODING opt_equal Iconst
8357-
{
8358-
$$ = makeDefElem("encoding", (Node *)makeInteger($3));
8359-
}
8360-
| ENCODING opt_equal DEFAULT
8361-
{
8362-
$$ = makeDefElem("encoding", NULL);
8363-
}
8364-
| LC_COLLATE_P opt_equal Sconst
8365-
{
8366-
$$ = makeDefElem("lc_collate", (Node *)makeString($3));
8367-
}
8368-
| LC_COLLATE_P opt_equal DEFAULT
8369-
{
8370-
$$ = makeDefElem("lc_collate", NULL);
8371-
}
8372-
| LC_CTYPE_P opt_equal Sconst
8334+
createdb_opt_name opt_equal SignedIconst
83738335
{
8374-
$$ = makeDefElem("lc_ctype", (Node *)makeString($3));
8336+
$$ = makeDefElem($1, (Node *)makeInteger($3));
83758337
}
8376-
| LC_CTYPE_P opt_equal DEFAULT
8338+
| createdb_opt_name opt_equal opt_boolean_or_string
83778339
{
8378-
$$ = makeDefElem("lc_ctype", NULL);
8340+
$$ = makeDefElem($1, (Node *)makeString($3));
83798341
}
8380-
| CONNECTION LIMIT opt_equal SignedIconst
8342+
| createdb_opt_name opt_equal DEFAULT
83818343
{
8382-
$$ = makeDefElem("connectionlimit", (Node *)makeInteger($4));
8383-
}
8384-
| OWNER opt_equal name
8385-
{
8386-
$$ = makeDefElem("owner", (Node *)makeString($3));
8387-
}
8388-
| OWNER opt_equal DEFAULT
8389-
{
8390-
$$ = makeDefElem("owner", NULL);
8344+
$$ = makeDefElem($1, NULL);
83918345
}
83928346
;
83938347

8348+
/*
8349+
* Ideally we'd use ColId here, but that causes shift/reduce conflicts against
8350+
* the ALTER DATABASE SET/RESET syntaxes. Instead call out specific keywords
8351+
* we need, and allow IDENT so that database option names don't have to be
8352+
* parser keywords unless they are already keywords for other reasons.
8353+
*
8354+
* XXX this coding technique is fragile since if someone makes a formerly
8355+
* non-keyword option name into a keyword and forgets to add it here, the
8356+
* option will silently break. Best defense is to provide a regression test
8357+
* exercising every such option, at least at the syntax level.
8358+
*/
8359+
createdb_opt_name:
8360+
IDENT { $$ = $1; }
8361+
| CONNECTION LIMIT { $$ = pstrdup("connection_limit"); }
8362+
| ENCODING { $$ = pstrdup($1); }
8363+
| LOCATION { $$ = pstrdup($1); }
8364+
| OWNER { $$ = pstrdup($1); }
8365+
| TABLESPACE { $$ = pstrdup($1); }
8366+
| TEMPLATE { $$ = pstrdup($1); }
8367+
;
8368+
83948369
/*
83958370
* Though the equals sign doesn't match other WITH options, pg_dump uses
83968371
* equals for backward compatibility, and it doesn't seem worth removing it.
@@ -8407,13 +8382,20 @@ opt_equal: '=' {}
84078382
*****************************************************************************/
84088383

84098384
AlterDatabaseStmt:
8410-
ALTER DATABASE database_name opt_with alterdb_opt_list
8385+
ALTER DATABASE database_name WITH createdb_opt_list
84118386
{
84128387
AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt);
84138388
n->dbname = $3;
84148389
n->options = $5;
84158390
$$ = (Node *)n;
84168391
}
8392+
| ALTER DATABASE database_name createdb_opt_list
8393+
{
8394+
AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt);
8395+
n->dbname = $3;
8396+
n->options = $4;
8397+
$$ = (Node *)n;
8398+
}
84178399
| ALTER DATABASE database_name SET TABLESPACE name
84188400
{
84198401
AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt);
@@ -8435,19 +8417,6 @@ AlterDatabaseSetStmt:
84358417
;
84368418

84378419

8438-
alterdb_opt_list:
8439-
alterdb_opt_list alterdb_opt_item { $$ = lappend($1, $2); }
8440-
| /* EMPTY */ { $$ = NIL; }
8441-
;
8442-
8443-
alterdb_opt_item:
8444-
CONNECTION LIMIT opt_equal SignedIconst
8445-
{
8446-
$$ = makeDefElem("connectionlimit", (Node *)makeInteger($4));
8447-
}
8448-
;
8449-
8450-
84518420
/*****************************************************************************
84528421
*
84538422
* DROP DATABASE [ IF EXISTS ]
@@ -12958,8 +12927,6 @@ unreserved_keyword:
1295812927
| LANGUAGE
1295912928
| LARGE_P
1296012929
| LAST_P
12961-
| LC_COLLATE_P
12962-
| LC_CTYPE_P
1296312930
| LEAKPROOF
1296412931
| LEVEL
1296512932
| LISTEN

src/include/parser/kwlist.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,6 @@ PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
215215
PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
216216
PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
217217
PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD)
218-
PG_KEYWORD("lc_collate", LC_COLLATE_P, UNRESERVED_KEYWORD)
219-
PG_KEYWORD("lc_ctype", LC_CTYPE_P, UNRESERVED_KEYWORD)
220218
PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD)
221219
PG_KEYWORD("leakproof", LEAKPROOF, UNRESERVED_KEYWORD)
222220
PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy