Allowing regular identifiers in isolationtester scripts - Mailing list pgsql-hackers

From Tom Lane
Subject Allowing regular identifiers in isolationtester scripts
Date
Msg-id 759113.1623861959@sss.pgh.pa.us
Whole thread Raw
List pgsql-hackers
[ new subject, new thread, new patch ]

Alvaro Herrera <alvherre@alvh.no-ip.org> writes:
> On 2021-Jun-16, Tom Lane wrote:
>> BTW, as long as we're thinking of back-patching nontrivial specfile
>> changes, I have another modest proposal.  What do people think of
>> removing the requirement for step/session names to be double-quoted,
>> and instead letting them work like SQL identifiers?

> Yes *please*.

Here's a draft patch for that.  I converted one specfile just as
proof-of-concept, but I don't want to touch the rest until the other
patch has gone in, or I'll have merge problems.  (This'll have some
merge problems with that anyway I fear, but they'll be minor.)

I decided to follow the standard SQL rule that you can use "foo""bar"
to include a double-quote in a quoted identifier.  This broke one
place in test_decoding's oldest_xmin.spec where somebody had left out
a space.  So maybe there's an argument for not doing that --- but I'd
rather not document more inconsistencies than I have to.

            regards, tom lane

diff --git a/contrib/test_decoding/specs/oldest_xmin.spec b/contrib/test_decoding/specs/oldest_xmin.spec
index da3a8cd512..88bd30f5ff 100644
--- a/contrib/test_decoding/specs/oldest_xmin.spec
+++ b/contrib/test_decoding/specs/oldest_xmin.spec
@@ -39,4 +39,4 @@ step "s1_commit" { COMMIT; }
 # composite type is a rare form of DDL which allows T1 to see the tuple which
 # will be removed (xmax set) before T1 commits. That is, interlocking doesn't
 # forbid modifying catalog after someone read it (and didn't commit yet).
-permutation "s0_begin" "s0_getxid" "s1_begin" "s1_insert" "s0_alter" "s0_commit" "s0_checkpoint" "s0_get_changes"
"s0_get_changes""s1_commit""s0_vacuum" "s0_get_changes" 
+permutation "s0_begin" "s0_getxid" "s1_begin" "s1_insert" "s0_alter" "s0_commit" "s0_checkpoint" "s0_get_changes"
"s0_get_changes""s1_commit" "s0_vacuum" "s0_get_changes" 
diff --git a/src/test/isolation/README b/src/test/isolation/README
index 6ae7152325..439b1d32b2 100644
--- a/src/test/isolation/README
+++ b/src/test/isolation/README
@@ -75,7 +75,7 @@ teardown { <SQL> }
   this to clean up in preparation for the next permutation, e.g dropping
   any test tables created by setup. This part is optional.

-session "<name>"
+session <name>

   There are normally several "session" parts in a spec file. Each
   session is executed in its own connection. A session part consists
@@ -86,13 +86,13 @@ session "<name>"

   Each step has the syntax

-  step "<name>" { <SQL> }
+  step <name> { <SQL> }

   where <name> is a name identifying this step, and SQL is a SQL statement
   (or statements, separated by semicolons) that is executed in the step.
   Step names must be unique across the whole spec file.

-permutation "<step name>" ...
+permutation <step name> ...

   A permutation line specifies a list of steps that are run in that order.
   Any number of permutation lines can appear.  If no permutation lines are
@@ -103,6 +103,13 @@ permutation "<step name>" ...
   available steps; it could for instance repeat some steps more than once,
   or leave others out.

+Session and step names are SQL identifiers or quoted identifiers.
+A difference from standard SQL is that no case-folding occurs, so
+FOO and "FOO" are the same name while FOO and Foo are different,
+whether you quote them or not.  You must use double quotes if you
+want to use an isolation test keyword (such as "permutation") as
+a name.
+
 Lines beginning with a # are considered comments.

 For each permutation of the session steps (whether these are manually
diff --git a/src/test/isolation/specparse.y b/src/test/isolation/specparse.y
index ae3a999961..efdf333b00 100644
--- a/src/test/isolation/specparse.y
+++ b/src/test/isolation/specparse.y
@@ -39,12 +39,12 @@ TestSpec        parseresult;            /* result of parsing is left here */
 %type <str>  opt_setup opt_teardown
 %type <str> setup
 %type <ptr_list> step_list session_list permutation_list opt_permutation_list
-%type <ptr_list> string_literal_list
+%type <ptr_list> identifier_list
 %type <session> session
 %type <step> step
 %type <permutation> permutation

-%token <str> sqlblock string_literal
+%token <str> sqlblock identifier
 %token PERMUTATION SESSION SETUP STEP TEARDOWN TEST

 %%
@@ -111,7 +111,7 @@ session_list:
         ;

 session:
-            SESSION string_literal opt_setup step_list opt_teardown
+            SESSION identifier opt_setup step_list opt_teardown
             {
                 $$ = pg_malloc(sizeof(Session));
                 $$->name = $2;
@@ -140,7 +140,7 @@ step_list:


 step:
-            STEP string_literal sqlblock
+            STEP identifier sqlblock
             {
                 $$ = pg_malloc(sizeof(Step));
                 $$->name = $2;
@@ -180,7 +180,7 @@ permutation_list:


 permutation:
-            PERMUTATION string_literal_list
+            PERMUTATION identifier_list
             {
                 $$ = pg_malloc(sizeof(Permutation));
                 $$->stepnames = (char **) $2.elements;
@@ -188,15 +188,15 @@ permutation:
             }
         ;

-string_literal_list:
-            string_literal_list string_literal
+identifier_list:
+            identifier_list identifier
             {
                 $$.elements = pg_realloc($1.elements,
                                          ($1.nelements + 1) * sizeof(void *));
                 $$.elements[$1.nelements] = $2;
                 $$.nelements = $1.nelements + 1;
             }
-            | string_literal
+            | identifier
             {
                 $$.nelements = 1;
                 $$.elements = pg_malloc(sizeof(void *));
diff --git a/src/test/isolation/specs/aborted-keyrevoke.spec b/src/test/isolation/specs/aborted-keyrevoke.spec
index 08945d8b31..4f6f9027cc 100644
--- a/src/test/isolation/specs/aborted-keyrevoke.spec
+++ b/src/test/isolation/specs/aborted-keyrevoke.spec
@@ -17,30 +17,30 @@ teardown
   DROP TABLE foo;
 }

-session "s1"
+session s1
 setup        { BEGIN; }
-step "s1s"    { SAVEPOINT f; }
-step "s1u"    { UPDATE foo SET key = 2; }    # obtain KEY REVOKE
-step "s1r"    { ROLLBACK TO f; } # lose KEY REVOKE
-step "s1l"    { SELECT * FROM foo FOR KEY SHARE; }
-step "s1c"    { COMMIT; }
+step s1s    { SAVEPOINT f; }
+step s1u    { UPDATE foo SET key = 2; }    # obtain KEY REVOKE
+step s1r    { ROLLBACK TO f; } # lose KEY REVOKE
+step s1l    { SELECT * FROM foo FOR KEY SHARE; }
+step s1c    { COMMIT; }

-session "s2"
+session s2
 setup        { BEGIN; }
-step "s2l"    { SELECT * FROM foo FOR KEY SHARE; }
-step "s2c"    { COMMIT; }
+step s2l    { SELECT * FROM foo FOR KEY SHARE; }
+step s2c    { COMMIT; }

-permutation "s1s" "s1u" "s1r" "s1l" "s1c" "s2l" "s2c"
-permutation "s1s" "s1u" "s1r" "s1l" "s2l" "s1c" "s2c"
-permutation "s1s" "s1u" "s1r" "s1l" "s2l" "s2c" "s1c"
-permutation "s1s" "s1u" "s1r" "s2l" "s1l" "s1c" "s2c"
-permutation "s1s" "s1u" "s1r" "s2l" "s1l" "s2c" "s1c"
-permutation "s1s" "s1u" "s1r" "s2l" "s2c" "s1l" "s1c"
-permutation "s1s" "s1u" "s2l" "s1r" "s1l" "s1c" "s2c"
-permutation "s1s" "s1u" "s2l" "s1r" "s1l" "s2c" "s1c"
-permutation "s1s" "s1u" "s2l" "s1r" "s2c" "s1l" "s1c"
-permutation "s1s" "s2l" "s1u" "s2c" "s1r" "s1l" "s1c"
-permutation "s1s" "s2l" "s2c" "s1u" "s1r" "s1l" "s1c"
-permutation "s2l" "s1s" "s1u" "s2c" "s1r" "s1l" "s1c"
-permutation "s2l" "s1s" "s2c" "s1u" "s1r" "s1l" "s1c"
-permutation "s2l" "s2c" "s1s" "s1u" "s1r" "s1l" "s1c"
+permutation s1s s1u s1r s1l s1c s2l s2c
+permutation s1s s1u s1r s1l s2l s1c s2c
+permutation s1s s1u s1r s1l s2l s2c s1c
+permutation s1s s1u s1r s2l s1l s1c s2c
+permutation s1s s1u s1r s2l s1l s2c s1c
+permutation s1s s1u s1r s2l s2c s1l s1c
+permutation s1s s1u s2l s1r s1l s1c s2c
+permutation s1s s1u s2l s1r s1l s2c s1c
+permutation s1s s1u s2l s1r s2c s1l s1c
+permutation s1s s2l s1u s2c s1r s1l s1c
+permutation s1s s2l s2c s1u s1r s1l s1c
+permutation s2l s1s s1u s2c s1r s1l s1c
+permutation s2l s1s s2c s1u s1r s1l s1c
+permutation s2l s2c s1s s1u s1r s1l s1c
diff --git a/src/test/isolation/specscanner.l b/src/test/isolation/specscanner.l
index 19883c265b..01f39fe05f 100644
--- a/src/test/isolation/specscanner.l
+++ b/src/test/isolation/specscanner.l
@@ -34,13 +34,19 @@ static void addlitchar(char c);


 %x sql
-%x qstr
+%x qident

 non_newline        [^\n\r]
 space            [ \t\r\f]

 comment            ("#"{non_newline}*)

+digit            [0-9]
+ident_start        [A-Za-z\200-\377_]
+ident_cont        [A-Za-z\200-\377_0-9\$]
+
+identifier        {ident_start}{ident_cont}*
+
 %%

 %{
@@ -48,32 +54,42 @@ comment            ("#"{non_newline}*)
     litbufsize = LITBUF_INIT;
 %}

+ /* Keywords (must appear before the {identifier} rule!) */
 permutation        { return PERMUTATION; }
 session            { return SESSION; }
 setup            { return SETUP; }
 step            { return STEP; }
 teardown        { return TEARDOWN; }

+ /* Whitespace and comments */
 [\n]            { yyline++; }
 {comment}        { /* ignore */ }
 {space}            { /* ignore */ }

- /* Quoted strings: "foo" */
+ /* Plain identifiers */
+{identifier}    {
+                    yylval.str = pg_strdup(yytext);
+                    return(identifier);
+                }
+
+ /* Quoted identifiers: "foo" */
 \"                {
                     litbufpos = 0;
-                    BEGIN(qstr);
+                    BEGIN(qident);
                 }
-<qstr>\"        {
+<qident>\"\"    { addlitchar(yytext[0]); }
+<qident>\"        {
                     litbuf[litbufpos] = '\0';
                     yylval.str = pg_strdup(litbuf);
                     BEGIN(INITIAL);
-                    return(string_literal);
+                    return(identifier);
                 }
-<qstr>.            { addlitchar(yytext[0]); }
-<qstr>\n        { yyerror("unexpected newline in quoted string"); }
-<qstr><<EOF>>    { yyerror("unterminated quoted string"); }
+<qident>.        { addlitchar(yytext[0]); }
+<qident>\n        { yyerror("unexpected newline in quoted identifier"); }
+<qident><<EOF>>    { yyerror("unterminated quoted identifier"); }

  /* SQL blocks: { UPDATE ... } */
+ /* We trim leading/trailing whitespace, otherwise they're unprocessed */
 "{"{space}*        {

                     litbufpos = 0;
@@ -96,6 +112,7 @@ teardown        { return TEARDOWN; }
                     yyerror("unterminated sql block");
                 }

+ /* Anything else is an error */
 .                {
                     fprintf(stderr, "syntax error at line %d: unexpected character \"%s\"\n", yyline, yytext);
                     exit(1);

pgsql-hackers by date:

Previous
From: John Naylor
Date:
Subject: Re: a path towards replacing GEQO with something better
Next
From: Peter Geoghegan
Date:
Subject: Re: pg14b1 stuck in lazy_scan_prune/heap_page_prune of pg_statistic