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

Commit 7c079d7

Browse files
committed
Allow generalized expression syntax for partition bounds
Previously, only literals were allowed. This change allows general expressions, including functions calls, which are evaluated at the time the DDL command is executed. Besides offering some more functionality, it simplifies the parser structures and removes some inconsistencies in how the literals were handled. Author: Kyotaro Horiguchi, Tom Lane, Amit Langote Reviewed-by: Peter Eisentraut <peter.eisentraut@2ndquadrant.com> Discussion: https://www.postgresql.org/message-id/flat/9f88b5e0-6da2-5227-20d0-0d7012beaa1c@lab.ntt.co.jp/
1 parent e3565fd commit 7c079d7

File tree

14 files changed

+314
-167
lines changed

14 files changed

+314
-167
lines changed

doc/src/sgml/ref/alter_table.sgml

+3-3
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ ALTER TABLE [ IF EXISTS ] <replaceable class="parameter">name</replaceable>
8686

8787
<phrase>and <replaceable class="parameter">partition_bound_spec</replaceable> is:</phrase>
8888

89-
IN ( { <replaceable class="parameter">numeric_literal</replaceable> | <replaceable class="parameter">string_literal</replaceable> | TRUE | FALSE | NULL } [, ...] ) |
90-
FROM ( { <replaceable class="parameter">numeric_literal</replaceable> | <replaceable class="parameter">string_literal</replaceable> | TRUE | FALSE | MINVALUE | MAXVALUE } [, ...] )
91-
TO ( { <replaceable class="parameter">numeric_literal</replaceable> | <replaceable class="parameter">string_literal</replaceable> | TRUE | FALSE | MINVALUE | MAXVALUE } [, ...] ) |
89+
IN ( <replaceable class="parameter">partition_bound_expr</replaceable> [, ...] ) |
90+
FROM ( { <replaceable class="parameter">partition_bound_expr</replaceable> | MINVALUE | MAXVALUE } [, ...] )
91+
TO ( { <replaceable class="parameter">partition_bound_expr</replaceable> | MINVALUE | MAXVALUE } [, ...] ) |
9292
WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REMAINDER <replaceable class="parameter">numeric_literal</replaceable> )
9393

9494
<phrase>and <replaceable class="parameter">column_constraint</replaceable> is:</phrase>

doc/src/sgml/ref/create_table.sgml

+10-9
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ class="parameter">referential_action</replaceable> ] [ ON UPDATE <replaceable cl
8787

8888
<phrase>and <replaceable class="parameter">partition_bound_spec</replaceable> is:</phrase>
8989

90-
IN ( { <replaceable class="parameter">numeric_literal</replaceable> | <replaceable class="parameter">string_literal</replaceable> | TRUE | FALSE | NULL } [, ...] ) |
91-
FROM ( { <replaceable class="parameter">numeric_literal</replaceable> | <replaceable class="parameter">string_literal</replaceable> | TRUE | FALSE | MINVALUE | MAXVALUE } [, ...] )
92-
TO ( { <replaceable class="parameter">numeric_literal</replaceable> | <replaceable class="parameter">string_literal</replaceable> | TRUE | FALSE | MINVALUE | MAXVALUE } [, ...] ) |
90+
IN ( <replaceable class="parameter">partition_bound_expr</replaceable> [, ...] ) |
91+
FROM ( { <replaceable class="parameter">partition_bound_expr</replaceable> | MINVALUE | MAXVALUE } [, ...] )
92+
TO ( { <replaceable class="parameter">partition_bound_expr</replaceable> | MINVALUE | MAXVALUE } [, ...] ) |
9393
WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REMAINDER <replaceable class="parameter">numeric_literal</replaceable> )
9494

9595
<phrase><replaceable class="parameter">index_parameters</replaceable> in <literal>UNIQUE</literal>, <literal>PRIMARY KEY</literal>, and <literal>EXCLUDE</literal> constraints are:</phrase>
@@ -413,12 +413,13 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
413413
</para>
414414

415415
<para>
416-
Each of the values specified in
417-
the <replaceable class="parameter">partition_bound_spec</replaceable> is
418-
a literal, <literal>NULL</literal>, <literal>MINVALUE</literal>, or
419-
<literal>MAXVALUE</literal>. Each literal value must be either a
420-
numeric constant that is coercible to the corresponding partition key
421-
column's type, or a string literal that is valid input for that type.
416+
<replaceable class="parameter">partition_bound_expr</replaceable> is
417+
any variable-free expression (subqueries, window functions, aggregate
418+
functions, and set-returning functions are not allowed). Its data type
419+
must match the data type of the corresponding partition key column.
420+
The expression is evaluated once at table creation time, so it can
421+
even contain volatile expressions such as
422+
<literal><function>CURRENT_TIMESTAMP</function></literal>.
422423
</para>
423424

424425
<para>

src/backend/commands/tablecmds.c

+9
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
830830
defaultPartOid;
831831
Relation parent,
832832
defaultRel = NULL;
833+
RangeTblEntry *rte;
833834

834835
/* Already have strong enough lock on the parent */
835836
parent = table_open(parentId, NoLock);
@@ -872,6 +873,14 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
872873
pstate = make_parsestate(NULL);
873874
pstate->p_sourcetext = queryString;
874875

876+
/*
877+
* Add an RTE containing this relation, so that transformExpr called
878+
* on partition bound expressions is able to report errors using a
879+
* proper context.
880+
*/
881+
rte = addRangeTableEntryForRelation(pstate, rel, AccessShareLock,
882+
NULL, false, false);
883+
addRTEtoQuery(pstate, rte, false, true, true);
875884
bound = transformPartitionBound(pstate, parent, stmt->partbound);
876885

877886
/*

src/backend/optimizer/util/clauses.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,6 @@ static Node *substitute_actual_parameters(Node *expr, int nargs, List *args,
150150
static Node *substitute_actual_parameters_mutator(Node *node,
151151
substitute_actual_parameters_context *context);
152152
static void sql_inline_error_callback(void *arg);
153-
static Expr *evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
154-
Oid result_collation);
155153
static Query *substitute_actual_srf_parameters(Query *expr,
156154
int nargs, List *args);
157155
static Node *substitute_actual_srf_parameters_mutator(Node *node,
@@ -5045,7 +5043,7 @@ sql_inline_error_callback(void *arg)
50455043
* We use the executor's routine ExecEvalExpr() to avoid duplication of
50465044
* code and ensure we get the same result as the executor would get.
50475045
*/
5048-
static Expr *
5046+
Expr *
50495047
evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
50505048
Oid result_collation)
50515049
{

src/backend/parser/gram.y

+3-57
Original file line numberDiff line numberDiff line change
@@ -581,8 +581,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
581581
%type <partelem> part_elem
582582
%type <list> part_params
583583
%type <partboundspec> PartitionBoundSpec
584-
%type <node> partbound_datum PartitionRangeDatum
585-
%type <list> hash_partbound partbound_datum_list range_datum_list
584+
%type <list> hash_partbound
586585
%type <defelt> hash_partbound_elem
587586

588587
/*
@@ -2731,7 +2730,7 @@ PartitionBoundSpec:
27312730
}
27322731

27332732
/* a LIST partition */
2734-
| FOR VALUES IN_P '(' partbound_datum_list ')'
2733+
| FOR VALUES IN_P '(' expr_list ')'
27352734
{
27362735
PartitionBoundSpec *n = makeNode(PartitionBoundSpec);
27372736

@@ -2744,7 +2743,7 @@ PartitionBoundSpec:
27442743
}
27452744

27462745
/* a RANGE partition */
2747-
| FOR VALUES FROM '(' range_datum_list ')' TO '(' range_datum_list ')'
2746+
| FOR VALUES FROM '(' expr_list ')' TO '(' expr_list ')'
27482747
{
27492748
PartitionBoundSpec *n = makeNode(PartitionBoundSpec);
27502749

@@ -2787,59 +2786,6 @@ hash_partbound:
27872786
}
27882787
;
27892788

2790-
partbound_datum:
2791-
Sconst { $$ = makeStringConst($1, @1); }
2792-
| NumericOnly { $$ = makeAConst($1, @1); }
2793-
| TRUE_P { $$ = makeStringConst(pstrdup("true"), @1); }
2794-
| FALSE_P { $$ = makeStringConst(pstrdup("false"), @1); }
2795-
| NULL_P { $$ = makeNullAConst(@1); }
2796-
;
2797-
2798-
partbound_datum_list:
2799-
partbound_datum { $$ = list_make1($1); }
2800-
| partbound_datum_list ',' partbound_datum
2801-
{ $$ = lappend($1, $3); }
2802-
;
2803-
2804-
range_datum_list:
2805-
PartitionRangeDatum { $$ = list_make1($1); }
2806-
| range_datum_list ',' PartitionRangeDatum
2807-
{ $$ = lappend($1, $3); }
2808-
;
2809-
2810-
PartitionRangeDatum:
2811-
MINVALUE
2812-
{
2813-
PartitionRangeDatum *n = makeNode(PartitionRangeDatum);
2814-
2815-
n->kind = PARTITION_RANGE_DATUM_MINVALUE;
2816-
n->value = NULL;
2817-
n->location = @1;
2818-
2819-
$$ = (Node *) n;
2820-
}
2821-
| MAXVALUE
2822-
{
2823-
PartitionRangeDatum *n = makeNode(PartitionRangeDatum);
2824-
2825-
n->kind = PARTITION_RANGE_DATUM_MAXVALUE;
2826-
n->value = NULL;
2827-
n->location = @1;
2828-
2829-
$$ = (Node *) n;
2830-
}
2831-
| partbound_datum
2832-
{
2833-
PartitionRangeDatum *n = makeNode(PartitionRangeDatum);
2834-
2835-
n->kind = PARTITION_RANGE_DATUM_VALUE;
2836-
n->value = $1;
2837-
n->location = @1;
2838-
2839-
$$ = (Node *) n;
2840-
}
2841-
;
2842-
28432789
/*****************************************************************************
28442790
*
28452791
* ALTER TYPE

src/backend/parser/parse_agg.c

+10
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,13 @@ check_agglevels_and_constraints(ParseState *pstate, Node *expr)
506506
else
507507
err = _("grouping operations are not allowed in trigger WHEN conditions");
508508

509+
break;
510+
case EXPR_KIND_PARTITION_BOUND:
511+
if (isAgg)
512+
err = _("aggregate functions are not allowed in partition bound");
513+
else
514+
err = _("grouping operations are not allowed in partition bound");
515+
509516
break;
510517
case EXPR_KIND_PARTITION_EXPRESSION:
511518
if (isAgg)
@@ -904,6 +911,9 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc,
904911
case EXPR_KIND_TRIGGER_WHEN:
905912
err = _("window functions are not allowed in trigger WHEN conditions");
906913
break;
914+
case EXPR_KIND_PARTITION_BOUND:
915+
err = _("window functions are not allowed in partition bound");
916+
break;
907917
case EXPR_KIND_PARTITION_EXPRESSION:
908918
err = _("window functions are not allowed in partition key expressions");
909919
break;

src/backend/parser/parse_expr.c

+5
Original file line numberDiff line numberDiff line change
@@ -1843,6 +1843,9 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
18431843
case EXPR_KIND_TRIGGER_WHEN:
18441844
err = _("cannot use subquery in trigger WHEN condition");
18451845
break;
1846+
case EXPR_KIND_PARTITION_BOUND:
1847+
err = _("cannot use subquery in partition bound");
1848+
break;
18461849
case EXPR_KIND_PARTITION_EXPRESSION:
18471850
err = _("cannot use subquery in partition key expression");
18481851
break;
@@ -3474,6 +3477,8 @@ ParseExprKindName(ParseExprKind exprKind)
34743477
return "EXECUTE";
34753478
case EXPR_KIND_TRIGGER_WHEN:
34763479
return "WHEN";
3480+
case EXPR_KIND_PARTITION_BOUND:
3481+
return "partition bound";
34773482
case EXPR_KIND_PARTITION_EXPRESSION:
34783483
return "PARTITION BY";
34793484
case EXPR_KIND_CALL_ARGUMENT:

src/backend/parser/parse_func.c

+3
Original file line numberDiff line numberDiff line change
@@ -2364,6 +2364,9 @@ check_srf_call_placement(ParseState *pstate, Node *last_srf, int location)
23642364
case EXPR_KIND_TRIGGER_WHEN:
23652365
err = _("set-returning functions are not allowed in trigger WHEN conditions");
23662366
break;
2367+
case EXPR_KIND_PARTITION_BOUND:
2368+
err = _("set-returning functions are not allowed in partition bound");
2369+
break;
23672370
case EXPR_KIND_PARTITION_EXPRESSION:
23682371
err = _("set-returning functions are not allowed in partition key expressions");
23692372
break;

0 commit comments

Comments
 (0)