@@ -136,6 +136,9 @@ static Node *makeBitStringConst(char *str, int location);
136
136
static Node *makeNullAConst (int location);
137
137
static Node *makeAConst (Value *v, int location);
138
138
static Node *makeBoolAConst (bool state, int location);
139
+ static Node *makeParamRef (int number, int location);
140
+ static Node *makeParamRefCast (int number, int location, TypeName *typename );
141
+ static Node *makeInterval_or_AExprOp (Node *lexpr, Node *rexpr, int location);
139
142
static void check_qualified_name (List *names, core_yyscan_t yyscanner);
140
143
static List *check_func_name (List *names, core_yyscan_t yyscanner);
141
144
static List *check_indirection (List *indirection, core_yyscan_t yyscanner);
@@ -461,6 +464,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
461
464
%type <str> ColId ColLabel var_name type_function_name param_name
462
465
%type <str> NonReservedWord NonReservedWord_or_Sconst
463
466
%type <node> var_value zone_value
467
+ %type <node> Iconst_or_Normalized Sconst_or_Normalized NonReservedWord_or_Sconst_or_Normalized
464
468
465
469
%type <keyword> unreserved_keyword type_func_name_keyword
466
470
%type <keyword> col_name_keyword reserved_keyword
@@ -663,6 +667,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
663
667
%left ' +' ' -'
664
668
%left ' *' ' /' ' %'
665
669
%left ' ^'
670
+ %left ' ?'
666
671
/* Unary Operators */
667
672
%left AT /* sets precedence for AT TIME ZONE */
668
673
%left COLLATE
@@ -1399,12 +1404,12 @@ set_rest_more: /* Generic SET syntaxes: */
1399
1404
parser_errposition(@2 )));
1400
1405
$$ = NULL ; /* not reached*/
1401
1406
}
1402
- | SCHEMA Sconst
1407
+ | SCHEMA Sconst_or_Normalized
1403
1408
{
1404
1409
VariableSetStmt *n = makeNode(VariableSetStmt);
1405
1410
n->kind = VAR_SET_VALUE;
1406
1411
n->name = " search_path" ;
1407
- n->args = list_make1(makeStringConst( $2 , @2 ) );
1412
+ n->args = list_make1($2 );
1408
1413
$$ = n;
1409
1414
}
1410
1415
| NAMES opt_encoding
@@ -1418,20 +1423,20 @@ set_rest_more: /* Generic SET syntaxes: */
1418
1423
n->kind = VAR_SET_DEFAULT;
1419
1424
$$ = n;
1420
1425
}
1421
- | ROLE NonReservedWord_or_Sconst
1426
+ | ROLE NonReservedWord_or_Sconst_or_Normalized
1422
1427
{
1423
1428
VariableSetStmt *n = makeNode(VariableSetStmt);
1424
1429
n->kind = VAR_SET_VALUE;
1425
1430
n->name = " role" ;
1426
- n->args = list_make1(makeStringConst( $2 , @2 ) );
1431
+ n->args = list_make1($2 );
1427
1432
$$ = n;
1428
1433
}
1429
- | SESSION AUTHORIZATION NonReservedWord_or_Sconst
1434
+ | SESSION AUTHORIZATION NonReservedWord_or_Sconst_or_Normalized
1430
1435
{
1431
1436
VariableSetStmt *n = makeNode(VariableSetStmt);
1432
1437
n->kind = VAR_SET_VALUE;
1433
1438
n->name = " session_authorization" ;
1434
- n->args = list_make1(makeStringConst( $3 , @3 ) );
1439
+ n->args = list_make1($3 );
1435
1440
$$ = n;
1436
1441
}
1437
1442
| SESSION AUTHORIZATION DEFAULT
@@ -1473,6 +1478,8 @@ var_value: opt_boolean_or_string
1473
1478
{ $$ = makeStringConst($1 , @1 ); }
1474
1479
| NumericOnly
1475
1480
{ $$ = makeAConst($1 , @1 ); }
1481
+ | ' ?'
1482
+ { $$ = makeStringConst(" ?" , @1 ); }
1476
1483
;
1477
1484
1478
1485
iso_level : READ UNCOMMITTED { $$ = " read uncommitted" ; }
@@ -1502,9 +1509,9 @@ opt_boolean_or_string:
1502
1509
* so use IDENT (meaning we reject anything that is a key word).
1503
1510
*/
1504
1511
zone_value :
1505
- Sconst
1512
+ Sconst_or_Normalized
1506
1513
{
1507
- $$ = makeStringConst( $1 , @1 ) ;
1514
+ $$ = $1 ;
1508
1515
}
1509
1516
| IDENT
1510
1517
{
@@ -10580,13 +10587,13 @@ ConstCharacter: CharacterWithLength
10580
10587
}
10581
10588
;
10582
10589
10583
- CharacterWithLength : character ' (' Iconst ' )' opt_charset
10590
+ CharacterWithLength : character ' (' Iconst_or_Normalized ' )' opt_charset
10584
10591
{
10585
10592
if (($5 != NULL ) && (strcmp($5 , " sql_text" ) != 0 ))
10586
10593
$1 = psprintf(" %s_%s" , $1 , $5 );
10587
10594
10588
10595
$$ = SystemTypeName($1 );
10589
- $$ ->typmods = list_make1(makeIntConst( $3 , @3 ) );
10596
+ $$ ->typmods = list_make1($3 );
10590
10597
$$ ->location = @1 ;
10591
10598
}
10592
10599
;
@@ -10827,6 +10834,13 @@ a_expr: c_expr { $$ = $1; }
10827
10834
| a_expr ' =' a_expr
10828
10835
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, " =" , $1 , $3 , @2 ); }
10829
10836
10837
+ | a_expr ' ?' a_expr %prec Op
10838
+ { $$ = makeInterval_or_AExprOp($1 , $3 , @2 ); }
10839
+ /* | '?' a_expr %prec Op
10840
+ { $$ = makeInterval_or_AExprOp(NULL, $2, @1); }*/
10841
+ | a_expr ' ?' %prec POSTFIXOP
10842
+ { $$ = makeInterval_or_AExprOp($1 , NULL , @2 ); }
10843
+
10830
10844
| a_expr qual_Op a_expr %prec Op
10831
10845
{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2 , $1 , $3 , @2 ); }
10832
10846
| qual_Op a_expr %prec Op
@@ -11190,6 +11204,14 @@ b_expr: c_expr
11190
11204
{ $$ = (Node *) makeSimpleA_Expr (AEXPR_OP, " >" , $1 , $3 , @2 ); }
11191
11205
| b_expr ' =' b_expr
11192
11206
{ $$ = (Node *) makeSimpleA_Expr (AEXPR_OP, " =" , $1 , $3 , @2 ); }
11207
+
11208
+ | b_expr ' ?' b_expr %prec Op
11209
+ { $$ = makeInterval_or_AExprOp ($1 , $3 , @2 ); }
11210
+ /* | '?' b_expr %prec Op
11211
+ { $$ = makeInterval_or_AExprOp(NULL, $2, @1); }*/
11212
+ | b_expr ' ?' %prec POSTFIXOP
11213
+ { $$ = makeInterval_or_AExprOp ($1 , NULL , @2 ); }
11214
+
11193
11215
| b_expr qual_Op b_expr %prec Op
11194
11216
{ $$ = (Node *) makeA_Expr (AEXPR_OP, $2 , $1 , $3 , @2 ); }
11195
11217
| qual_Op b_expr %prec Op
@@ -11237,6 +11259,18 @@ b_expr: c_expr
11237
11259
*/
11238
11260
c_expr: columnref { $$ = $1 ; }
11239
11261
| AexprConst { $$ = $1 ; }
11262
+ | ' ?' opt_indirection
11263
+ {
11264
+ if ($2 )
11265
+ {
11266
+ A_Indirection *n = makeNode (A_Indirection);
11267
+ n->arg = makeParamRef (0 , @1 );
11268
+ n->indirection = check_indirection ($2 , yyscanner);
11269
+ $$ = (Node *) n;
11270
+ }
11271
+ else
11272
+ $$ = makeParamRef (0 , @1 );
11273
+ }
11240
11274
| PARAM opt_indirection
11241
11275
{
11242
11276
ParamRef *p = makeNode (ParamRef);
@@ -12105,6 +12139,7 @@ MathOp: '+' { $$ = "+"; }
12105
12139
| ' <' { $$ = " <" ; }
12106
12140
| ' >' { $$ = " >" ; }
12107
12141
| ' =' { $$ = " =" ; }
12142
+ | ' ?' { $$ = " ?" ; }
12108
12143
;
12109
12144
12110
12145
qual_Op: Op
@@ -12207,6 +12242,10 @@ extract_list:
12207
12242
{
12208
12243
$$ = list_make2 (makeStringConst ($1 , @1 ), $3 );
12209
12244
}
12245
+ | ' ?' FROM a_expr
12246
+ {
12247
+ $$ = list_make2 (makeParamRef (0 , @1 ), $3 );
12248
+ }
12210
12249
| /* EMPTY*/ { $$ = NIL; }
12211
12250
;
12212
12251
@@ -12694,6 +12733,19 @@ AexprConst: Iconst
12694
12733
makeIntConst ($3 , @3 ));
12695
12734
$$ = makeStringConstCast ($5 , @5 , t);
12696
12735
}
12736
+ /* Version without () is handled in a_expr/b_expr logic due to ? mis-parsing as operator */
12737
+ | ConstInterval ' (' ' ?' ' )' ' ?' opt_interval
12738
+ {
12739
+ TypeName *t = $1 ;
12740
+ if ($6 != NIL)
12741
+ {
12742
+ t->typmods = lappend ($6 , makeParamRef (0 , @3 ));
12743
+ }
12744
+ else
12745
+ t->typmods = list_make2 (makeIntConst (INTERVAL_FULL_RANGE, -1 ),
12746
+ makeParamRef (0 , @3 ));
12747
+ $$ = makeParamRefCast (0 , @5 , t);
12748
+ }
12697
12749
| TRUE_P
12698
12750
{
12699
12751
$$ = makeBoolAConst (TRUE , @1 );
@@ -12723,6 +12775,21 @@ SignedIconst: Iconst { $$ = $1; }
12723
12775
| ' -' Iconst { $$ = - $2 ; }
12724
12776
;
12725
12777
12778
+ /* Const that would be replaced by ? if run through pg_stat_statements
12779
+ Note: This reduces to a node and returns a ParamRef if its ? */
12780
+
12781
+ Iconst_or_Normalized: Iconst { $$ = makeIntConst ($1 , @1 ); }
12782
+ | ' ?' { $$ = makeParamRef ( 0 , @1 ); }
12783
+ ;
12784
+
12785
+ Sconst_or_Normalized: Sconst { $$ = makeStringConst ($1 , @1 ); }
12786
+ | ' ?' { $$ = makeParamRef ( 0 , @1 ); }
12787
+ ;
12788
+
12789
+ NonReservedWord_or_Sconst_or_Normalized: NonReservedWord_or_Sconst { $$ = makeStringConst ($1 , @1 ); }
12790
+ | ' ?' { $$ = makeParamRef ( 0 , @1 ); }
12791
+ ;
12792
+
12726
12793
/*
12727
12794
* Name classification hierarchy.
12728
12795
*
@@ -13406,6 +13473,49 @@ makeBoolAConst(bool state, int location)
13406
13473
return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
13407
13474
}
13408
13475
13476
+ /* makeParamRef
13477
+ * Creates a new ParamRef node
13478
+ */
13479
+ static Node* makeParamRef(int number, int location)
13480
+ {
13481
+ ParamRef *p = makeNode(ParamRef);
13482
+ p->number = number;
13483
+ p->location = location;
13484
+ return (Node *) p;
13485
+ }
13486
+
13487
+ static Node *
13488
+ makeParamRefCast(int number, int location, TypeName *typename)
13489
+ {
13490
+ Node *p = makeParamRef(number, location);
13491
+ return makeTypeCast(p, typename, -1);
13492
+ }
13493
+
13494
+ /*
13495
+ * Makes INTERVAL-like nodes for "INTERVAL ? typemod", otherwise treat as A_EXPR
13496
+ */
13497
+ static Node *
13498
+ makeInterval_or_AExprOp(Node *lexpr, Node *rexpr, int location)
13499
+ {
13500
+ if (lexpr && IsA(lexpr, ColumnRef)) {
13501
+ ColumnRef *c = (ColumnRef *) lexpr;
13502
+ if (strcmp(strVal(linitial(c->fields)), "interval") == 0 ) {
13503
+ TypeName *t = SystemTypeName("interval");
13504
+ t->location = c->location;
13505
+
13506
+ /* Its too difficult to tell the parser to give us the right typemod,
13507
+ * just use a dummy one if present
13508
+ */
13509
+ if (rexpr)
13510
+ t->typmods = list_make1(makeIntConst(0, -1));
13511
+
13512
+ return makeParamRefCast(0, location, t);
13513
+ }
13514
+ }
13515
+
13516
+ return (Node *) makeA_Expr(AEXPR_OP, list_make1(makeString("?")), lexpr, rexpr, location);
13517
+ }
13518
+
13409
13519
/* check_qualified_name --- check the result of qualified_name production
13410
13520
*
13411
13521
* It's easiest to let the grammar production for qualified_name allow
0 commit comments