Re: Boolean partitions syntax

Поиск
Список
Период
Сортировка
От Kyotaro HORIGUCHI
Тема Re: Boolean partitions syntax
Дата
Msg-id 20180410.201305.37655300.horiguchi.kyotaro@lab.ntt.co.jp
обсуждение исходный текст
Ответ на Re: Boolean partitions syntax  (Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>)
Ответы Re: Boolean partitions syntax  (David Rowley <david.rowley@2ndquadrant.com>)
Список pgsql-hackers
Hello.

Note: This is not intended to be committed this time but just for
information.

At Tue, 10 Apr 2018 10:34:27 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> wrote in
<20180410.103427.244142052.horiguchi.kyotaro@lab.ntt.co.jp>
> Just adding negation would work as a_expr is doing.
> 
> >             | '-' a_expr                    %prec UMINUS
> >                 { $$ = doNegate($2, @1); }

a_expr fits partbound_datum_list as is but it cannot sit
side-by-side with MAX/MINVALUE at all. However c_expr can if
columnref is not excluded. The attached patch does that and
partition bound accepts the following syntax. (I didn't see the
transform side at all)

create table p2c1 partition of p2 for values from (log(1000),0+1,0/1) to (10, 10, ('1'||'0')::int);

=# \d p2c1
...
Partition of: p2 FOR VALUES FROM (3, 1, 0) TO (10, 10, 10)


regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index dd0c26c11b..2a3d6a3bb8 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -180,6 +180,8 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
 static List *mergeTableFuncParameters(List *func_args, List *columns);
 static TypeName *TableFuncTypeName(List *columns);
 static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner);
+static Node *makePartRangeDatum(PartitionRangeDatumKind kind, Node *value,
+                                int location);
 static void SplitColQualList(List *qualList,
                              List **constraintList, CollateClause **collClause,
                              core_yyscan_t yyscanner);
@@ -472,7 +474,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <node>    columnDef columnOptions
 %type <defelt>    def_elem reloption_elem old_aggr_elem operator_def_elem
 %type <node>    def_arg columnElem where_clause where_or_current_clause
-                a_expr b_expr c_expr AexprConst indirection_el opt_slice_bound
+                a_expr l_expr b_expr b0_expr c_expr c0_expr AexprConst indirection_el opt_slice_bound
                 columnref in_expr having_clause func_table xmltable array_expr
                 ExclusionWhereClause operator_def_arg
 %type <list>    rowsfrom_item rowsfrom_list opt_col_def_list
@@ -585,7 +587,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <partelem>    part_elem
 %type <list>        part_params
 %type <partboundspec> PartitionBoundSpec
-%type <node>        partbound_datum PartitionRangeDatum
+%type <node>        PartitionRangeDatum
 %type <list>        hash_partbound partbound_datum_list range_datum_list
 %type <defelt>        hash_partbound_elem
 
@@ -2804,15 +2806,9 @@ hash_partbound:
             }
         ;
 
-partbound_datum:
-            Sconst            { $$ = makeStringConst($1, @1); }
-            | NumericOnly    { $$ = makeAConst($1, @1); }
-            | NULL_P        { $$ = makeNullAConst(@1); }
-        ;
-
 partbound_datum_list:
-            partbound_datum                        { $$ = list_make1($1); }
-            | partbound_datum_list ',' partbound_datum
+            a_expr                        { $$ = list_make1($1); }
+            | partbound_datum_list ',' a_expr
                                                 { $$ = lappend($1, $3); }
         ;
 
@@ -2825,33 +2821,18 @@ range_datum_list:
 PartitionRangeDatum:
             MINVALUE
                 {
-                    PartitionRangeDatum *n = makeNode(PartitionRangeDatum);
-
-                    n->kind = PARTITION_RANGE_DATUM_MINVALUE;
-                    n->value = NULL;
-                    n->location = @1;
-
-                    $$ = (Node *) n;
+                    $$ = makePartRangeDatum(PARTITION_RANGE_DATUM_MINVALUE,
+                                            NULL, @1);
                 }
             | MAXVALUE
                 {
-                    PartitionRangeDatum *n = makeNode(PartitionRangeDatum);
-
-                    n->kind = PARTITION_RANGE_DATUM_MAXVALUE;
-                    n->value = NULL;
-                    n->location = @1;
-
-                    $$ = (Node *) n;
+                    $$ = makePartRangeDatum(PARTITION_RANGE_DATUM_MAXVALUE,
+                                            NULL, @1);
                 }
-            | partbound_datum
+            | l_expr
                 {
-                    PartitionRangeDatum *n = makeNode(PartitionRangeDatum);
-
-                    n->kind = PARTITION_RANGE_DATUM_VALUE;
-                    n->value = $1;
-                    n->location = @1;
-
-                    $$ = (Node *) n;
+                    $$ = makePartRangeDatum(PARTITION_RANGE_DATUM_VALUE,
+                                            $1, @1);
                 }
         ;
 
@@ -13478,9 +13459,20 @@ a_expr:        c_expr                                    { $$ = $1; }
  * cause trouble in the places where b_expr is used.  For simplicity, we
  * just eliminate all the boolean-keyword-operator productions from b_expr.
  */
-b_expr:        c_expr
-                { $$ = $1; }
-            | b_expr TYPECAST Typename
+b_expr:        c_expr { $$ = $1; }
+            | b0_expr { $$ = $1; }
+        ;
+
+/*
+ * l_expr is a subset of b_expr so as to fit in comma-separated list based on
+ * b_expr.
+ */
+l_expr:        c0_expr { $$ = $1; }
+            | b0_expr { $$ = $1; }
+        ;
+
+/* common part of b_expr and l_expr */
+b0_expr: b_expr TYPECAST Typename
                 { $$ = makeTypeCast($1, $3, @2); }
             | '+' b_expr                    %prec UMINUS
                 { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
@@ -13554,7 +13546,11 @@ b_expr:        c_expr
  * ambiguity to the b_expr syntax.
  */
 c_expr:        columnref                                { $$ = $1; }
-            | AexprConst                            { $$ = $1; }
+            | c0_expr                                { $$ = $1; }
+        ;
+
+/* common part of c_expr and l_expr */
+c0_expr:         AexprConst                            { $$ = $1; }
             | PARAM opt_indirection
                 {
                     ParamRef *p = makeNode(ParamRef);
@@ -16275,6 +16271,18 @@ makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner)
     return r;
 }
 
+static Node *
+makePartRangeDatum(PartitionRangeDatumKind kind, Node *value, int location)
+{
+    PartitionRangeDatum *n = makeNode(PartitionRangeDatum);
+
+    n->kind = kind;
+    n->value = value;
+    n->location = location;
+
+    return (Node *) n;
+}
+
 /* Separate Constraint nodes from COLLATE clauses in a ColQualList */
 static void
 SplitColQualList(List *qualList,
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 0307738946..61f59f7527 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -506,6 +506,12 @@ check_agglevels_and_constraints(ParseState *pstate, Node *expr)
             else
                 err = _("grouping operations are not allowed in EXECUTE parameters");
 
+        case EXPR_KIND_PARTITION_BOUNDS:
+            if (isAgg)
+                err = _("aggregate functions are not allowed in partition bounds");
+            else
+                err = _("grouping operations are not allowed in partition bounds");
+
             break;
         case EXPR_KIND_TRIGGER_WHEN:
             if (isAgg)
@@ -908,6 +914,8 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
             break;
         case EXPR_KIND_PARTITION_EXPRESSION:
             err = _("window functions are not allowed in partition key expressions");
+        case EXPR_KIND_PARTITION_BOUNDS:
+            err = _("window functions are not allowed in partition bounds");
             break;
         case EXPR_KIND_CALL_ARGUMENT:
             err = _("window functions are not allowed in CALL arguments");
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 38fbe3366f..a7f3d86f75 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -1850,6 +1850,9 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
         case EXPR_KIND_CALL_ARGUMENT:
             err = _("cannot use subquery in CALL argument");
             break;
+        case EXPR_KIND_PARTITION_BOUNDS:
+            err = _("cannot use subquery in partition bounds");
+            break;
 
             /*
              * There is intentionally no default: case here, so that the
@@ -3474,6 +3477,8 @@ ParseExprKindName(ParseExprKind exprKind)
             return "WHEN";
         case EXPR_KIND_PARTITION_EXPRESSION:
             return "PARTITION BY";
+        case EXPR_KIND_PARTITION_BOUNDS:
+            return "partition bounds";
         case EXPR_KIND_CALL_ARGUMENT:
             return "CALL";
         case EXPR_KIND_MERGE_WHEN_AND:
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 615aee6d15..a39e26dd76 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -2306,6 +2306,9 @@ check_srf_call_placement(ParseState *pstate, Node *last_srf, int location)
         case EXPR_KIND_PARTITION_EXPRESSION:
             err = _("set-returning functions are not allowed in partition key expressions");
             break;
+        case EXPR_KIND_PARTITION_BOUNDS:
+            err = _("set-returning functions are not allowed in partition bounds");
+            break;
         case EXPR_KIND_CALL_ARGUMENT:
             err = _("set-returning functions are not allowed in CALL arguments");
             break;
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index f9f9904bad..c14f1265a9 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -138,7 +138,7 @@ static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column);
 static void setSchemaName(char *context_schema, char **stmt_schema_name);
 static void transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd);
 static void validateInfiniteBounds(ParseState *pstate, List *blist);
-static Const *transformPartitionBoundValue(ParseState *pstate, A_Const *con,
+static Const *transformPartitionBoundValue(ParseState *pstate, Node *con,
                              const char *colName, Oid colType, int32 colTypmod);
 
 
@@ -3674,12 +3674,12 @@ transformPartitionBound(ParseState *pstate, Relation parent,
         result_spec->listdatums = NIL;
         foreach(cell, spec->listdatums)
         {
-            A_Const    *con = castNode(A_Const, lfirst(cell));
+            Node       *expr = (Node *)lfirst (cell);
             Const       *value;
             ListCell   *cell2;
             bool        duplicate;
 
-            value = transformPartitionBoundValue(pstate, con,
+            value = transformPartitionBoundValue(pstate, expr,
                                                  colname, coltype, coltypmod);
 
             /* Don't add to the result if the value is a duplicate */
@@ -3740,7 +3740,6 @@ transformPartitionBound(ParseState *pstate, Relation parent,
             char       *colname;
             Oid            coltype;
             int32        coltypmod;
-            A_Const    *con;
             Const       *value;
 
             /* Get the column's name in case we need to output an error */
@@ -3761,8 +3760,8 @@ transformPartitionBound(ParseState *pstate, Relation parent,
 
             if (ldatum->value)
             {
-                con = castNode(A_Const, ldatum->value);
-                value = transformPartitionBoundValue(pstate, con,
+                value = transformPartitionBoundValue(pstate,
+                                                     ldatum->value,
                                                      colname,
                                                      coltype, coltypmod);
                 if (value->constisnull)
@@ -3775,8 +3774,8 @@ transformPartitionBound(ParseState *pstate, Relation parent,
 
             if (rdatum->value)
             {
-                con = castNode(A_Const, rdatum->value);
-                value = transformPartitionBoundValue(pstate, con,
+                value = transformPartitionBoundValue(pstate,
+                                                     rdatum->value,
                                                      colname,
                                                      coltype, coltypmod);
                 if (value->constisnull)
@@ -3845,13 +3844,13 @@ validateInfiniteBounds(ParseState *pstate, List *blist)
  * Transform one constant in a partition bound spec
  */
 static Const *
-transformPartitionBoundValue(ParseState *pstate, A_Const *con,
+transformPartitionBoundValue(ParseState *pstate, Node *val,
                              const char *colName, Oid colType, int32 colTypmod)
 {
     Node       *value;
 
     /* Make it into a Const */
-    value = (Node *) make_const(pstate, &con->val, con->location);
+    value = transformExpr(pstate, val, EXPR_KIND_PARTITION_BOUNDS);
 
     /* Coerce to correct type */
     value = coerce_to_target_type(pstate,
@@ -3867,7 +3866,7 @@ transformPartitionBoundValue(ParseState *pstate, A_Const *con,
                 (errcode(ERRCODE_DATATYPE_MISMATCH),
                  errmsg("specified value cannot be cast to type %s for column \"%s\"",
                         format_type_be(colType), colName),
-                 parser_errposition(pstate, con->location)));
+                 parser_errposition(pstate, exprLocation(val))));
 
     /* Simplify the expression, in case we had a coercion */
     if (!IsA(value, Const))
@@ -3881,7 +3880,7 @@ transformPartitionBoundValue(ParseState *pstate, A_Const *con,
                         format_type_be(colType), colName),
                  errdetail("The cast requires a non-immutable conversion."),
                  errhint("Try putting the literal value in single quotes."),
-                 parser_errposition(pstate, con->location)));
+                 parser_errposition(pstate, exprLocation(val))));
 
     return (Const *) value;
 }
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 3fd2151ccb..5eccf5078a 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -70,6 +70,7 @@ typedef enum ParseExprKind
     EXPR_KIND_TRIGGER_WHEN,        /* WHEN condition in CREATE TRIGGER */
     EXPR_KIND_POLICY,            /* USING or WITH CHECK expr in policy */
     EXPR_KIND_PARTITION_EXPRESSION, /* PARTITION BY expression */
+    EXPR_KIND_PARTITION_BOUNDS,     /* partition bounds value */
     EXPR_KIND_CALL_ARGUMENT        /* procedure argument in CALL */
 } ParseExprKind;
 
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index e724439037..ac71d17d2c 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -308,7 +308,7 @@ CREATE TABLE partitioned (
     a int,
     b int
 ) PARTITION BY RANGE ((avg(a) OVER (PARTITION BY b)));
-ERROR:  window functions are not allowed in partition key expressions
+ERROR:  window functions are not allowed in partition bounds
 CREATE TABLE partitioned (
     a int
 ) PARTITION BY LIST ((a LIKE (SELECT 1)));
@@ -450,13 +450,9 @@ CREATE TABLE part_1 PARTITION OF list_parted FOR VALUES IN ('1');
 CREATE TABLE part_2 PARTITION OF list_parted FOR VALUES IN (2);
 CREATE TABLE part_null PARTITION OF list_parted FOR VALUES IN (null);
 CREATE TABLE fail_part PARTITION OF list_parted FOR VALUES IN (int '1');
-ERROR:  syntax error at or near "int"
-LINE 1: ... fail_part PARTITION OF list_parted FOR VALUES IN (int '1');
-                                                              ^
+ERROR:  partition "fail_part" would overlap partition "part_1"
 CREATE TABLE fail_part PARTITION OF list_parted FOR VALUES IN ('1'::int);
-ERROR:  syntax error at or near "::"
-LINE 1: ...fail_part PARTITION OF list_parted FOR VALUES IN ('1'::int);
-                                                                ^
+ERROR:  partition "fail_part" would overlap partition "part_1"
 -- syntax does not allow empty list of values for list partitions
 CREATE TABLE fail_part PARTITION OF list_parted FOR VALUES IN ();
 ERROR:  syntax error at or near ")"

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Sergei Kornilov
Дата:
Сообщение: Re: Custom PGC_POSTMASTER GUC variables ... feasible?
Следующее
От: ilmari@ilmari.org (Dagfinn Ilmari Mannsåker)
Дата:
Сообщение: Re: Transform for pl/perl