Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit02ff474

Browse files
committed
improved function cook_partitioning_expression()
1 parentba12800 commit02ff474

File tree

7 files changed

+108
-76
lines changed

7 files changed

+108
-76
lines changed

‎expected/pathman_basic.out

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,9 +1511,9 @@ SELECT pathman.create_partitions_from_range('test."RangeRel"', 'dt', '2015-01-01
15111511
DROP TABLE test."RangeRel" CASCADE;
15121512
NOTICE: drop cascades to 6 other objects
15131513
SELECT * FROM pathman.pathman_config;
1514-
partrel | expr | parttype | range_interval | cooked_expr
1515-
--------------------+------+----------+----------------+------------------------------------------------------------------------------------------------------------------------
1516-
test.num_range_rel | id | 2 | 1000 | {VAR :varno 1 :varattno 1 :vartype 23 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnoold 1 :varoattno 1 :location-1}
1514+
partrel | expr | parttype | range_interval | cooked_expr
1515+
--------------------+------+----------+----------------+-----------------------------------------------------------------------------------------------------------------------
1516+
test.num_range_rel | id | 2 | 1000 | {VAR :varno 1 :varattno 1 :vartype 23 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnoold 1 :varoattno 1 :location8}
15171517
(1 row)
15181518

15191519
CREATE TABLE test."RangeRel" (

‎expected/pathman_calamity.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ ERROR: 'expression' should not be NULL
306306
SELECT validate_expression('calamity.part_test', 'valval');/* not ok */
307307
ERROR: cannot find type name for attribute "valval" of relation "part_test"
308308
SELECT validate_expression('calamity.part_test', 'random()');/* not ok */
309-
ERROR: failed to analyze partitioning expression(random())
309+
ERROR: failed to analyze partitioning expression"random()"
310310
SELECT validate_expression('calamity.part_test', 'val');/* OK */
311311
validate_expression
312312
---------------------

‎expected/pathman_expressions.out

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,43 +27,52 @@ SELECT COUNT(*) FROM test_exprs.hash_rel;
2727
5
2828
(1 row)
2929

30+
\set VERBOSITY default
3031
/* Try using constant expression */
3132
SELECT create_hash_partitions('test_exprs.hash_rel', '1 + 1', 4);
32-
ERROR: partitioning expression should reference table "hash_rel"
33-
\set VERBOSITY default
33+
ERROR: failed to analyze partitioning expression "1 + 1"
34+
DETAIL: partitioning expression should reference table "hash_rel"
35+
CONTEXT: SQL statement "SELECT public.validate_expression(parent_relid, expression)"
36+
PL/pgSQL function prepare_for_partitioning(regclass,text,boolean) line 9 at PERFORM
37+
SQL statement "SELECT public.prepare_for_partitioning(parent_relid,
38+
expression,
39+
partition_data)"
40+
PL/pgSQL function create_hash_partitions(regclass,text,integer,boolean,text[],text[]) line 4 at PERFORM
41+
/* Try using multiple queries */
42+
SELECT create_hash_partitions('test_exprs.hash_rel',
43+
'value, (select oid from pg_class limit 1)',
44+
4);
45+
ERROR: failed to analyze partitioning expression "value, (select oid from pg_class limit 1)"
46+
DETAIL: subqueries are not allowed in partitioning expression
47+
CONTEXT: SQL statement "SELECT public.validate_expression(parent_relid, expression)"
48+
PL/pgSQL function prepare_for_partitioning(regclass,text,boolean) line 9 at PERFORM
49+
SQL statement "SELECT public.prepare_for_partitioning(parent_relid,
50+
expression,
51+
partition_data)"
52+
PL/pgSQL function create_hash_partitions(regclass,text,integer,boolean,text[],text[]) line 4 at PERFORM
3453
/* Try using mutable expression */
3554
SELECT create_hash_partitions('test_exprs.hash_rel', 'random()', 4);
36-
ERROR: failed to analyze partitioning expression(random())
55+
ERROR: failed to analyze partitioning expression"random()"
3756
DETAIL: functions in partitioning expression must be marked IMMUTABLE
3857
CONTEXT: SQL statement "SELECT public.validate_expression(parent_relid, expression)"
3958
PL/pgSQL function prepare_for_partitioning(regclass,text,boolean) line 9 at PERFORM
4059
SQL statement "SELECT public.prepare_for_partitioning(parent_relid,
4160
expression,
4261
partition_data)"
4362
PL/pgSQL function create_hash_partitions(regclass,text,integer,boolean,text[],text[]) line 4 at PERFORM
44-
/* Check that 'pathman_hooks_enabled' is true (1 partition in plan) */
45-
EXPLAIN (COSTS OFF) INSERT INTO test_exprs.canary_copy
46-
SELECT * FROM test_exprs.canary WHERE val = 1;
47-
QUERY PLAN
48-
----------------------------------
49-
Insert on canary_copy
50-
-> Append
51-
-> Seq Scan on canary_0
52-
Filter: (val = 1)
53-
(4 rows)
54-
55-
/* Try using missing columns */
63+
/* Try using broken parentheses */
5664
SELECT create_hash_partitions('test_exprs.hash_rel', 'value * value2))', 4);
57-
ERROR: failed to parse partitioning expression(value * value2)))
65+
ERROR: failed to parse partitioning expression"value * value2))"
5866
DETAIL: syntax error at or near ")"
5967
QUERY: SELECT public.validate_expression(parent_relid, expression)
6068
CONTEXT: PL/pgSQL function prepare_for_partitioning(regclass,text,boolean) line 9 at PERFORM
6169
SQL statement "SELECT public.prepare_for_partitioning(parent_relid,
6270
expression,
6371
partition_data)"
6472
PL/pgSQL function create_hash_partitions(regclass,text,integer,boolean,text[],text[]) line 4 at PERFORM
73+
/* Try using missing columns */
6574
SELECT create_hash_partitions('test_exprs.hash_rel', 'value * value3', 4);
66-
ERROR: failed to analyze partitioning expression(value * value3)
75+
ERROR: failed to analyze partitioning expression"value * value3"
6776
DETAIL: column "value3" does not exist
6877
HINT: Perhaps you meant to reference the column "hash_rel.value" or the column "hash_rel.value2".
6978
QUERY: SELECT public.validate_expression(parent_relid, expression)
@@ -144,15 +153,22 @@ EXPLAIN (COSTS OFF) SELECT * FROM test_exprs.hash_rel WHERE (value * value2) = 5
144153
CREATE TABLE test_exprs.range_rel (id SERIAL PRIMARY KEY, dt TIMESTAMP, txt TEXT);
145154
INSERT INTO test_exprs.range_rel (dt, txt)
146155
SELECT g, md5(g::TEXT) FROM generate_series('2015-01-01', '2020-04-30', '1 month'::interval) as g;
156+
\set VERBOSITY default
147157
/* Try using constant expression */
148158
SELECT create_range_partitions('test_exprs.range_rel', '''16 years''::interval',
149159
'15 years'::INTERVAL, '1 year'::INTERVAL, 10);
150-
ERROR: partitioning expression should reference table "range_rel"
151-
\set VERBOSITY default
160+
ERROR: failed to analyze partitioning expression "'16 years'::interval"
161+
DETAIL: partitioning expression should reference table "range_rel"
162+
CONTEXT: SQL statement "SELECT public.validate_expression(parent_relid, expression)"
163+
PL/pgSQL function prepare_for_partitioning(regclass,text,boolean) line 9 at PERFORM
164+
SQL statement "SELECT public.prepare_for_partitioning(parent_relid,
165+
expression,
166+
partition_data)"
167+
PL/pgSQL function create_range_partitions(regclass,text,anyelement,interval,integer,boolean) line 12 at PERFORM
152168
/* Try using mutable expression */
153169
SELECT create_range_partitions('test_exprs.range_rel', 'RANDOM()',
154170
'15 years'::INTERVAL, '1 year'::INTERVAL, 10);
155-
ERROR: failed to analyze partitioning expression(RANDOM())
171+
ERROR: failed to analyze partitioning expression"RANDOM()"
156172
DETAIL: functions in partitioning expression must be marked IMMUTABLE
157173
CONTEXT: SQL statement "SELECT public.validate_expression(parent_relid, expression)"
158174
PL/pgSQL function prepare_for_partitioning(regclass,text,boolean) line 9 at PERFORM

‎sql/pathman_expressions.sql

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,24 @@ INSERT INTO test_exprs.hash_rel (value, value2)
2727
SELECTCOUNT(*)FROMtest_exprs.hash_rel;
2828

2929

30+
31+
\set VERBOSITY default
32+
3033
/* Try using constant expression*/
3134
SELECT create_hash_partitions('test_exprs.hash_rel','1 + 1',4);
3235

33-
34-
\set VERBOSITY default
36+
/* Try using multiple queries*/
37+
SELECT create_hash_partitions('test_exprs.hash_rel',
38+
'value, (select oid from pg_class limit 1)',
39+
4);
3540

3641
/* Try using mutable expression*/
3742
SELECT create_hash_partitions('test_exprs.hash_rel','random()',4);
3843

39-
/* Check that 'pathman_hooks_enabled' is true (1 partition in plan)*/
40-
EXPLAIN (COSTS OFF)INSERT INTOtest_exprs.canary_copy
41-
SELECT*FROMtest_exprs.canaryWHERE val=1;
44+
/* Try using broken parentheses*/
45+
SELECT create_hash_partitions('test_exprs.hash_rel','value * value2))',4);
4246

4347
/* Try using missing columns*/
44-
SELECT create_hash_partitions('test_exprs.hash_rel','value * value2))',4);
4548
SELECT create_hash_partitions('test_exprs.hash_rel','value * value3',4);
4649

4750
/* Check that 'pathman_hooks_enabled' is true (1 partition in plan)*/
@@ -75,13 +78,13 @@ INSERT INTO test_exprs.range_rel (dt, txt)
7578
SELECT g, md5(g::TEXT)FROM generate_series('2015-01-01','2020-04-30','1 month'::interval)as g;
7679

7780

81+
82+
\set VERBOSITY default
83+
7884
/* Try using constant expression*/
7985
SELECT create_range_partitions('test_exprs.range_rel','''16 years''::interval',
8086
'15 years'::INTERVAL,'1 year'::INTERVAL,10);
8187

82-
83-
\set VERBOSITY default
84-
8588
/* Try using mutable expression*/
8689
SELECT create_range_partitions('test_exprs.range_rel','RANDOM()',
8790
'15 years'::INTERVAL,'1 year'::INTERVAL,10);

‎src/hooks.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,6 @@ pathman_join_pathlist_hook(PlannerInfo *root,
9191
set_join_pathlist_next(root,joinrel,outerrel,
9292
innerrel,jointype,extra);
9393

94-
/* Hooks can be disabled */
95-
if (!pathman_hooks_enabled)
96-
return;
97-
9894
/* Check that both pg_pathman & RuntimeAppend nodes are enabled */
9995
if (!IsPathmanReady()|| !pg_pathman_enable_runtimeappend)
10096
return;
@@ -289,10 +285,6 @@ pathman_rel_pathlist_hook(PlannerInfo *root,
289285
if (set_rel_pathlist_hook_next!=NULL)
290286
set_rel_pathlist_hook_next(root,rel,rti,rte);
291287

292-
/* Hooks can be disabled */
293-
if (!pathman_hooks_enabled)
294-
return;
295-
296288
/* Make sure that pg_pathman is ready */
297289
if (!IsPathmanReady())
298290
return;
@@ -554,7 +546,7 @@ pathman_planner_hook(Query *parse, int cursorOptions, ParamListInfo boundParams)
554546
uint32query_id=parse->queryId;
555547

556548
/* Save the result in case it changes */
557-
boolpathman_ready=pathman_hooks_enabled&&IsPathmanReady();
549+
boolpathman_ready=IsPathmanReady();
558550

559551
PG_TRY();
560552
{

‎src/nodes_common.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -348,9 +348,6 @@ canonicalize_custom_exprs_mutator(Node *node, void *cxt)
348348
/* Restore original 'varattno' */
349349
var->varattno=var->varoattno;
350350

351-
/* Forget 'location' */
352-
var->location=-1;
353-
354351
return (Node*)var;
355352
}
356353

‎src/relation_info.c

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@
4747

4848

4949
/* Error messages for partitioning expression */
50-
#definePARSE_PART_EXPR_ERROR"failed to parse partitioning expression(%s)"
51-
#defineCOOK_PART_EXPR_ERROR"failed to analyze partitioning expression(%s)"
50+
#definePARSE_PART_EXPR_ERROR"failed to parse partitioning expression\"%s\""
51+
#defineCOOK_PART_EXPR_ERROR"failed to analyze partitioning expression\"%s\""
5252

5353

5454
/* Comparison function info */
@@ -105,6 +105,8 @@ static void fill_pbin_with_bounds(PartBoundInfo *pbin,
105105

106106
staticintcmp_range_entries(constvoid*p1,constvoid*p2,void*arg);
107107

108+
staticboolquery_contains_subqueries(Node*node,void*context);
109+
108110

109111
void
110112
init_relation_info_static_data(void)
@@ -139,7 +141,6 @@ refresh_pathman_relation_info(Oid relid,
139141
Datumparam_values[Natts_pathman_config_params];
140142
boolparam_isnull[Natts_pathman_config_params];
141143
char*expr;
142-
Relidsexpr_varnos;
143144
HeapTuplehtup;
144145
MemoryContextold_mcxt;
145146

@@ -182,11 +183,6 @@ refresh_pathman_relation_info(Oid relid,
182183
prel->expr= (Node*)stringToNode(expr);
183184
fix_opfuncids(prel->expr);
184185

185-
expr_varnos=pull_varnos(prel->expr);
186-
if (bms_num_members(expr_varnos)!=1)
187-
elog(ERROR,"partitioning expression should reference table \"%s\"",
188-
get_rel_name(relid));
189-
190186
/* Extract Vars and varattnos of partitioning expression */
191187
prel->expr_vars=NIL;
192188
prel->expr_atts=NULL;
@@ -559,6 +555,17 @@ fill_prel_with_partitions(PartRelationInfo *prel,
559555
#endif
560556
}
561557

558+
/* qsort comparison function for RangeEntries */
559+
staticint
560+
cmp_range_entries(constvoid*p1,constvoid*p2,void*arg)
561+
{
562+
constRangeEntry*v1= (constRangeEntry*)p1;
563+
constRangeEntry*v2= (constRangeEntry*)p2;
564+
cmp_func_info*info= (cmp_func_info*)arg;
565+
566+
returncmp_bounds(&info->flinfo,info->collid,&v1->min,&v2->min);
567+
}
568+
562569

563570
/*
564571
* Partitioning expression routines.
@@ -691,34 +698,47 @@ cook_partitioning_expression(const Oid relid,
691698

692699
PG_TRY();
693700
{
694-
TargetEntry*target_entry;
695-
696-
Query*expr_query;
697-
PlannedStmt*expr_plan;
698-
Node*expr;
701+
Query*query;
702+
Node*expr;
703+
Relidsexpr_varnos;
699704

700705
/* This will fail with ERROR in case of wrong expression */
701706
query_tree_list=pg_analyze_and_rewrite(parse_tree,query_string,NULL,0);
702707

708+
/* Sanity check #1 */
703709
if (list_length(query_tree_list)!=1)
704710
elog(ERROR,"partitioning expression produced more than 1 query");
705711

706-
expr_query= (Query*)linitial(query_tree_list);
712+
query= (Query*)linitial(query_tree_list);
707713

708-
/* Plan this query. We reuse 'expr_node' here */
709-
expr_plan=pg_plan_query(expr_query,0,NULL);
714+
/* Sanity check #2 */
715+
if (list_length(query->targetList)!=1)
716+
elog(ERROR,"there should be exactly 1 partitioning expression");
710717

711-
target_entry=IsA(expr_plan->planTree,IndexOnlyScan) ?
712-
linitial(((IndexOnlyScan*)expr_plan->planTree)->indextlist) :
713-
linitial(expr_plan->planTree->targetlist);
718+
/* Sanity check #3 */
719+
if (query_tree_walker(query,query_contains_subqueries,NULL,0))
720+
elog(ERROR,"subqueries are not allowed in partitioning expression");
714721

715-
expr=eval_const_expressions(NULL, (Node*)target_entry->expr);
722+
expr= (Node*) ((TargetEntry*)linitial(query->targetList))->expr;
723+
expr=eval_const_expressions(NULL,expr);
724+
725+
/* Sanity check #4 */
716726
if (contain_mutable_functions(expr))
717727
ereport(ERROR,
718728
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
719729
errmsg("functions in partitioning expression"
720730
" must be marked IMMUTABLE")));
721731

732+
/* Sanity check #5 */
733+
expr_varnos=pull_varnos(expr);
734+
if (bms_num_members(expr_varnos)!=1||
735+
((RangeTblEntry*)linitial(query->rtable))->relid!=relid)
736+
{
737+
elog(ERROR,"partitioning expression should reference table \"%s\"",
738+
get_rel_name(relid));
739+
}
740+
bms_free(expr_varnos);
741+
722742
Assert(expr);
723743
expr_serialized=nodeToString(expr);
724744

@@ -755,6 +775,7 @@ cook_partitioning_expression(const Oid relid,
755775
/* Switch to previous mcxt */
756776
MemoryContextSwitchTo(old_mcxt);
757777

778+
/* Get Datum of serialized expression (right mcxt) */
758779
expr_datum=CStringGetTextDatum(expr_serialized);
759780

760781
/* Free memory */
@@ -763,6 +784,20 @@ cook_partitioning_expression(const Oid relid,
763784
returnexpr_datum;
764785
}
765786

787+
/* Check if query has subqueries */
788+
staticbool
789+
query_contains_subqueries(Node*node,void*context)
790+
{
791+
if (node==NULL)
792+
return false;
793+
794+
/* We've met a subquery */
795+
if (IsA(node,Query))
796+
return true;
797+
798+
returnexpression_tree_walker(node,query_contains_subqueries,NULL);
799+
}
800+
766801

767802
/*
768803
* Functions for delayed invalidation.
@@ -1308,17 +1343,6 @@ fill_pbin_with_bounds(PartBoundInfo *pbin,
13081343
}
13091344
}
13101345

1311-
/* qsort comparison function for RangeEntries */
1312-
staticint
1313-
cmp_range_entries(constvoid*p1,constvoid*p2,void*arg)
1314-
{
1315-
constRangeEntry*v1= (constRangeEntry*)p1;
1316-
constRangeEntry*v2= (constRangeEntry*)p2;
1317-
cmp_func_info*info= (cmp_func_info*)arg;
1318-
1319-
returncmp_bounds(&info->flinfo,info->collid,&v1->min,&v2->min);
1320-
}
1321-
13221346

13231347
/*
13241348
* Common PartRelationInfo checks. Emit ERROR if anything is wrong.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp