Skip to content

Commit 4d8e430

Browse files
committed
refactoring, introduce create_partitions() (switch between backend\BGW), fixes
1 parent 57305e2 commit 4d8e430

File tree

9 files changed

+190
-131
lines changed

9 files changed

+190
-131
lines changed

range.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,8 @@ BEGIN
449449
EXECUTE v_sql;
450450
RETURN v_child_relname;
451451
END
452-
$$ LANGUAGE plpgsql;
452+
$$ LANGUAGE plpgsql
453+
SET client_min_messages = WARNING;
453454

454455
/*
455456
* Split RANGE partition

src/init.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "utils.h"
1919

2020
#include "access/htup_details.h"
21+
#include "access/sysattr.h"
2122
#include "catalog/indexing.h"
2223
#include "catalog/pg_inherits_fn.h"
2324
#include "catalog/pg_type.h"
@@ -368,7 +369,8 @@ build_check_constraint_name_internal(Oid relid, AttrNumber attno)
368369
* Extract tuple into 'values' and 'isnull' if they're provided.
369370
*/
370371
bool
371-
pathman_config_contains_relation(Oid relid, Datum *values, bool *isnull)
372+
pathman_config_contains_relation(Oid relid, Datum *values, bool *isnull,
373+
TransactionId *xmin)
372374
{
373375
Oid pathman_config;
374376
Relation rel;
@@ -404,6 +406,21 @@ pathman_config_contains_relation(Oid relid, Datum *values, bool *isnull)
404406
/* Extract data if necessary */
405407
if (values && isnull)
406408
heap_deformtuple(htup, RelationGetDescr(rel), values, isnull);
409+
410+
/* Set xmin if necessary */
411+
if (xmin)
412+
{
413+
Datum value;
414+
bool isnull;
415+
416+
value = heap_getsysattr(htup,
417+
MinTransactionIdAttributeNumber,
418+
RelationGetDescr(rel),
419+
&isnull);
420+
421+
Assert(!isnull);
422+
*xmin = DatumGetTransactionId(value);
423+
}
407424
}
408425

409426
/* Clean resources */

src/init.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ char *build_check_constraint_name_internal(Oid relid,
4242

4343
bool pathman_config_contains_relation(Oid relid,
4444
Datum *values,
45-
bool *isnull);
45+
bool *isnull,
46+
TransactionId *xmin);
4647

4748
#endif

src/partition_filter.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,13 @@ partition_filter_exec(CustomScanState *node)
184184
ranges = walk_expr_tree((Expr *) &state->temp_const, &state->wcxt)->rangeset;
185185
parts = get_partition_oids(ranges, &nparts, state->prel);
186186

187-
188187
if (nparts > 1)
189188
elog(ERROR, "PartitionFilter selected more than one partition");
190189
else if (nparts == 0)
191190
{
192-
selected_partid = create_partitions_bg_worker(state->partitioned_table,
193-
state->temp_const.constvalue,
194-
state->temp_const.consttype);
191+
selected_partid = create_partitions(state->partitioned_table,
192+
state->temp_const.constvalue,
193+
state->temp_const.consttype);
195194

196195
/* Now we have to refresh state->wcxt->ranges manually */
197196
refresh_walker_context_ranges(&state->wcxt);

src/pathman.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ typedef struct
194194
/* Check that WalkerContext contains ExprContext (plan execution stage) */
195195
#define WcxtHasExprContext(wcxt) ( (wcxt)->econtext )
196196

197+
Oid create_partitions_internal(Oid relid, Datum value, Oid value_type);
198+
Oid create_partitions(Oid relid, Datum value, Oid value_type);
199+
197200
void select_range_partitions(const Datum value,
198201
FmgrInfo *cmp_func,
199202
const RangeEntry *ranges,

src/pg_pathman.c

Lines changed: 126 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,33 +18,24 @@
1818
#include "runtime_merge_append.h"
1919

2020
#include "postgres.h"
21-
#include "fmgr.h"
21+
#include "access/heapam.h"
22+
#include "access/transam.h"
23+
#include "access/xact.h"
24+
#include "catalog/pg_type.h"
25+
#include "executor/spi.h"
2226
#include "miscadmin.h"
23-
#include "nodes/makefuncs.h"
24-
#include "nodes/nodeFuncs.h"
25-
#include "nodes/pg_list.h"
26-
#include "nodes/relation.h"
27-
#include "nodes/primnodes.h"
2827
#include "optimizer/clauses.h"
29-
#include "optimizer/paths.h"
30-
#include "optimizer/pathnode.h"
31-
#include "optimizer/planner.h"
3228
#include "optimizer/prep.h"
3329
#include "optimizer/restrictinfo.h"
3430
#include "optimizer/cost.h"
35-
#include "parser/analyze.h"
36-
#include "utils/hsearch.h"
3731
#include "utils/rel.h"
38-
#include "utils/elog.h"
39-
#include "utils/array.h"
4032
#include "utils/guc.h"
4133
#include "utils/lsyscache.h"
4234
#include "utils/selfuncs.h"
35+
#include "utils/snapmgr.h"
4336
#include "utils/memutils.h"
44-
#include "access/heapam.h"
45-
#include "storage/ipc.h"
46-
#include "catalog/pg_type.h"
4737
#include "foreign/fdwapi.h"
38+
#include "fmgr.h"
4839

4940

5041
PG_MODULE_MAGIC;
@@ -112,7 +103,7 @@ static Path *get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo
112103

113104

114105
/*
115-
* Entry point
106+
* Set initial values for all Postmaster's forks.
116107
*/
117108
void
118109
_PG_init(void)
@@ -161,8 +152,8 @@ _PG_init(void)
161152
}
162153

163154
/*
164-
* Disables inheritance for partitioned by pathman relations. It must be done to
165-
* prevent PostgresSQL from full search.
155+
* Disables inheritance for partitioned by pathman relations.
156+
* It must be done to prevent PostgresSQL from exhaustive search.
166157
*/
167158
void
168159
disable_inheritance(Query *parse)
@@ -171,7 +162,6 @@ disable_inheritance(Query *parse)
171162
RangeTblEntry *rte;
172163
PartRelationInfo *prel;
173164
MemoryContext oldcontext;
174-
bool found;
175165

176166
/* If query contains CTE (WITH statement) then handle subqueries too */
177167
disable_inheritance_cte(parse);
@@ -189,10 +179,12 @@ disable_inheritance(Query *parse)
189179
if (rte->inh)
190180
{
191181
/* Look up this relation in pathman relations */
192-
prel = get_pathman_relation_info(rte->relid, &found);
193-
if (prel != NULL && found)
182+
prel = get_pathman_relation_info(rte->relid, NULL);
183+
if (prel)
194184
{
185+
/* We'll set this flag later */
195186
rte->inh = false;
187+
196188
/*
197189
* Sometimes user uses the ONLY statement and in this case
198190
* rte->inh is also false. We should differ the case
@@ -754,6 +746,118 @@ finish_least_greatest(WrapperNode *wrap, WalkerContext *context)
754746
context->hasGreatest = false;
755747
}
756748

749+
/*
750+
* Append partitions (if needed) and return Oid of the partition to contain value.
751+
*
752+
* NB: This function should not be called directly, use create_partitions() instead.
753+
*/
754+
Oid
755+
create_partitions_internal(Oid relid, Datum value, Oid value_type)
756+
{
757+
int ret;
758+
char *sql;
759+
PartRelationInfo *prel;
760+
FmgrInfo cmp_func;
761+
MemoryContext old_mcxt = CurrentMemoryContext;
762+
Oid partid = InvalidOid; /* default value */
763+
764+
if ((prel = get_pathman_relation_info(relid, NULL)) == NULL)
765+
{
766+
elog(LOG, "Cannot fetch PartRelationInfo for relation %u [%u]",
767+
relid, MyProcPid);
768+
769+
return InvalidOid;
770+
}
771+
772+
if ((ret = SPI_connect()) < 0)
773+
{
774+
elog(LOG, "create_partitions_internal(): SPI_connect returned %d", ret);
775+
776+
return InvalidOid;
777+
}
778+
779+
/* Comparison function */
780+
fill_type_cmp_fmgr_info(&cmp_func, value_type, prel->atttype);
781+
782+
/* Perform PL procedure */
783+
sql = psprintf("SELECT %s.append_partitions_on_demand_internal($1, $2)",
784+
get_namespace_name(get_pathman_schema()));
785+
786+
PG_TRY();
787+
{
788+
Oid oids[] = { OIDOID, value_type };
789+
Datum vals[] = { ObjectIdGetDatum(relid), value };
790+
bool nulls[] = { false, false };
791+
bool isnull;
792+
793+
/* TODO: maybe this could be rewritten with FunctionCall */
794+
ret = SPI_execute_with_args(sql, 2, oids, vals, nulls, false, 0);
795+
if (ret == SPI_OK_SELECT)
796+
{
797+
TupleDesc tupdesc = SPI_tuptable->tupdesc;
798+
HeapTuple tuple = SPI_tuptable->vals[0];
799+
800+
Assert(SPI_processed == 1);
801+
802+
partid = DatumGetObjectId(SPI_getbinval(tuple, tupdesc, 1, &isnull));
803+
}
804+
}
805+
PG_CATCH();
806+
{
807+
ErrorData *edata;
808+
809+
MemoryContextSwitchTo(old_mcxt);
810+
edata = CopyErrorData();
811+
FlushErrorState();
812+
813+
elog(LOG, "create_partitions_internal(): %s [%u]",
814+
edata->message, MyProcPid);
815+
816+
FreeErrorData(edata);
817+
}
818+
PG_END_TRY();
819+
820+
SPI_finish();
821+
822+
return partid;
823+
}
824+
825+
/*
826+
* Create RANGE partitions (if needed) using either BGW or current backend.
827+
*
828+
* Returns Oid of the partition to store 'value'.
829+
*/
830+
Oid
831+
create_partitions(Oid relid, Datum value, Oid value_type)
832+
{
833+
TransactionId rel_xmin;
834+
835+
/* Check that table is partitioned and fetch xmin */
836+
if (pathman_config_contains_relation(relid, NULL, NULL, &rel_xmin))
837+
{
838+
/* If table was partitioned in some previous xact, run BGWorker */
839+
if (TransactionIdPrecedes(rel_xmin, GetCurrentTransactionId()))
840+
{
841+
elog(DEBUG2, "create_partitions(): chose BGW [%u]", MyProcPid);
842+
return create_partitions_bg_worker(relid, value, value_type);
843+
}
844+
/* Else it'd better for the current backend to create partitions */
845+
else
846+
{
847+
elog(DEBUG2, "create_partitions(): chose backend [%u]", MyProcPid);
848+
return create_partitions_internal(relid, value, value_type);
849+
}
850+
}
851+
else
852+
elog(ERROR, "Relation %u is not partitioned by pg_pathman", relid);
853+
854+
return InvalidOid; /* keep compiler happy */
855+
}
856+
857+
/*
858+
* Given RangeEntry array and 'value', return selected
859+
* RANGE partitions inside the WrapperNode.
860+
*/
757861
void
758862
select_range_partitions(const Datum value,
759863
FmgrInfo *cmp_func,

src/pl_funcs.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,7 @@ find_or_create_range_partition(PG_FUNCTION_ARGS)
152152
PG_RETURN_OID(found_rentry.child_oid);
153153
}
154154

155-
/* Start background worker to create new partitions */
156-
child_oid = create_partitions_bg_worker(relid, value, value_type);
155+
child_oid = create_partitions(relid, value, value_type);
157156

158157
LWLockRelease(pmstate->load_config_lock);
159158
LWLockRelease(pmstate->edit_partitions_lock);

src/relation_info.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ get_pathman_relation_info(Oid relid, bool *found)
183183
bool isnull[Natts_pathman_config];
184184

185185
/* Check that PATHMAN_CONFIG table contains this relation */
186-
if (pathman_config_contains_relation(relid, values, isnull))
186+
if (pathman_config_contains_relation(relid, values, isnull, NULL))
187187
{
188188
PartType part_type;
189189
const char *attname;
@@ -355,7 +355,7 @@ try_syscache_parent_search(Oid partition, PartParentSearch *status)
355355
parent = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhparent;
356356

357357
/* Check that PATHMAN_CONFIG contains this table */
358-
if (pathman_config_contains_relation(parent, NULL, NULL))
358+
if (pathman_config_contains_relation(parent, NULL, NULL, NULL))
359359
{
360360
/* We've found the entry, update status */
361361
if (status) *status = PPS_ENTRY_FOUND;

0 commit comments

Comments
 (0)