Skip to content

Commit bf826d2

Browse files
committed
Add partial support (creation) of expression based partitions
1 parent ceecae3 commit bf826d2

20 files changed

+693
-230
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ regression.out
1010
*.gcno
1111
*.gcov
1212
pg_pathman--*.sql
13+
tags
14+
cscope*

hash.sql

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ BEGIN
3535
PERFORM @extschema@.common_relation_checks(parent_relid, attribute);
3636

3737
/* Insert new entry to pathman config */
38-
INSERT INTO @extschema@.pathman_config (partrel, attname, parttype)
39-
VALUES (parent_relid, attribute, 1);
38+
PERFORM @extschema@.add_to_pathman_config(parent_relid, attribute);
4039

4140
/* Create partitions */
4241
PERFORM @extschema@.create_hash_partitions_internal(parent_relid,
@@ -48,13 +47,13 @@ BEGIN
4847
/* Notify backend about changes */
4948
PERFORM @extschema@.on_create_partitions(parent_relid);
5049

51-
/* Copy data */
50+
/* Copy data
5251
IF partition_data = true THEN
5352
PERFORM @extschema@.set_enable_parent(parent_relid, false);
5453
PERFORM @extschema@.partition_data(parent_relid);
5554
ELSE
5655
PERFORM @extschema@.set_enable_parent(parent_relid, true);
57-
END IF;
56+
END IF; */
5857

5958
RETURN partitions_count;
6059
END
@@ -299,14 +298,3 @@ LANGUAGE C STRICT;
299298
CREATE OR REPLACE FUNCTION @extschema@.get_hash_part_idx(INTEGER, INTEGER)
300299
RETURNS INTEGER AS 'pg_pathman', 'get_hash_part_idx'
301300
LANGUAGE C STRICT;
302-
303-
/*
304-
* Build hash condition for a CHECK CONSTRAINT
305-
*/
306-
CREATE OR REPLACE FUNCTION @extschema@.build_hash_condition(
307-
attribute_type REGTYPE,
308-
attribute TEXT,
309-
partitions_count INT4,
310-
partitions_index INT4)
311-
RETURNS TEXT AS 'pg_pathman', 'build_hash_condition'
312-
LANGUAGE C STRICT;

init.sql

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ LANGUAGE C;
3535
CREATE TABLE IF NOT EXISTS @extschema@.pathman_config (
3636
partrel REGCLASS NOT NULL PRIMARY KEY,
3737
attname TEXT NOT NULL,
38+
atttype OID NOT NULL,
3839
parttype INTEGER NOT NULL,
3940
range_interval TEXT,
4041

@@ -427,7 +428,7 @@ LANGUAGE plpgsql STRICT;
427428
*/
428429
CREATE OR REPLACE FUNCTION @extschema@.common_relation_checks(
429430
relation REGCLASS,
430-
p_attribute TEXT)
431+
expression TEXT)
431432
RETURNS BOOLEAN AS
432433
$$
433434
DECLARE
@@ -450,8 +451,8 @@ BEGIN
450451
RAISE EXCEPTION 'relation "%" has already been partitioned', relation;
451452
END IF;
452453

453-
IF @extschema@.is_attribute_nullable(relation, p_attribute) THEN
454-
RAISE EXCEPTION 'partitioning key "%" must be NOT NULL', p_attribute;
454+
IF NOT @extschema@.is_expression_suitable(relation, expression) THEN
455+
RAISE EXCEPTION 'partitioning expression "%" is not suitable', expression;
455456
END IF;
456457

457458
/* Check if there are foreign keys that reference the relation */
@@ -467,7 +468,7 @@ BEGIN
467468
RAISE EXCEPTION 'relation "%" is referenced from other relations', relation;
468469
END IF;
469470

470-
RETURN TRUE;
471+
RETURN FALSE;
471472
END
472473
$$
473474
LANGUAGE plpgsql;
@@ -796,6 +797,15 @@ CREATE OR REPLACE FUNCTION @extschema@.is_attribute_nullable(
796797
RETURNS BOOLEAN AS 'pg_pathman', 'is_attribute_nullable'
797798
LANGUAGE C STRICT;
798799

800+
/*
801+
* Checks if expression is suitable
802+
*/
803+
CREATE OR REPLACE FUNCTION @extschema@.is_expression_suitable(
804+
relid REGCLASS,
805+
expr TEXT)
806+
RETURNS BOOLEAN AS 'pg_pathman', 'is_expression_suitable'
807+
LANGUAGE C STRICT;
808+
799809
/*
800810
* Check if regclass is date or timestamp.
801811
*/

sql/pathman_basic.sql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ CREATE TABLE test.hash_rel (
1111
INSERT INTO test.hash_rel VALUES (1, 1);
1212
INSERT INTO test.hash_rel VALUES (2, 2);
1313
INSERT INTO test.hash_rel VALUES (3, 3);
14-
SELECT pathman.create_hash_partitions('test.hash_rel', 'value', 3);
14+
:gdb
15+
SELECT pg_sleep(10);
16+
SELECT pathman.create_hash_partitions('test.hash_rel', 'value + 1', 3);
1517
ALTER TABLE test.hash_rel ALTER COLUMN value SET NOT NULL;
1618
SELECT pathman.create_hash_partitions('test.hash_rel', 'value', 3, partition_data:=false);
1719
EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel;

src/hooks.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,11 @@ pathman_rel_pathlist_hook(PlannerInfo *root,
255255
int32 type_mod;
256256
TypeCacheEntry *tce;
257257

258-
/* Make Var from partition column */
259-
get_rte_attribute_type(rte, prel->attnum,
258+
/* Make Var from patition column */
259+
/* FIX: this */
260+
get_rte_attribute_type(rte, 0,
260261
&vartypeid, &type_mod, &varcollid);
261-
var = makeVar(rti, prel->attnum, vartypeid, type_mod, varcollid, 0);
262+
var = makeVar(rti, 0, vartypeid, type_mod, varcollid, 0);
262263
var->location = -1;
263264

264265
/* Determine operator type */

src/include/init.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ void unload_config(void);
132132

133133
void fill_prel_with_partitions(const Oid *partitions,
134134
const uint32 parts_count,
135-
const char *part_column_name,
136135
PartRelationInfo *prel);
137136

138137
/* Result of find_inheritance_children_array() */
@@ -149,11 +148,9 @@ find_children_status find_inheritance_children_array(Oid parentrelId,
149148
uint32 *children_size,
150149
Oid **children);
151150

152-
char *build_check_constraint_name_relid_internal(Oid relid,
153-
AttrNumber attno);
151+
char *build_check_constraint_name_relid_internal(Oid relid);
154152

155-
char *build_check_constraint_name_relname_internal(const char *relname,
156-
AttrNumber attno);
153+
char *build_check_constraint_name_relname_internal(const char *relname);
157154

158155
char *build_sequence_name_internal(Oid relid);
159156

src/include/partition_creation.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,24 @@ bool check_range_available(Oid parent_relid,
6666

6767
/* HASH constraints */
6868
Constraint * build_hash_check_constraint(Oid child_relid,
69-
char *attname,
69+
const char *expr,
7070
uint32 part_idx,
7171
uint32 part_count,
7272
Oid value_type);
7373

74-
Node * build_raw_hash_check_tree(char *attname,
74+
Node * build_raw_hash_check_tree(const char *base_expr,
7575
uint32 part_idx,
76-
uint32 part_count, Oid value_type);
76+
uint32 part_count,
77+
Oid relid,
78+
Oid value_type);
7779

7880
void drop_check_constraint(Oid relid, AttrNumber attnum);
7981

82+
/* expression parsing functions */
83+
Node *get_expression_node(Oid relid, const char *expr, bool analyze);
84+
Oid get_partition_expr_type(Oid relid, const char *expr);
85+
86+
8087

8188
/* Partitioning callback type */
8289
typedef enum

src/include/partition_filter.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
#endif
2626

2727

28-
#define ERR_PART_ATTR_NULL "partitioned column's value should not be NULL"
28+
#define ERR_PART_ATTR_NULL "partition expression's value should not be NULL"
29+
#define ERR_PART_ATTR_MULTIPLE_RESULTS \
30+
"partition expression's value should be single, not set"
2931
#define ERR_PART_ATTR_NO_PART "no suitable partition for key '%s'"
3032
#define ERR_PART_ATTR_MULTIPLE "PartitionFilter selected more than one partition"
3133

src/include/pathman.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "rangeset.h"
1717

1818
#include "postgres.h"
19+
#include "fmgr.h"
1920
#include "nodes/makefuncs.h"
2021
#include "nodes/primnodes.h"
2122
#include "nodes/execnodes.h"
@@ -43,11 +44,12 @@
4344
* Definitions for the "pathman_config" table.
4445
*/
4546
#define PATHMAN_CONFIG "pathman_config"
46-
#define Natts_pathman_config 4
47+
#define Natts_pathman_config 5
4748
#define Anum_pathman_config_partrel 1 /* partitioned relation (regclass) */
4849
#define Anum_pathman_config_attname 2 /* partitioned column (text) */
49-
#define Anum_pathman_config_parttype 3 /* partitioning type (1|2) */
50-
#define Anum_pathman_config_range_interval 4 /* interval for RANGE pt. (text) */
50+
#define Anum_pathman_config_atttype 3 /* partitioned atttype */
51+
#define Anum_pathman_config_parttype 4 /* partitioning type (1|2) */
52+
#define Anum_pathman_config_range_interval 5 /* interval for RANGE pt. (text) */
5153

5254
/* type modifier (typmod) for 'range_interval' */
5355
#define PATHMAN_CONFIG_interval_typmod -1

src/include/relation_info.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "postgres.h"
1616
#include "access/attnum.h"
1717
#include "fmgr.h"
18+
#include "nodes/nodes.h"
19+
#include "nodes/primnodes.h"
1820
#include "port/atomics.h"
1921
#include "storage/lock.h"
2022
#include "utils/datum.h"
@@ -126,9 +128,9 @@ typedef struct
126128
RangeEntry *ranges; /* per-partition range entry or NULL */
127129

128130
PartType parttype; /* partitioning type (HASH | RANGE) */
129-
AttrNumber attnum; /* partitioned column's index */
130-
Oid atttype; /* partitioned column's type */
131-
int32 atttypmod; /* partitioned column type modifier */
131+
Expr *expr;
132+
Oid atttype; /* expression type */
133+
int32 atttypmod; /* expression type modifier */
132134
bool attbyval; /* is partitioned column stored by value? */
133135
int16 attlen; /* length of the partitioned column's type */
134136
int attalign; /* alignment of the part column's type */
@@ -191,8 +193,8 @@ PrelLastChild(const PartRelationInfo *prel)
191193

192194

193195
const PartRelationInfo *refresh_pathman_relation_info(Oid relid,
194-
PartType partitioning_type,
195-
const char *part_column_name,
196+
Datum *values,
197+
bool *isnull,
196198
bool allow_incomplete);
197199
void invalidate_pathman_relation_info(Oid relid, bool *found);
198200
void remove_pathman_relation_info(Oid relid);

src/init.c

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ static void init_local_cache(void);
7171
static void fini_local_cache(void);
7272
static void read_pathman_config(void);
7373

74-
static Expr *get_partition_constraint_expr(Oid partition, AttrNumber part_attno);
74+
static Expr *get_partition_constraint_expr(Oid partition);
7575

7676
static int cmp_range_entries(const void *p1, const void *p2, void *arg);
7777

@@ -89,7 +89,6 @@ static bool validate_range_opexpr(const Expr *expr,
8989

9090
static bool validate_hash_constraint(const Expr *expr,
9191
const PartRelationInfo *prel,
92-
const AttrNumber part_attno,
9392
uint32 *part_hash);
9493

9594
static bool read_opexpr_const(const OpExpr *opexpr,
@@ -363,7 +362,6 @@ fini_local_cache(void)
363362
void
364363
fill_prel_with_partitions(const Oid *partitions,
365364
const uint32 parts_count,
366-
const char *part_column_name,
367365
PartRelationInfo *prel)
368366
{
369367
uint32 i;
@@ -378,18 +376,7 @@ fill_prel_with_partitions(const Oid *partitions,
378376

379377
for (i = 0; i < PrelChildrenCount(prel); i++)
380378
{
381-
AttrNumber part_attno;
382-
383-
/* NOTE: Partitions may have different TupleDescs */
384-
part_attno = get_attnum(partitions[i], part_column_name);
385-
386-
/* Raise ERROR if there's no such column */
387-
if (part_attno == InvalidAttrNumber)
388-
elog(ERROR, "partition \"%s\" has no column \"%s\"",
389-
get_rel_name_or_relid(partitions[i]),
390-
part_column_name);
391-
392-
con_expr = get_partition_constraint_expr(partitions[i], part_attno);
379+
con_expr = get_partition_constraint_expr(partitions[i]);
393380

394381
/* Perform a partitioning_type-dependent task */
395382
switch (prel->parttype)
@@ -398,7 +385,7 @@ fill_prel_with_partitions(const Oid *partitions,
398385
{
399386
uint32 hash; /* hash value < parts_count */
400387

401-
if (validate_hash_constraint(con_expr, prel, part_attno, &hash))
388+
if (validate_hash_constraint(con_expr, prel, &hash))
402389
prel->children[hash] = partitions[i];
403390
else
404391
{
@@ -416,7 +403,7 @@ fill_prel_with_partitions(const Oid *partitions,
416403
Datum lower, upper;
417404
bool lower_null, upper_null;
418405

419-
if (validate_range_constraint(con_expr, prel, part_attno,
406+
if (validate_range_constraint(con_expr, prel, 0,
420407
&lower, &upper,
421408
&lower_null, &upper_null))
422409
{
@@ -656,15 +643,15 @@ find_inheritance_children_array(Oid parentrelId,
656643
* These functions does not perform sanity checks at all.
657644
*/
658645
char *
659-
build_check_constraint_name_relid_internal(Oid relid, AttrNumber attno)
646+
build_check_constraint_name_relid_internal(Oid relid)
660647
{
661-
return build_check_constraint_name_relname_internal(get_rel_name(relid), attno);
648+
return build_check_constraint_name_relname_internal(get_rel_name(relid));
662649
}
663650

664651
char *
665-
build_check_constraint_name_relname_internal(const char *relname, AttrNumber attno)
652+
build_check_constraint_name_relname_internal(const char *relname)
666653
{
667-
return psprintf("pathman_%s_%u_check", relname, attno);
654+
return psprintf("pathman_%s_check", relname);
668655
}
669656

670657
/*
@@ -854,7 +841,10 @@ read_pathman_config(void)
854841
}
855842

856843
/* get_pathman_relation_info() will refresh this entry */
857-
invalidate_pathman_relation_info(relid, NULL);
844+
refresh_pathman_relation_info(relid,
845+
values,
846+
isnull,
847+
true); /* allow lazy prel loading */
858848
}
859849

860850
/* Clean resources */
@@ -869,7 +859,7 @@ read_pathman_config(void)
869859
* build_check_constraint_name_internal() is used to build conname.
870860
*/
871861
static Expr *
872-
get_partition_constraint_expr(Oid partition, AttrNumber part_attno)
862+
get_partition_constraint_expr(Oid partition)
873863
{
874864
Oid conid; /* constraint Oid */
875865
char *conname; /* constraint name */
@@ -878,7 +868,7 @@ get_partition_constraint_expr(Oid partition, AttrNumber part_attno)
878868
bool conbin_isnull;
879869
Expr *expr; /* expression tree for constraint */
880870

881-
conname = build_check_constraint_name_relid_internal(partition, part_attno);
871+
conname = build_check_constraint_name_relid_internal(partition);
882872
conid = get_relation_constraint_oid(partition, conname, true);
883873
if (conid == InvalidOid)
884874
{
@@ -1116,7 +1106,6 @@ read_opexpr_const(const OpExpr *opexpr,
11161106
static bool
11171107
validate_hash_constraint(const Expr *expr,
11181108
const PartRelationInfo *prel,
1119-
const AttrNumber part_attno,
11201109
uint32 *part_hash)
11211110
{
11221111
const TypeCacheEntry *tce;
@@ -1156,23 +1145,11 @@ validate_hash_constraint(const Expr *expr,
11561145
type_hash_proc_expr = (FuncExpr *) first;
11571146

11581147
/* Check that function is indeed TYPE_HASH_PROC */
1159-
if (type_hash_proc_expr->funcid != prel->hash_proc ||
1160-
!(IsA(linitial(type_hash_proc_expr->args), Var) ||
1161-
IsA(linitial(type_hash_proc_expr->args), RelabelType)))
1148+
if (type_hash_proc_expr->funcid != prel->hash_proc)
11621149
{
11631150
return false;
11641151
}
11651152

1166-
/* Extract argument into 'var' */
1167-
if (IsA(linitial(type_hash_proc_expr->args), RelabelType))
1168-
var = (Var *) ((RelabelType *) linitial(type_hash_proc_expr->args))->arg;
1169-
else
1170-
var = (Var *) linitial(type_hash_proc_expr->args);
1171-
1172-
/* Check that 'var' is the partitioning key attribute */
1173-
if (var->varoattno != part_attno)
1174-
return false;
1175-
11761153
/* Check that PARTITIONS_COUNT is equal to total amount of partitions */
11771154
if (DatumGetUInt32(((Const *) second)->constvalue) != PrelChildrenCount(prel))
11781155
return false;

0 commit comments

Comments
 (0)