Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d160882

Browse files
committed
Fix bootstrap parser so that its keywords are unreserved words.
Mark Dilger pointed out that the bootstrap parser does not allow any of its keywords to appear as column values unless they're quoted, and proposed dealing with that by quoting such values in genbki.pl. Looking closer, though, we also have that problem with respect to table, column, and type names appearing in the .bki file: the parser would fail if any of those matched any of its keywords. While so far there have been no conflicts (that I've heard of), this seems like a booby trap waiting to catch somebody. Rather than clutter genbki.pl with enough quoting logic to handle all that, let's make the bootstrap parser grow up a little bit and treat its keywords as unreserved. Experimentation shows that it's fairly easy to do so with the exception of _null_, which I don't have a big problem with keeping as a reserved word. The only change needed is that we can't have the "close" command take an optional table name: it has to either require or forbid the table name to avoid shift/reduce conflicts. genbki.pl has historically always included the table name, so I took that option. The implementation has bootscanner.l passing forward the string value of each keyword, in case bootparse.y needs that. This avoids needing to know the precise spelling of each keyword in bootparse.y, which is good because that's not always obvious from the token name. Discussion: https://postgr.es/m/3024FC91-DB6D-4732-B31C-DF772DF039A0@gmail.com
1 parent 5c4c771 commit d160882

File tree

3 files changed

+79
-52
lines changed

3 files changed

+79
-52
lines changed

doc/src/sgml/bki.sgml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@
248248
<listitem>
249249
<para>
250250
Null values are represented by <literal>_null_</literal>.
251+
(Note that there is no way to create a value that is just that
252+
string.)
251253
</para>
252254
</listitem>
253255

@@ -752,13 +754,13 @@ $ perl rewrite_dat_with_prokind.pl pg_proc.dat
752754

753755
<varlistentry>
754756
<term>
755-
<literal>close</literal> <optional><replaceable class="parameter">tablename</replaceable></optional>
757+
<literal>close</literal> <replaceable class="parameter">tablename</replaceable>
756758
</term>
757759

758760
<listitem>
759761
<para>
760-
Close the open table. The name of the table can be given as a
761-
cross-check, but this is not required.
762+
Close the open table. The name of the table must be given as a
763+
cross-check.
762764
</para>
763765
</listitem>
764766
</varlistentry>
@@ -782,8 +784,8 @@ $ perl rewrite_dat_with_prokind.pl pg_proc.dat
782784

783785
<para>
784786
NULL values can be specified using the special key word
785-
<literal>_null_</literal>. Values containing spaces must be
786-
double quoted.
787+
<literal>_null_</literal>. Values that do not look like
788+
identifiers or digit strings must be double quoted.
787789
</para>
788790
</listitem>
789791
</varlistentry>

src/backend/bootstrap/bootparse.y

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ static int num_columns_read = 0;
105105
List *list;
106106
IndexElem *ielem;
107107
char *str;
108+
const char *kw;
108109
int ival;
109110
Oid oidval;
110111
}
@@ -116,17 +117,17 @@ static int num_columns_read = 0;
116117
%type <oidval> oidspec optoideq optrowtypeoid
117118

118119
%token <str> ID
119-
%token OPEN XCLOSE XCREATE INSERT_TUPLE
120-
%token XDECLARE INDEX ON USING XBUILD INDICES UNIQUE XTOAST
121120
%token COMMA EQUALS LPAREN RPAREN
122-
%token OBJ_ID XBOOTSTRAP XSHARED_RELATION XWITHOUT_OIDS XROWTYPE_OID NULLVAL
123-
%token XFORCE XNOT XNULL
121+
/* NULLVAL is a reserved keyword */
122+
%token NULLVAL
123+
/* All the rest are unreserved, and should be handled in boot_ident! */
124+
%token <kw> OPEN XCLOSE XCREATE INSERT_TUPLE
125+
%token <kw> XDECLARE INDEX ON USING XBUILD INDICES UNIQUE XTOAST
126+
%token <kw> OBJ_ID XBOOTSTRAP XSHARED_RELATION XWITHOUT_OIDS XROWTYPE_OID
127+
%token <kw> XFORCE XNOT XNULL
124128

125129
%start TopLevel
126130

127-
%nonassoc low
128-
%nonassoc high
129-
130131
%%
131132

132133
TopLevel:
@@ -160,18 +161,12 @@ Boot_OpenStmt:
160161
;
161162

162163
Boot_CloseStmt:
163-
XCLOSE boot_ident %prec low
164+
XCLOSE boot_ident
164165
{
165166
do_start();
166167
closerel($2);
167168
do_end();
168169
}
169-
| XCLOSE %prec high
170-
{
171-
do_start();
172-
closerel(NULL);
173-
do_end();
174-
}
175170
;
176171

177172
Boot_CreateStmt:
@@ -489,8 +484,28 @@ boot_column_val:
489484
{ InsertOneNull(num_columns_read++); }
490485
;
491486

492-
boot_ident :
493-
ID { $$ = yylval.str; }
487+
boot_ident:
488+
ID { $$ = $1; }
489+
| OPEN { $$ = pstrdup($1); }
490+
| XCLOSE { $$ = pstrdup($1); }
491+
| XCREATE { $$ = pstrdup($1); }
492+
| INSERT_TUPLE { $$ = pstrdup($1); }
493+
| XDECLARE { $$ = pstrdup($1); }
494+
| INDEX { $$ = pstrdup($1); }
495+
| ON { $$ = pstrdup($1); }
496+
| USING { $$ = pstrdup($1); }
497+
| XBUILD { $$ = pstrdup($1); }
498+
| INDICES { $$ = pstrdup($1); }
499+
| UNIQUE { $$ = pstrdup($1); }
500+
| XTOAST { $$ = pstrdup($1); }
501+
| OBJ_ID { $$ = pstrdup($1); }
502+
| XBOOTSTRAP { $$ = pstrdup($1); }
503+
| XSHARED_RELATION { $$ = pstrdup($1); }
504+
| XWITHOUT_OIDS { $$ = pstrdup($1); }
505+
| XROWTYPE_OID { $$ = pstrdup($1); }
506+
| XFORCE { $$ = pstrdup($1); }
507+
| XNOT { $$ = pstrdup($1); }
508+
| XNULL { $$ = pstrdup($1); }
494509
;
495510
%%
496511

src/backend/bootstrap/bootscanner.l

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -68,64 +68,74 @@ static int yyline = 1; /* line number for error reporting */
6868
id [-A-Za-z0-9_]+
6969
sid \"([^\"])*\"
7070

71+
/*
72+
* Keyword tokens return the keyword text (as a constant string) in yylval.kw,
73+
* just in case that's needed because we want to treat the keyword as an
74+
* unreserved identifier. Note that _null_ is not treated as a keyword
75+
* for this purpose; it's the one "reserved word" in the bootstrap syntax.
76+
*
77+
* Notice that all the keywords are case-sensitive, and for historical
78+
* reasons some must be upper case.
79+
*
80+
* String tokens return a palloc'd string in yylval.str.
81+
*/
82+
7183
%%
7284

73-
open { return OPEN; }
85+
open { yylval.kw = "open"; return OPEN; }
7486

75-
close { return XCLOSE; }
87+
close { yylval.kw = "close"; return XCLOSE; }
7688

77-
create { return XCREATE; }
89+
create { yylval.kw = "create"; return XCREATE; }
7890

79-
OID { return OBJ_ID; }
80-
bootstrap { return XBOOTSTRAP; }
81-
"shared_relation" { return XSHARED_RELATION; }
82-
"without_oids" { return XWITHOUT_OIDS; }
83-
"rowtype_oid" { return XROWTYPE_OID; }
84-
_null_ { return NULLVAL; }
91+
OID { yylval.kw = "OID"; return OBJ_ID; }
92+
bootstrap { yylval.kw = "bootstrap"; return XBOOTSTRAP; }
93+
shared_relation { yylval.kw = "shared_relation"; return XSHARED_RELATION; }
94+
without_oids { yylval.kw = "without_oids"; return XWITHOUT_OIDS; }
95+
rowtype_oid { yylval.kw = "rowtype_oid"; return XROWTYPE_OID; }
96+
97+
insert { yylval.kw = "insert"; return INSERT_TUPLE; }
8598

86-
insert { return INSERT_TUPLE; }
99+
_null_ { return NULLVAL; }
87100

88101
"," { return COMMA; }
89102
"=" { return EQUALS; }
90103
"(" { return LPAREN; }
91104
")" { return RPAREN; }
92105

93106
[\n] { yyline++; }
94-
[\t] ;
95-
" " ;
96-
97-
^\#[^\n]* ; /* drop everything after "#" for comments */
98-
99-
100-
"declare" { return XDECLARE; }
101-
"build" { return XBUILD; }
102-
"indices" { return INDICES; }
103-
"unique" { return UNIQUE; }
104-
"index" { return INDEX; }
105-
"on" { return ON; }
106-
"using" { return USING; }
107-
"toast" { return XTOAST; }
108-
"FORCE" { return XFORCE; }
109-
"NOT" { return XNOT; }
110-
"NULL" { return XNULL; }
107+
[\r\t ] ;
108+
109+
^\#[^\n]* ; /* drop everything after "#" for comments */
110+
111+
declare { yylval.kw = "declare"; return XDECLARE; }
112+
build { yylval.kw = "build"; return XBUILD; }
113+
indices { yylval.kw = "indices"; return INDICES; }
114+
unique { yylval.kw = "unique"; return UNIQUE; }
115+
index { yylval.kw = "index"; return INDEX; }
116+
on { yylval.kw = "on"; return ON; }
117+
using { yylval.kw = "using"; return USING; }
118+
toast { yylval.kw = "toast"; return XTOAST; }
119+
FORCE { yylval.kw = "FORCE"; return XFORCE; }
120+
NOT { yylval.kw = "NOT"; return XNOT; }
121+
NULL { yylval.kw = "NULL"; return XNULL; }
111122

112123
{id} {
113124
yylval.str = scanstr(yytext);
114125
return ID;
115126
}
116127
{sid} {
117-
yytext[strlen(yytext)-1] = '\0'; /* strip off quotes */
128+
/* leading and trailing quotes are not passed to scanstr */
129+
yytext[strlen(yytext) - 1] = '\0';
118130
yylval.str = scanstr(yytext+1);
119-
yytext[strlen(yytext)] = '"'; /* restore quotes */
131+
yytext[strlen(yytext)] = '"'; /* restore yytext */
120132
return ID;
121133
}
122134

123135
. {
124136
elog(ERROR, "syntax error at line %d: unexpected character \"%s\"", yyline, yytext);
125137
}
126138

127-
128-
129139
%%
130140

131141
/* LCOV_EXCL_STOP */

0 commit comments

Comments
 (0)