PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
partition.h File Reference
#include "fmgr.h"
#include "executor/tuptable.h"
#include "nodes/execnodes.h"
#include "parser/parse_node.h"
#include "utils/rel.h"
Include dependency graph for partition.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PartitionDescData
 
struct  PartitionDispatchData
 

Typedefs

typedef struct
PartitionBoundInfoData
PartitionBoundInfo
 
typedef struct PartitionDescData PartitionDescData
 
typedef struct PartitionDescDataPartitionDesc
 
typedef struct
PartitionDispatchData 
PartitionDispatchData
 
typedef struct
PartitionDispatchData
PartitionDispatch
 

Functions

void RelationBuildPartitionDesc (Relation relation)
 
bool partition_bounds_equal (int partnatts, int16 *parttyplen, bool *parttypbyval, PartitionBoundInfo b1, PartitionBoundInfo b2)
 
PartitionBoundInfo partition_bounds_copy (PartitionBoundInfo src, PartitionKey key)
 
void check_new_partition_bound (char *relname, Relation parent, PartitionBoundSpec *spec)
 
Oid get_partition_parent (Oid relid)
 
Listget_qual_from_partbound (Relation rel, Relation parent, PartitionBoundSpec *spec)
 
Listmap_partition_varattnos (List *expr, int target_varno, Relation partrel, Relation parent, bool *found_whole_row)
 
ListRelationGetPartitionQual (Relation rel)
 
Exprget_partition_qual_relid (Oid relid)
 
PartitionDispatchRelationGetPartitionDispatchInfo (Relation rel, int *num_parted, List **leaf_part_oids)
 
void FormPartitionKeyDatum (PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
 
int get_partition_for_tuple (PartitionDispatch *pd, TupleTableSlot *slot, EState *estate, PartitionDispatchData **failed_at, TupleTableSlot **failed_slot)
 
Oid get_default_oid_from_partdesc (PartitionDesc partdesc)
 
Oid get_default_partition_oid (Oid parentId)
 
void update_default_partition_oid (Oid parentId, Oid defaultPartId)
 
void check_default_allows_bound (Relation parent, Relation defaultRel, PartitionBoundSpec *new_spec)
 
Listget_proposed_default_constraint (List *new_part_constaints)
 

Typedef Documentation

Definition at line 28 of file partition.h.

Definition at line 40 of file partition.h.

Definition at line 71 of file partition.h.

Function Documentation

void check_default_allows_bound ( Relation  parent,
Relation  defaultRel,
PartitionBoundSpec new_spec 
)

Definition at line 969 of file partition.c.

References AccessExclusiveLock, CHECK_FOR_INTERRUPTS, CreateExecutorState(), CreateTupleDescCopy(), ExprContext::ecxt_scantuple, ereport, errcode(), errmsg(), ERROR, ExecCheck(), ExecDropSingleTupleTableSlot(), ExecPrepareExpr(), ExecStoreTuple(), find_all_inheritors(), ForwardScanDirection, FreeExecutorState(), get_proposed_default_constraint(), get_qual_for_list(), get_qual_for_range(), GetLatestSnapshot(), GetPerTupleExprContext, GetPerTupleMemoryContext, heap_beginscan(), heap_close, heap_endscan(), heap_getnext(), heap_open(), INFO, InvalidBuffer, lfirst_oid, linitial, list_make1_oid, MakeSingleTupleTableSlot(), map_partition_varattnos(), MemoryContextSwitchTo(), NoLock, PartConstraintImpliedByRelConstraint(), PARTITION_STRATEGY_LIST, RelationData::rd_rel, RegisterSnapshot(), RelationGetDescr, RelationGetRelationName, RelationGetRelid, RELKIND_FOREIGN_TABLE, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, ResetExprContext, PartitionBoundSpec::strategy, UnregisterSnapshot(), and WARNING.

Referenced by DefineRelation().

971 {
972  List *new_part_constraints;
973  List *def_part_constraints;
974  List *all_parts;
975  ListCell *lc;
976 
977  new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
978  ? get_qual_for_list(parent, new_spec)
979  : get_qual_for_range(parent, new_spec, false);
980  def_part_constraints =
981  get_proposed_default_constraint(new_part_constraints);
982 
983  /*
984  * If the existing constraints on the default partition imply that it will
985  * not contain any row that would belong to the new partition, we can
986  * avoid scanning the default partition.
987  */
988  if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
989  {
990  ereport(INFO,
991  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
992  RelationGetRelationName(default_rel))));
993  return;
994  }
995 
996  /*
997  * Scan the default partition and its subpartitions, and check for rows
998  * that do not satisfy the revised partition constraints.
999  */
1000  if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1001  all_parts = find_all_inheritors(RelationGetRelid(default_rel),
1002  AccessExclusiveLock, NULL);
1003  else
1004  all_parts = list_make1_oid(RelationGetRelid(default_rel));
1005 
1006  foreach(lc, all_parts)
1007  {
1008  Oid part_relid = lfirst_oid(lc);
1009  Relation part_rel;
1010  Expr *constr;
1011  Expr *partition_constraint;
1012  EState *estate;
1013  HeapTuple tuple;
1014  ExprState *partqualstate = NULL;
1015  Snapshot snapshot;
1016  TupleDesc tupdesc;
1017  ExprContext *econtext;
1018  HeapScanDesc scan;
1019  MemoryContext oldCxt;
1020  TupleTableSlot *tupslot;
1021 
1022  /* Lock already taken above. */
1023  if (part_relid != RelationGetRelid(default_rel))
1024  {
1025  part_rel = heap_open(part_relid, NoLock);
1026 
1027  /*
1028  * If the partition constraints on default partition child imply
1029  * that it will not contain any row that would belong to the new
1030  * partition, we can avoid scanning the child table.
1031  */
1033  def_part_constraints))
1034  {
1035  ereport(INFO,
1036  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
1037  RelationGetRelationName(part_rel))));
1038 
1039  heap_close(part_rel, NoLock);
1040  continue;
1041  }
1042  }
1043  else
1044  part_rel = default_rel;
1045 
1046  /*
1047  * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
1048  * scanned.
1049  */
1050  if (part_rel->rd_rel->relkind != RELKIND_RELATION)
1051  {
1052  if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1053  ereport(WARNING,
1054  (errcode(ERRCODE_CHECK_VIOLATION),
1055  errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
1056  RelationGetRelationName(part_rel),
1057  RelationGetRelationName(default_rel))));
1058 
1059  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1060  heap_close(part_rel, NoLock);
1061 
1062  continue;
1063  }
1064 
1065  tupdesc = CreateTupleDescCopy(RelationGetDescr(part_rel));
1066  constr = linitial(def_part_constraints);
1067  partition_constraint = (Expr *)
1068  map_partition_varattnos((List *) constr,
1069  1, part_rel, parent, NULL);
1070  estate = CreateExecutorState();
1071 
1072  /* Build expression execution states for partition check quals */
1073  partqualstate = ExecPrepareExpr(partition_constraint, estate);
1074 
1075  econtext = GetPerTupleExprContext(estate);
1076  snapshot = RegisterSnapshot(GetLatestSnapshot());
1077  scan = heap_beginscan(part_rel, snapshot, 0, NULL);
1078  tupslot = MakeSingleTupleTableSlot(tupdesc);
1079 
1080  /*
1081  * Switch to per-tuple memory context and reset it for each tuple
1082  * produced, so we don't leak memory.
1083  */
1085 
1086  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1087  {
1088  ExecStoreTuple(tuple, tupslot, InvalidBuffer, false);
1089  econtext->ecxt_scantuple = tupslot;
1090 
1091  if (!ExecCheck(partqualstate, econtext))
1092  ereport(ERROR,
1093  (errcode(ERRCODE_CHECK_VIOLATION),
1094  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
1095  RelationGetRelationName(default_rel))));
1096 
1097  ResetExprContext(econtext);
1099  }
1100 
1101  MemoryContextSwitchTo(oldCxt);
1102  heap_endscan(scan);
1103  UnregisterSnapshot(snapshot);
1105  FreeExecutorState(estate);
1106 
1107  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1108  heap_close(part_rel, NoLock); /* keep the lock until commit */
1109  }
1110 }
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:102
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1565
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:863
#define RelationGetDescr(relation)
Definition: rel.h:428
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:575
#define INFO
Definition: elog.h:33
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:437
List * map_partition_varattnos(List *expr, int target_varno, Relation partrel, Relation parent, bool *found_whole_row)
Definition: partition.c:1207
void FreeExecutorState(EState *estate)
Definition: execUtils.c:183
#define GetPerTupleExprContext(estate)
Definition: executor.h:477
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partition.c:1554
#define NoLock
Definition: lockdefs.h:34
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:2876
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:216
#define RelationGetRelationName(relation)
Definition: rel.h:436
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc)
Definition: execTuples.c:199
#define ereport(elevel, rest)
Definition: elog.h:122
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partition.c:1869
EState * CreateExecutorState(void)
Definition: execUtils.c:80
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:905
#define WARNING
Definition: elog.h:40
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define list_make1_oid(x1)
Definition: pg_list.h:151
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1808
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:197
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:379
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:482
#define AccessExclusiveLock
Definition: lockdefs.h:45
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:167
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:544
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45
HeapScanDesc heap_beginscan(Relation relation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: heapam.c:1397
#define RelationGetRelid(relation)
Definition: rel.h:416
#define ResetExprContext(econtext)
Definition: executor.h:471
#define lfirst_oid(lc)
Definition: pg_list.h:108
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:13537
void check_new_partition_bound ( char *  relname,
Relation  parent,
PartitionBoundSpec spec 
)

Definition at line 779 of file partition.c.

References Assert, PartitionDescData::boundinfo, castNode, Const::constisnull, Const::constvalue, PartitionRangeBound::datums, PartitionBoundInfoData::default_index, elog, equal(), ereport, errcode(), errdetail(), errmsg(), ERROR, get_range_partbound_string(), get_rel_name(), PartitionBoundInfoData::indexes, PartitionBoundSpec::is_default, PartitionRangeBound::kind, lfirst, PartitionBoundSpec::listdatums, PartitionBoundSpec::location, lower(), PartitionBoundSpec::lowerdatums, make_one_range_bound(), make_parsestate(), PartitionBoundInfoData::ndatums, PartitionDescData::nparts, PartitionBoundInfoData::null_index, PartitionDescData::oids, parser_errposition(), partition_bound_accepts_nulls, partition_bound_bsearch(), partition_bound_cmp(), partition_bound_has_default, partition_rbound_cmp(), PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, RelationGetPartitionDesc, RelationGetPartitionKey, PartitionKeyData::strategy, PartitionBoundInfoData::strategy, PartitionBoundSpec::strategy, upper(), PartitionBoundSpec::upperdatums, and val.

Referenced by ATExecAttachPartition(), and DefineRelation().

781 {
783  PartitionDesc partdesc = RelationGetPartitionDesc(parent);
784  PartitionBoundInfo boundinfo = partdesc->boundinfo;
785  ParseState *pstate = make_parsestate(NULL);
786  int with = -1;
787  bool overlap = false;
788 
789  if (spec->is_default)
790  {
791  if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
792  return;
793 
794  /* Default partition already exists, error out. */
795  ereport(ERROR,
796  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
797  errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
798  relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
799  parser_errposition(pstate, spec->location)));
800  }
801 
802  switch (key->strategy)
803  {
805  {
807 
808  if (partdesc->nparts > 0)
809  {
810  ListCell *cell;
811 
812  Assert(boundinfo &&
813  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
814  (boundinfo->ndatums > 0 ||
815  partition_bound_accepts_nulls(boundinfo) ||
816  partition_bound_has_default(boundinfo)));
817 
818  foreach(cell, spec->listdatums)
819  {
820  Const *val = castNode(Const, lfirst(cell));
821 
822  if (!val->constisnull)
823  {
824  int offset;
825  bool equal;
826 
827  offset = partition_bound_bsearch(key, boundinfo,
828  &val->constvalue,
829  true, &equal);
830  if (offset >= 0 && equal)
831  {
832  overlap = true;
833  with = boundinfo->indexes[offset];
834  break;
835  }
836  }
837  else if (partition_bound_accepts_nulls(boundinfo))
838  {
839  overlap = true;
840  with = boundinfo->null_index;
841  break;
842  }
843  }
844  }
845 
846  break;
847  }
848 
850  {
852  *upper;
853 
855  lower = make_one_range_bound(key, -1, spec->lowerdatums, true);
856  upper = make_one_range_bound(key, -1, spec->upperdatums, false);
857 
858  /*
859  * First check if the resulting range would be empty with
860  * specified lower and upper bounds
861  */
862  if (partition_rbound_cmp(key, lower->datums, lower->kind, true,
863  upper) >= 0)
864  {
865  ereport(ERROR,
866  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
867  errmsg("empty range bound specified for partition \"%s\"",
868  relname),
869  errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
872  parser_errposition(pstate, spec->location)));
873  }
874 
875  if (partdesc->nparts > 0)
876  {
877  PartitionBoundInfo boundinfo = partdesc->boundinfo;
878  int offset;
879  bool equal;
880 
881  Assert(boundinfo &&
882  boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
883  (boundinfo->ndatums > 0 ||
884  partition_bound_has_default(boundinfo)));
885 
886  /*
887  * Test whether the new lower bound (which is treated
888  * inclusively as part of the new partition) lies inside
889  * an existing partition, or in a gap.
890  *
891  * If it's inside an existing partition, the bound at
892  * offset + 1 will be the upper bound of that partition,
893  * and its index will be >= 0.
894  *
895  * If it's in a gap, the bound at offset + 1 will be the
896  * lower bound of the next partition, and its index will
897  * be -1. This is also true if there is no next partition,
898  * since the index array is initialised with an extra -1
899  * at the end.
900  */
901  offset = partition_bound_bsearch(key, boundinfo, lower,
902  true, &equal);
903 
904  if (boundinfo->indexes[offset + 1] < 0)
905  {
906  /*
907  * Check that the new partition will fit in the gap.
908  * For it to fit, the new upper bound must be less
909  * than or equal to the lower bound of the next
910  * partition, if there is one.
911  */
912  if (offset + 1 < boundinfo->ndatums)
913  {
914  int32 cmpval;
915 
916  cmpval = partition_bound_cmp(key, boundinfo,
917  offset + 1, upper,
918  true);
919  if (cmpval < 0)
920  {
921  /*
922  * The new partition overlaps with the
923  * existing partition between offset + 1 and
924  * offset + 2.
925  */
926  overlap = true;
927  with = boundinfo->indexes[offset + 2];
928  }
929  }
930  }
931  else
932  {
933  /*
934  * The new partition overlaps with the existing
935  * partition between offset and offset + 1.
936  */
937  overlap = true;
938  with = boundinfo->indexes[offset + 1];
939  }
940  }
941 
942  break;
943  }
944 
945  default:
946  elog(ERROR, "unexpected partition strategy: %d",
947  (int) key->strategy);
948  }
949 
950  if (overlap)
951  {
952  Assert(with >= 0);
953  ereport(ERROR,
954  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
955  errmsg("partition \"%s\" would overlap partition \"%s\"",
956  relname, get_rel_name(partdesc->oids[with])),
957  parser_errposition(pstate, spec->location)));
958  }
959 }
Datum constvalue
Definition: primnodes.h:196
PartitionRangeDatumKind * kind
Definition: partition.c:110
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2972
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
#define castNode(_type_, nodeptr)
Definition: nodes.h:579
#define partition_bound_accepts_nulls(bi)
Definition: partition.c:90
int errcode(int sqlerrcode)
Definition: elog.c:575
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:74
char strategy
Definition: rel.h:54
signed int int32
Definition: c.h:246
PartitionBoundInfo boundinfo
Definition: partition.h:37
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
#define ERROR
Definition: elog.h:43
#define partition_bound_has_default(bi)
Definition: partition.c:91
static int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, void *probe, bool probe_is_bound, bool *is_equal)
Definition: partition.c:2766
static int32 partition_rbound_cmp(PartitionKey key, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partition.c:2615
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ereport(elevel, rest)
Definition: elog.h:122
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:10923
static PartitionRangeBound * make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
Definition: partition.c:2552
#define Assert(condition)
Definition: c.h:681
#define lfirst(lc)
Definition: pg_list.h:106
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
#define RelationGetPartitionKey(relation)
Definition: rel.h:584
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
long val
Definition: informix.c:689
static int32 partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo, int offset, void *probe, bool probe_is_bound)
Definition: partition.c:2705
bool constisnull
Definition: primnodes.h:197
#define RelationGetPartitionDesc(relation)
Definition: rel.h:632
void FormPartitionKeyDatum ( PartitionDispatch  pd,
TupleTableSlot slot,
EState estate,
Datum values,
bool isnull 
)

Definition at line 2300 of file partition.c.

References Assert, elog, ERROR, ExecEvalExprSwitchContext(), ExecPrepareExprList(), GetPerTupleExprContext, i, PartitionDispatchData::key, PartitionDispatchData::keystate, lfirst, list_head(), lnext, NIL, PartitionKeyData::partattrs, PartitionKeyData::partexprs, PartitionKeyData::partnatts, and slot_getattr().

Referenced by ExecFindPartition(), and get_partition_for_tuple().

2305 {
2306  ListCell *partexpr_item;
2307  int i;
2308 
2309  if (pd->key->partexprs != NIL && pd->keystate == NIL)
2310  {
2311  /* Check caller has set up context correctly */
2312  Assert(estate != NULL &&
2313  GetPerTupleExprContext(estate)->ecxt_scantuple == slot);
2314 
2315  /* First time through, set up expression evaluation state */
2316  pd->keystate = ExecPrepareExprList(pd->key->partexprs, estate);
2317  }
2318 
2319  partexpr_item = list_head(pd->keystate);
2320  for (i = 0; i < pd->key->partnatts; i++)
2321  {
2322  AttrNumber keycol = pd->key->partattrs[i];
2323  Datum datum;
2324  bool isNull;
2325 
2326  if (keycol != 0)
2327  {
2328  /* Plain column; get the value directly from the heap tuple */
2329  datum = slot_getattr(slot, keycol, &isNull);
2330  }
2331  else
2332  {
2333  /* Expression; need to evaluate it */
2334  if (partexpr_item == NULL)
2335  elog(ERROR, "wrong number of partition key expressions");
2336  datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
2337  GetPerTupleExprContext(estate),
2338  &isNull);
2339  partexpr_item = lnext(partexpr_item);
2340  }
2341  values[i] = datum;
2342  isnull[i] = isNull;
2343  }
2344 
2345  if (partexpr_item != NULL)
2346  elog(ERROR, "wrong number of partition key expressions");
2347 }
#define NIL
Definition: pg_list.h:69
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:301
List * partexprs
Definition: rel.h:58
#define GetPerTupleExprContext(estate)
Definition: executor.h:477
#define ERROR
Definition: elog.h:43
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:511
AttrNumber * partattrs
Definition: rel.h:56
uintptr_t Datum
Definition: postgres.h:372
int16 partnatts
Definition: rel.h:55
#define Assert(condition)
Definition: c.h:681
#define lfirst(lc)
Definition: pg_list.h:106
static Datum values[MAXATTR]
Definition: bootstrap.c:164
int i
Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: heaptuple.c:1142
#define elog
Definition: elog.h:219
int16 AttrNumber
Definition: attnum.h:21
PartitionKey key
Definition: partition.h:63
Oid get_default_oid_from_partdesc ( PartitionDesc  partdesc)

Definition at line 2804 of file partition.c.

References PartitionDescData::boundinfo, PartitionBoundInfoData::default_index, InvalidOid, PartitionDescData::oids, and partition_bound_has_default.

Referenced by ATExecAttachPartition(), ATExecDetachPartition(), DefineRelation(), and StorePartitionBound().

2805 {
2806  if (partdesc && partdesc->boundinfo &&
2808  return partdesc->oids[partdesc->boundinfo->default_index];
2809 
2810  return InvalidOid;
2811 }
PartitionBoundInfo boundinfo
Definition: partition.h:37
#define partition_bound_has_default(bi)
Definition: partition.c:91
#define InvalidOid
Definition: postgres_ext.h:36
Oid get_default_partition_oid ( Oid  parentId)

Definition at line 2821 of file partition.c.

References GETSTRUCT, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum, PARTRELID, ReleaseSysCache(), and SearchSysCache1().

Referenced by heap_drop_with_catalog(), and RelationBuildPartitionDesc().

2822 {
2823  HeapTuple tuple;
2824  Oid defaultPartId = InvalidOid;
2825 
2826  tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(parentId));
2827 
2828  if (HeapTupleIsValid(tuple))
2829  {
2830  Form_pg_partitioned_table part_table_form;
2831 
2832  part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
2833  defaultPartId = part_table_form->partdefid;
2834  }
2835 
2836  ReleaseSysCache(tuple);
2837  return defaultPartId;
2838 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
unsigned int Oid
Definition: postgres_ext.h:31
FormData_pg_partitioned_table * Form_pg_partitioned_table
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
int get_partition_for_tuple ( PartitionDispatch pd,
TupleTableSlot slot,
EState estate,
PartitionDispatchData **  failed_at,
TupleTableSlot **  failed_slot 
)

Definition at line 2359 of file partition.c.

References PartitionDescData::boundinfo, PartitionBoundInfoData::default_index, do_convert_tuple(), ExprContext::ecxt_scantuple, elog, equal(), ERROR, ExecClearTuple(), ExecFetchSlotTuple(), ExecStoreTuple(), FormPartitionKeyDatum(), GetPerTupleExprContext, i, PartitionDispatchData::indexes, PartitionBoundInfoData::indexes, InvalidBuffer, PartitionDispatchData::key, PartitionDescData::nparts, PartitionBoundInfoData::null_index, PartitionDispatchData::partdesc, partition_bound_accepts_nulls, partition_bound_bsearch(), partition_bound_has_default, PARTITION_MAX_KEYS, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partnatts, PartitionKeyData::strategy, PartitionDispatchData::tupmap, PartitionDispatchData::tupslot, and values.

Referenced by ExecFindPartition().

2364 {
2365  PartitionDispatch parent;
2367  bool isnull[PARTITION_MAX_KEYS];
2368  int result;
2369  ExprContext *ecxt = GetPerTupleExprContext(estate);
2370  TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
2371 
2372  /* start with the root partitioned table */
2373  parent = pd[0];
2374  while (true)
2375  {
2376  PartitionKey key = parent->key;
2377  PartitionDesc partdesc = parent->partdesc;
2378  TupleTableSlot *myslot = parent->tupslot;
2379  TupleConversionMap *map = parent->tupmap;
2380  int cur_index = -1;
2381 
2382  if (myslot != NULL && map != NULL)
2383  {
2384  HeapTuple tuple = ExecFetchSlotTuple(slot);
2385 
2386  ExecClearTuple(myslot);
2387  tuple = do_convert_tuple(tuple, map);
2388  ExecStoreTuple(tuple, myslot, InvalidBuffer, true);
2389  slot = myslot;
2390  }
2391 
2392  /* Quick exit */
2393  if (partdesc->nparts == 0)
2394  {
2395  *failed_at = parent;
2396  *failed_slot = slot;
2397  result = -1;
2398  goto error_exit;
2399  }
2400 
2401  /*
2402  * Extract partition key from tuple. Expression evaluation machinery
2403  * that FormPartitionKeyDatum() invokes expects ecxt_scantuple to
2404  * point to the correct tuple slot. The slot might have changed from
2405  * what was used for the parent table if the table of the current
2406  * partitioning level has different tuple descriptor from the parent.
2407  * So update ecxt_scantuple accordingly.
2408  */
2409  ecxt->ecxt_scantuple = slot;
2410  FormPartitionKeyDatum(parent, slot, estate, values, isnull);
2411 
2412  /* Route as appropriate based on partitioning strategy. */
2413  switch (key->strategy)
2414  {
2416 
2417  if (isnull[0])
2418  {
2420  cur_index = partdesc->boundinfo->null_index;
2421  }
2422  else
2423  {
2424  bool equal = false;
2425  int cur_offset;
2426 
2427  cur_offset = partition_bound_bsearch(key,
2428  partdesc->boundinfo,
2429  values,
2430  false,
2431  &equal);
2432  if (cur_offset >= 0 && equal)
2433  cur_index = partdesc->boundinfo->indexes[cur_offset];
2434  }
2435  break;
2436 
2438  {
2439  bool equal = false,
2440  range_partkey_has_null = false;
2441  int cur_offset;
2442  int i;
2443 
2444  /*
2445  * No range includes NULL, so this will be accepted by the
2446  * default partition if there is one, and otherwise
2447  * rejected.
2448  */
2449  for (i = 0; i < key->partnatts; i++)
2450  {
2451  if (isnull[i] &&
2453  {
2454  range_partkey_has_null = true;
2455  break;
2456  }
2457  else if (isnull[i])
2458  {
2459  *failed_at = parent;
2460  *failed_slot = slot;
2461  result = -1;
2462  goto error_exit;
2463  }
2464  }
2465 
2466  /*
2467  * No need to search for partition, as the null key will
2468  * be routed to the default partition.
2469  */
2470  if (range_partkey_has_null)
2471  break;
2472 
2473  cur_offset = partition_bound_bsearch(key,
2474  partdesc->boundinfo,
2475  values,
2476  false,
2477  &equal);
2478 
2479  /*
2480  * The offset returned is such that the bound at
2481  * cur_offset is less than or equal to the tuple value, so
2482  * the bound at offset+1 is the upper bound.
2483  */
2484  cur_index = partdesc->boundinfo->indexes[cur_offset + 1];
2485  }
2486  break;
2487 
2488  default:
2489  elog(ERROR, "unexpected partition strategy: %d",
2490  (int) key->strategy);
2491  }
2492 
2493  /*
2494  * cur_index < 0 means we failed to find a partition of this parent.
2495  * Use the default partition, if there is one.
2496  */
2497  if (cur_index < 0)
2498  cur_index = partdesc->boundinfo->default_index;
2499 
2500  /*
2501  * If cur_index is still less than 0 at this point, there's no
2502  * partition for this tuple. Otherwise, we either found the leaf
2503  * partition, or a child partitioned table through which we have to
2504  * route the tuple.
2505  */
2506  if (cur_index < 0)
2507  {
2508  result = -1;
2509  *failed_at = parent;
2510  *failed_slot = slot;
2511  break;
2512  }
2513  else if (parent->indexes[cur_index] >= 0)
2514  {
2515  result = parent->indexes[cur_index];
2516  break;
2517  }
2518  else
2519  parent = pd[-parent->indexes[cur_index]];
2520  }
2521 
2522 error_exit:
2523  ecxt->ecxt_scantuple = ecxt_scantuple_old;
2524  return result;
2525 }
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
PartitionDesc partdesc
Definition: partition.h:65
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2972
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
TupleConversionMap * tupmap
Definition: partition.h:67
#define InvalidBuffer
Definition: buf.h:25
#define partition_bound_accepts_nulls(bi)
Definition: partition.c:90
#define PARTITION_MAX_KEYS
char strategy
Definition: rel.h:54
PartitionBoundInfo boundinfo
Definition: partition.h:37
#define GetPerTupleExprContext(estate)
Definition: executor.h:477
#define ERROR
Definition: elog.h:43
#define partition_bound_has_default(bi)
Definition: partition.c:91
static int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, void *probe, bool probe_is_bound, bool *is_equal)
Definition: partition.c:2766
void FormPartitionKeyDatum(PartitionDispatch pd, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: partition.c:2300
uintptr_t Datum
Definition: postgres.h:372
int16 partnatts
Definition: rel.h:55
TupleTableSlot * tupslot
Definition: partition.h:66
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:197
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
HeapTuple do_convert_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:354
HeapTuple ExecFetchSlotTuple(TupleTableSlot *slot)
Definition: execTuples.c:618
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
int i
#define elog
Definition: elog.h:219
PartitionKey key
Definition: partition.h:63
Oid get_partition_parent ( Oid  relid)

Definition at line 1122 of file partition.c.

References AccessShareLock, Anum_pg_inherits_inhrelid, Anum_pg_inherits_inhseqno, BTEqualStrategyNumber, elog, ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, InheritsRelationId, InheritsRelidSeqnoIndexId, Int32GetDatum, ObjectIdGetDatum, ScanKeyInit(), systable_beginscan(), systable_endscan(), and systable_getnext().

Referenced by ATExecDropNotNull(), generate_partition_qual(), heap_drop_with_catalog(), and RangeVarCallbackForDropRelation().

1123 {
1124  Form_pg_inherits form;
1125  Relation catalogRelation;
1126  SysScanDesc scan;
1127  ScanKeyData key[2];
1128  HeapTuple tuple;
1129  Oid result;
1130 
1131  catalogRelation = heap_open(InheritsRelationId, AccessShareLock);
1132 
1133  ScanKeyInit(&key[0],
1135  BTEqualStrategyNumber, F_OIDEQ,
1136  ObjectIdGetDatum(relid));
1137  ScanKeyInit(&key[1],
1139  BTEqualStrategyNumber, F_INT4EQ,
1140  Int32GetDatum(1));
1141 
1142  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
1143  NULL, 2, key);
1144 
1145  tuple = systable_getnext(scan);
1146  if (!HeapTupleIsValid(tuple))
1147  elog(ERROR, "could not find tuple for parent of relation %u", relid);
1148 
1149  form = (Form_pg_inherits) GETSTRUCT(tuple);
1150  result = form->inhparent;
1151 
1152  systable_endscan(scan);
1153  heap_close(catalogRelation, AccessShareLock);
1154 
1155  return result;
1156 }
#define Anum_pg_inherits_inhrelid
Definition: pg_inherits.h:50
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define AccessShareLock
Definition: lockdefs.h:36
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define Anum_pg_inherits_inhseqno
Definition: pg_inherits.h:52
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define InheritsRelidSeqnoIndexId
Definition: indexing.h:167
FormData_pg_inherits * Form_pg_inherits
Definition: pg_inherits.h:43
#define InheritsRelationId
Definition: pg_inherits.h:29
#define Int32GetDatum(X)
Definition: postgres.h:485
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Expr* get_partition_qual_relid ( Oid  relid)

Definition at line 1257 of file partition.c.

References AccessShareLock, AND_EXPR, generate_partition_qual(), heap_close, heap_open(), linitial, list_length(), makeBoolExpr(), NIL, NoLock, and RelationData::rd_rel.

Referenced by pg_get_partition_constraintdef().

1258 {
1259  Relation rel = heap_open(relid, AccessShareLock);
1260  Expr *result = NULL;
1261  List *and_args;
1262 
1263  /* Do the work only if this relation is a partition. */
1264  if (rel->rd_rel->relispartition)
1265  {
1266  and_args = generate_partition_qual(rel);
1267 
1268  if (and_args == NIL)
1269  result = NULL;
1270  else if (list_length(and_args) > 1)
1271  result = makeBoolExpr(AND_EXPR, and_args, -1);
1272  else
1273  result = linitial(and_args);
1274  }
1275 
1276  /* Keep the lock. */
1277  heap_close(rel, NoLock);
1278 
1279  return result;
1280 }
#define NIL
Definition: pg_list.h:69
#define AccessShareLock
Definition: lockdefs.h:36
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:366
#define linitial(l)
Definition: pg_list.h:111
#define NoLock
Definition: lockdefs.h:34
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
static int list_length(const List *l)
Definition: pg_list.h:89
static List * generate_partition_qual(Relation rel)
Definition: partition.c:2213
Definition: pg_list.h:45
List* get_proposed_default_constraint ( List new_part_constaints)

Definition at line 2876 of file partition.c.

References canonicalize_qual(), eval_const_expressions(), list_make1, make_ands_explicit(), makeBoolExpr(), and NOT_EXPR.

Referenced by ATExecAttachPartition(), and check_default_allows_bound().

2877 {
2878  Expr *defPartConstraint;
2879 
2880  defPartConstraint = make_ands_explicit(new_part_constraints);
2881 
2882  /*
2883  * Derive the partition constraints of default partition by negating the
2884  * given partition constraints. The partition constraint never evaluates
2885  * to NULL, so negating it like this is safe.
2886  */
2887  defPartConstraint = makeBoolExpr(NOT_EXPR,
2888  list_make1(defPartConstraint),
2889  -1);
2890  defPartConstraint =
2891  (Expr *) eval_const_expressions(NULL,
2892  (Node *) defPartConstraint);
2893  defPartConstraint = canonicalize_qual(defPartConstraint);
2894 
2895  return list_make1(defPartConstraint);
2896 }
Definition: nodes.h:510
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2429
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:366
Expr * make_ands_explicit(List *andclauses)
Definition: clauses.c:367
#define list_make1(x1)
Definition: pg_list.h:139
Expr * canonicalize_qual(Expr *qual)
Definition: prepqual.c:286
List* get_qual_from_partbound ( Relation  rel,
Relation  parent,
PartitionBoundSpec spec 
)

Definition at line 1164 of file partition.c.

References Assert, elog, ERROR, get_qual_for_list(), get_qual_for_range(), NIL, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, RelationGetPartitionKey, PartitionKeyData::strategy, and PartitionBoundSpec::strategy.

Referenced by ATExecAttachPartition(), and generate_partition_qual().

1166 {
1167  PartitionKey key = RelationGetPartitionKey(parent);
1168  List *my_qual = NIL;
1169 
1170  Assert(key != NULL);
1171 
1172  switch (key->strategy)
1173  {
1176  my_qual = get_qual_for_list(parent, spec);
1177  break;
1178 
1181  my_qual = get_qual_for_range(parent, spec, false);
1182  break;
1183 
1184  default:
1185  elog(ERROR, "unexpected partition strategy: %d",
1186  (int) key->strategy);
1187  }
1188 
1189  return my_qual;
1190 }
#define NIL
Definition: pg_list.h:69
char strategy
Definition: rel.h:54
#define ERROR
Definition: elog.h:43
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partition.c:1554
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partition.c:1869
#define Assert(condition)
Definition: c.h:681
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
#define RelationGetPartitionKey(relation)
Definition: rel.h:584
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
List* map_partition_varattnos ( List expr,
int  target_varno,
Relation  partrel,
Relation  parent,
bool found_whole_row 
)

Definition at line 1207 of file partition.c.

References convert_tuples_by_name_map(), gettext_noop, map_variable_attnos(), NIL, RelationGetDescr, and RelationGetForm.

Referenced by ATExecAttachPartition(), check_default_allows_bound(), ExecInitModifyTable(), generate_partition_qual(), and ValidatePartitionConstraints().

1210 {
1211  bool my_found_whole_row = false;
1212 
1213  if (expr != NIL)
1214  {
1215  AttrNumber *part_attnos;
1216 
1217  part_attnos = convert_tuples_by_name_map(RelationGetDescr(partrel),
1218  RelationGetDescr(parent),
1219  gettext_noop("could not convert row type"));
1220  expr = (List *) map_variable_attnos((Node *) expr,
1221  target_varno, 0,
1222  part_attnos,
1223  RelationGetDescr(parent)->natts,
1224  RelationGetForm(partrel)->reltype,
1225  &my_found_whole_row);
1226  }
1227 
1228  if (found_whole_row)
1229  *found_whole_row = my_found_whole_row;
1230 
1231  return expr;
1232 }
#define NIL
Definition: pg_list.h:69
#define RelationGetDescr(relation)
Definition: rel.h:428
#define RelationGetForm(relation)
Definition: rel.h:410
#define gettext_noop(x)
Definition: c.h:139
Definition: nodes.h:510
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrNumber *attno_map, int map_length, Oid to_rowtype, bool *found_whole_row)
AttrNumber * convert_tuples_by_name_map(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:293
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
PartitionBoundInfo partition_bounds_copy ( PartitionBoundInfo  src,
PartitionKey  key 
)

Definition at line 709 of file partition.c.

References Assert, datumCopy(), PartitionBoundInfoData::datums, PartitionBoundInfoData::default_index, i, PartitionBoundInfoData::indexes, PartitionBoundInfoData::kind, PartitionBoundInfoData::ndatums, PartitionBoundInfoData::null_index, palloc(), PARTITION_RANGE_DATUM_VALUE, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partnatts, PartitionKeyData::parttypbyval, PartitionKeyData::parttyplen, PartitionKeyData::strategy, and PartitionBoundInfoData::strategy.

Referenced by set_relation_partition_info().

711 {
712  PartitionBoundInfo dest;
713  int i;
714  int ndatums;
715  int partnatts;
716  int num_indexes;
717 
719 
720  dest->strategy = src->strategy;
721  ndatums = dest->ndatums = src->ndatums;
722  partnatts = key->partnatts;
723 
724  /* Range partitioned table has an extra index. */
725  num_indexes = key->strategy == PARTITION_STRATEGY_RANGE ? ndatums + 1 : ndatums;
726 
727  /* List partitioned tables have only a single partition key. */
728  Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
729 
730  dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
731 
732  if (src->kind != NULL)
733  {
734  dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
735  sizeof(PartitionRangeDatumKind *));
736  for (i = 0; i < ndatums; i++)
737  {
738  dest->kind[i] = (PartitionRangeDatumKind *) palloc(partnatts *
739  sizeof(PartitionRangeDatumKind));
740 
741  memcpy(dest->kind[i], src->kind[i],
742  sizeof(PartitionRangeDatumKind) * key->partnatts);
743  }
744  }
745  else
746  dest->kind = NULL;
747 
748  for (i = 0; i < ndatums; i++)
749  {
750  int j;
751  dest->datums[i] = (Datum *) palloc(sizeof(Datum) * partnatts);
752 
753  for (j = 0; j < partnatts; j++)
754  {
755  if (dest->kind == NULL ||
756  dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
757  dest->datums[i][j] = datumCopy(src->datums[i][j],
758  key->parttypbyval[j],
759  key->parttyplen[j]);
760  }
761  }
762 
763  dest->indexes = (int *) palloc(sizeof(int) * num_indexes);
764  memcpy(dest->indexes, src->indexes, sizeof(int) * num_indexes);
765 
766  dest->null_index = src->null_index;
767  dest->default_index = src->default_index;
768 
769  return dest;
770 }
PartitionRangeDatumKind ** kind
Definition: partition.c:79
PartitionRangeDatumKind
Definition: parsenodes.h:817
char strategy
Definition: rel.h:54
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
uintptr_t Datum
Definition: postgres.h:372
int16 partnatts
Definition: rel.h:55
bool * parttypbyval
Definition: rel.h:72
struct PartitionBoundInfoData * PartitionBoundInfo
Definition: partition.h:28
#define Assert(condition)
Definition: c.h:681
int16 * parttyplen
Definition: rel.h:71
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
void * palloc(Size size)
Definition: mcxt.c:848
int i
bool partition_bounds_equal ( int  partnatts,
int16 parttyplen,
bool parttypbyval,
PartitionBoundInfo  b1,
PartitionBoundInfo  b2 
)

Definition at line 641 of file partition.c.

References datumIsEqual(), PartitionBoundInfoData::datums, PartitionBoundInfoData::default_index, i, PartitionBoundInfoData::indexes, PartitionBoundInfoData::kind, PartitionBoundInfoData::ndatums, PartitionBoundInfoData::null_index, PARTITION_RANGE_DATUM_VALUE, PARTITION_STRATEGY_RANGE, and PartitionBoundInfoData::strategy.

Referenced by build_joinrel_partition_info(), equalPartitionDescs(), and try_partition_wise_join().

643 {
644  int i;
645 
646  if (b1->strategy != b2->strategy)
647  return false;
648 
649  if (b1->ndatums != b2->ndatums)
650  return false;
651 
652  if (b1->null_index != b2->null_index)
653  return false;
654 
655  if (b1->default_index != b2->default_index)
656  return false;
657 
658  for (i = 0; i < b1->ndatums; i++)
659  {
660  int j;
661 
662  for (j = 0; j < partnatts; j++)
663  {
664  /* For range partitions, the bounds might not be finite. */
665  if (b1->kind != NULL)
666  {
667  /* The different kinds of bound all differ from each other */
668  if (b1->kind[i][j] != b2->kind[i][j])
669  return false;
670 
671  /* Non-finite bounds are equal without further examination. */
672  if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
673  continue;
674  }
675 
676  /*
677  * Compare the actual values. Note that it would be both incorrect
678  * and unsafe to invoke the comparison operator derived from the
679  * partitioning specification here. It would be incorrect because
680  * we want the relcache entry to be updated for ANY change to the
681  * partition bounds, not just those that the partitioning operator
682  * thinks are significant. It would be unsafe because we might
683  * reach this code in the context of an aborted transaction, and
684  * an arbitrary partitioning operator might not be safe in that
685  * context. datumIsEqual() should be simple enough to be safe.
686  */
687  if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
688  parttypbyval[j], parttyplen[j]))
689  return false;
690  }
691 
692  if (b1->indexes[i] != b2->indexes[i])
693  return false;
694  }
695 
696  /* There are ndatums+1 indexes in case of range partitions */
697  if (b1->strategy == PARTITION_STRATEGY_RANGE &&
698  b1->indexes[i] != b2->indexes[i])
699  return false;
700 
701  return true;
702 }
PartitionRangeDatumKind ** kind
Definition: partition.c:79
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:219
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
int i
void RelationBuildPartitionDesc ( Relation  relation)

Definition at line 161 of file partition.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), Anum_pg_class_relpartbound, Assert, PartitionDescData::boundinfo, CacheMemoryContext, castNode, Const::constisnull, Const::constvalue, cur, datumCopy(), DatumGetInt32, PartitionBoundInfoData::datums, PartitionRangeBound::datums, PartitionBoundInfoData::default_index, elog, ERROR, find_inheritance_children(), FunctionCall2Coll(), get_default_partition_oid(), GETSTRUCT, HeapTupleIsValid, i, PartitionListValue::index, PartitionRangeBound::index, PartitionBoundInfoData::indexes, PartitionBoundSpec::is_default, PartitionBoundInfoData::kind, PartitionRangeBound::kind, lappend(), lappend_oid(), lfirst, lfirst_oid, list_length(), PartitionBoundSpec::listdatums, lower(), PartitionBoundSpec::lowerdatums, make_one_range_bound(), MemoryContextSwitchTo(), PartitionBoundInfoData::ndatums, NIL, NoLock, PartitionDescData::nparts, PartitionBoundInfoData::null_index, PartitionDescData::oids, palloc(), palloc0(), PartitionKeyData::partcollation, PARTITION_RANGE_DATUM_VALUE, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partnatts, PartitionKeyData::partsupfunc, PartitionKeyData::parttypbyval, PartitionKeyData::parttyplen, pfree(), qsort_arg(), qsort_partition_list_value_cmp(), qsort_partition_rbound_cmp(), RelationData::rd_partdesc, RelationData::rd_pdcxt, RelationGetPartitionKey, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), RELOID, SearchSysCache1(), PartitionKeyData::strategy, PartitionBoundInfoData::strategy, PartitionBoundSpec::strategy, stringToNode(), SysCacheGetAttr(), TextDatumGetCString, upper(), PartitionBoundSpec::upperdatums, val, PartitionListValue::value, and value.

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

162 {
163  List *inhoids,
164  *partoids;
165  Oid *oids = NULL;
166  List *boundspecs = NIL;
167  ListCell *cell;
168  int i,
169  nparts;
171  PartitionDesc result;
172  MemoryContext oldcxt;
173 
174  int ndatums = 0;
175  int default_index = -1;
176 
177  /* List partitioning specific */
178  PartitionListValue **all_values = NULL;
179  int null_index = -1;
180 
181  /* Range partitioning specific */
182  PartitionRangeBound **rbounds = NULL;
183 
184  /*
185  * The following could happen in situations where rel has a pg_class entry
186  * but not the pg_partitioned_table entry yet.
187  */
188  if (key == NULL)
189  return;
190 
191  /* Get partition oids from pg_inherits */
193 
194  /* Collect bound spec nodes in a list */
195  i = 0;
196  partoids = NIL;
197  foreach(cell, inhoids)
198  {
199  Oid inhrelid = lfirst_oid(cell);
200  HeapTuple tuple;
201  Datum datum;
202  bool isnull;
203  Node *boundspec;
204 
205  tuple = SearchSysCache1(RELOID, inhrelid);
206  if (!HeapTupleIsValid(tuple))
207  elog(ERROR, "cache lookup failed for relation %u", inhrelid);
208 
209  /*
210  * It is possible that the pg_class tuple of a partition has not been
211  * updated yet to set its relpartbound field. The only case where
212  * this happens is when we open the parent relation to check using its
213  * partition descriptor that a new partition's bound does not overlap
214  * some existing partition.
215  */
216  if (!((Form_pg_class) GETSTRUCT(tuple))->relispartition)
217  {
218  ReleaseSysCache(tuple);
219  continue;
220  }
221 
222  datum = SysCacheGetAttr(RELOID, tuple,
224  &isnull);
225  Assert(!isnull);
226  boundspec = (Node *) stringToNode(TextDatumGetCString(datum));
227 
228  /*
229  * Sanity check: If the PartitionBoundSpec says this is the default
230  * partition, its OID should correspond to whatever's stored in
231  * pg_partitioned_table.partdefid; if not, the catalog is corrupt.
232  */
233  if (castNode(PartitionBoundSpec, boundspec)->is_default)
234  {
235  Oid partdefid;
236 
238  if (partdefid != inhrelid)
239  elog(ERROR, "expected partdefid %u, but got %u",
240  inhrelid, partdefid);
241  }
242 
243  boundspecs = lappend(boundspecs, boundspec);
244  partoids = lappend_oid(partoids, inhrelid);
245  ReleaseSysCache(tuple);
246  }
247 
248  nparts = list_length(partoids);
249 
250  if (nparts > 0)
251  {
252  oids = (Oid *) palloc(nparts * sizeof(Oid));
253  i = 0;
254  foreach(cell, partoids)
255  oids[i++] = lfirst_oid(cell);
256 
257  /* Convert from node to the internal representation */
258  if (key->strategy == PARTITION_STRATEGY_LIST)
259  {
260  List *non_null_values = NIL;
261 
262  /*
263  * Create a unified list of non-null values across all partitions.
264  */
265  i = 0;
266  null_index = -1;
267  foreach(cell, boundspecs)
268  {
270  lfirst(cell));
271  ListCell *c;
272 
273  if (spec->strategy != PARTITION_STRATEGY_LIST)
274  elog(ERROR, "invalid strategy in partition bound spec");
275 
276  /*
277  * Note the index of the partition bound spec for the default
278  * partition. There's no datum to add to the list of non-null
279  * datums for this partition.
280  */
281  if (spec->is_default)
282  {
283  default_index = i;
284  i++;
285  continue;
286  }
287 
288  foreach(c, spec->listdatums)
289  {
290  Const *val = castNode(Const, lfirst(c));
291  PartitionListValue *list_value = NULL;
292 
293  if (!val->constisnull)
294  {
295  list_value = (PartitionListValue *)
296  palloc0(sizeof(PartitionListValue));
297  list_value->index = i;
298  list_value->value = val->constvalue;
299  }
300  else
301  {
302  /*
303  * Never put a null into the values array, flag
304  * instead for the code further down below where we
305  * construct the actual relcache struct.
306  */
307  if (null_index != -1)
308  elog(ERROR, "found null more than once");
309  null_index = i;
310  }
311 
312  if (list_value)
313  non_null_values = lappend(non_null_values,
314  list_value);
315  }
316 
317  i++;
318  }
319 
320  ndatums = list_length(non_null_values);
321 
322  /*
323  * Collect all list values in one array. Alongside the value, we
324  * also save the index of partition the value comes from.
325  */
326  all_values = (PartitionListValue **) palloc(ndatums *
327  sizeof(PartitionListValue *));
328  i = 0;
329  foreach(cell, non_null_values)
330  {
331  PartitionListValue *src = lfirst(cell);
332 
333  all_values[i] = (PartitionListValue *)
334  palloc(sizeof(PartitionListValue));
335  all_values[i]->value = src->value;
336  all_values[i]->index = src->index;
337  i++;
338  }
339 
340  qsort_arg(all_values, ndatums, sizeof(PartitionListValue *),
341  qsort_partition_list_value_cmp, (void *) key);
342  }
343  else if (key->strategy == PARTITION_STRATEGY_RANGE)
344  {
345  int k;
346  PartitionRangeBound **all_bounds,
347  *prev;
348 
349  all_bounds = (PartitionRangeBound **) palloc0(2 * nparts *
350  sizeof(PartitionRangeBound *));
351 
352  /*
353  * Create a unified list of range bounds across all the
354  * partitions.
355  */
356  i = ndatums = 0;
357  foreach(cell, boundspecs)
358  {
360  lfirst(cell));
362  *upper;
363 
364  if (spec->strategy != PARTITION_STRATEGY_RANGE)
365  elog(ERROR, "invalid strategy in partition bound spec");
366 
367  /*
368  * Note the index of the partition bound spec for the default
369  * partition. There's no datum to add to the allbounds array
370  * for this partition.
371  */
372  if (spec->is_default)
373  {
374  default_index = i++;
375  continue;
376  }
377 
378  lower = make_one_range_bound(key, i, spec->lowerdatums,
379  true);
380  upper = make_one_range_bound(key, i, spec->upperdatums,
381  false);
382  all_bounds[ndatums++] = lower;
383  all_bounds[ndatums++] = upper;
384  i++;
385  }
386 
387  Assert(ndatums == nparts * 2 ||
388  (default_index != -1 && ndatums == (nparts - 1) * 2));
389 
390  /* Sort all the bounds in ascending order */
391  qsort_arg(all_bounds, ndatums,
392  sizeof(PartitionRangeBound *),
394  (void *) key);
395 
396  /* Save distinct bounds from all_bounds into rbounds. */
397  rbounds = (PartitionRangeBound **)
398  palloc(ndatums * sizeof(PartitionRangeBound *));
399  k = 0;
400  prev = NULL;
401  for (i = 0; i < ndatums; i++)
402  {
403  PartitionRangeBound *cur = all_bounds[i];
404  bool is_distinct = false;
405  int j;
406 
407  /* Is the current bound distinct from the previous one? */
408  for (j = 0; j < key->partnatts; j++)
409  {
410  Datum cmpval;
411 
412  if (prev == NULL || cur->kind[j] != prev->kind[j])
413  {
414  is_distinct = true;
415  break;
416  }
417 
418  /*
419  * If the bounds are both MINVALUE or MAXVALUE, stop now
420  * and treat them as equal, since any values after this
421  * point must be ignored.
422  */
423  if (cur->kind[j] != PARTITION_RANGE_DATUM_VALUE)
424  break;
425 
426  cmpval = FunctionCall2Coll(&key->partsupfunc[j],
427  key->partcollation[j],
428  cur->datums[j],
429  prev->datums[j]);
430  if (DatumGetInt32(cmpval) != 0)
431  {
432  is_distinct = true;
433  break;
434  }
435  }
436 
437  /*
438  * Only if the bound is distinct save it into a temporary
439  * array i.e. rbounds which is later copied into boundinfo
440  * datums array.
441  */
442  if (is_distinct)
443  rbounds[k++] = all_bounds[i];
444 
445  prev = cur;
446  }
447 
448  /* Update ndatums to hold the count of distinct datums. */
449  ndatums = k;
450  }
451  else
452  elog(ERROR, "unexpected partition strategy: %d",
453  (int) key->strategy);
454  }
455 
456  /* Now build the actual relcache partition descriptor */
460  oldcxt = MemoryContextSwitchTo(rel->rd_pdcxt);
461 
462  result = (PartitionDescData *) palloc0(sizeof(PartitionDescData));
463  result->nparts = nparts;
464  if (nparts > 0)
465  {
466  PartitionBoundInfo boundinfo;
467  int *mapping;
468  int next_index = 0;
469 
470  result->oids = (Oid *) palloc0(nparts * sizeof(Oid));
471 
472  boundinfo = (PartitionBoundInfoData *)
474  boundinfo->strategy = key->strategy;
475  boundinfo->default_index = -1;
476  boundinfo->ndatums = ndatums;
477  boundinfo->null_index = -1;
478  boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
479 
480  /* Initialize mapping array with invalid values */
481  mapping = (int *) palloc(sizeof(int) * nparts);
482  for (i = 0; i < nparts; i++)
483  mapping[i] = -1;
484 
485  switch (key->strategy)
486  {
488  {
489  boundinfo->indexes = (int *) palloc(ndatums * sizeof(int));
490 
491  /*
492  * Copy values. Indexes of individual values are mapped
493  * to canonical values so that they match for any two list
494  * partitioned tables with same number of partitions and
495  * same lists per partition. One way to canonicalize is
496  * to assign the index in all_values[] of the smallest
497  * value of each partition, as the index of all of the
498  * partition's values.
499  */
500  for (i = 0; i < ndatums; i++)
501  {
502  boundinfo->datums[i] = (Datum *) palloc(sizeof(Datum));
503  boundinfo->datums[i][0] = datumCopy(all_values[i]->value,
504  key->parttypbyval[0],
505  key->parttyplen[0]);
506 
507  /* If the old index has no mapping, assign one */
508  if (mapping[all_values[i]->index] == -1)
509  mapping[all_values[i]->index] = next_index++;
510 
511  boundinfo->indexes[i] = mapping[all_values[i]->index];
512  }
513 
514  /*
515  * If null-accepting partition has no mapped index yet,
516  * assign one. This could happen if such partition
517  * accepts only null and hence not covered in the above
518  * loop which only handled non-null values.
519  */
520  if (null_index != -1)
521  {
522  Assert(null_index >= 0);
523  if (mapping[null_index] == -1)
524  mapping[null_index] = next_index++;
525  boundinfo->null_index = mapping[null_index];
526  }
527 
528  /* Assign mapped index for the default partition. */
529  if (default_index != -1)
530  {
531  /*
532  * The default partition accepts any value not
533  * specified in the lists of other partitions, hence
534  * it should not get mapped index while assigning
535  * those for non-null datums.
536  */
537  Assert(default_index >= 0 &&
538  mapping[default_index] == -1);
539  mapping[default_index] = next_index++;
540  boundinfo->default_index = mapping[default_index];
541  }
542 
543  /* All partition must now have a valid mapping */
544  Assert(next_index == nparts);
545  break;
546  }
547 
549  {
550  boundinfo->kind = (PartitionRangeDatumKind **)
551  palloc(ndatums *
552  sizeof(PartitionRangeDatumKind *));
553  boundinfo->indexes = (int *) palloc((ndatums + 1) *
554  sizeof(int));
555 
556  for (i = 0; i < ndatums; i++)
557  {
558  int j;
559 
560  boundinfo->datums[i] = (Datum *) palloc(key->partnatts *
561  sizeof(Datum));
562  boundinfo->kind[i] = (PartitionRangeDatumKind *)
563  palloc(key->partnatts *
564  sizeof(PartitionRangeDatumKind));
565  for (j = 0; j < key->partnatts; j++)
566  {
567  if (rbounds[i]->kind[j] == PARTITION_RANGE_DATUM_VALUE)
568  boundinfo->datums[i][j] =
569  datumCopy(rbounds[i]->datums[j],
570  key->parttypbyval[j],
571  key->parttyplen[j]);
572  boundinfo->kind[i][j] = rbounds[i]->kind[j];
573  }
574 
575  /*
576  * There is no mapping for invalid indexes.
577  *
578  * Any lower bounds in the rbounds array have invalid
579  * indexes assigned, because the values between the
580  * previous bound (if there is one) and this (lower)
581  * bound are not part of the range of any existing
582  * partition.
583  */
584  if (rbounds[i]->lower)
585  boundinfo->indexes[i] = -1;
586  else
587  {
588  int orig_index = rbounds[i]->index;
589 
590  /* If the old index has no mapping, assign one */
591  if (mapping[orig_index] == -1)
592  mapping[orig_index] = next_index++;
593 
594  boundinfo->indexes[i] = mapping[orig_index];
595  }
596  }
597 
598  /* Assign mapped index for the default partition. */
599  if (default_index != -1)
600  {
601  Assert(default_index >= 0 && mapping[default_index] == -1);
602  mapping[default_index] = next_index++;
603  boundinfo->default_index = mapping[default_index];
604  }
605  boundinfo->indexes[i] = -1;
606  break;
607  }
608 
609  default:
610  elog(ERROR, "unexpected partition strategy: %d",
611  (int) key->strategy);
612  }
613 
614  result->boundinfo = boundinfo;
615 
616  /*
617  * Now assign OIDs from the original array into mapped indexes of the
618  * result array. Order of OIDs in the former is defined by the
619  * catalog scan that retrieved them, whereas that in the latter is
620  * defined by canonicalized representation of the list values or the
621  * range bounds.
622  */
623  for (i = 0; i < nparts; i++)
624  result->oids[mapping[i]] = oids[i];
625  pfree(mapping);
626  }
627 
628  MemoryContextSwitchTo(oldcxt);
629  rel->rd_partdesc = result;
630 }
Datum constvalue
Definition: primnodes.h:196
#define NIL
Definition: pg_list.h:69
void * stringToNode(char *str)
Definition: read.c:38
PartitionRangeDatumKind ** kind
Definition: partition.c:79
PartitionRangeDatumKind * kind
Definition: partition.c:110
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define DatumGetInt32(X)
Definition: postgres.h:478
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
FmgrInfo * partsupfunc
Definition: rel.h:63
#define castNode(_type_, nodeptr)
Definition: nodes.h:579
PartitionRangeDatumKind
Definition: parsenodes.h:817
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static int32 qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
Definition: partition.c:2592
Definition: nodes.h:510
struct cursor * cur
Definition: ecpg.c:28
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:74
char strategy
Definition: rel.h:54
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1042
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
PartitionBoundInfo boundinfo
Definition: partition.h:37
Definition: type.h:89
void pfree(void *pointer)
Definition: mcxt.c:949
#define ERROR
Definition: elog.h:43
static struct @121 value
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
static int32 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
Definition: partition.c:2533
char * c
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:436
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
Oid get_default_partition_oid(Oid parentId)
Definition: partition.c:2821
List * lappend(List *list, void *datum)
Definition: list.c:128
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
Definition: qsort_arg.c:113
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
Oid * partcollation
Definition: rel.h:66
#define TextDatumGetCString(d)
Definition: builtins.h:92
static PartitionRangeBound * make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
Definition: partition.c:2552
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:877
uintptr_t Datum
Definition: postgres.h:372
int16 partnatts
Definition: rel.h:55
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:57
#define Anum_pg_class_relpartbound
Definition: pg_class.h:135
bool * parttypbyval
Definition: rel.h:72
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:681
#define lfirst(lc)
Definition: pg_list.h:106
int16 * parttyplen
Definition: rel.h:71
static int list_length(const List *l)
Definition: pg_list.h:89
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:786
#define RelationGetPartitionKey(relation)
Definition: rel.h:584
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:787
void * palloc(Size size)
Definition: mcxt.c:848
int i
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:416
long val
Definition: informix.c:689
bool constisnull
Definition: primnodes.h:197
#define lfirst_oid(lc)
Definition: pg_list.h:108
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
PartitionDispatch* RelationGetPartitionDispatchInfo ( Relation  rel,
int *  num_parted,
List **  leaf_part_oids 
)

Definition at line 1295 of file partition.c.

References Assert, get_partition_dispatch_recurse(), i, lfirst, list_length(), NIL, palloc(), RelationData::rd_rel, and RELKIND_PARTITIONED_TABLE.

Referenced by ExecSetupPartitionTupleRouting().

1297 {
1298  List *pdlist = NIL;
1299  PartitionDispatchData **pd;
1300  ListCell *lc;
1301  int i;
1302 
1303  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
1304 
1305  *num_parted = 0;
1306  *leaf_part_oids = NIL;
1307 
1308  get_partition_dispatch_recurse(rel, NULL, &pdlist, leaf_part_oids);
1309  *num_parted = list_length(pdlist);
1310  pd = (PartitionDispatchData **) palloc(*num_parted *
1311  sizeof(PartitionDispatchData *));
1312  i = 0;
1313  foreach(lc, pdlist)
1314  {
1315  pd[i++] = lfirst(lc);
1316  }
1317 
1318  return pd;
1319 }
#define NIL
Definition: pg_list.h:69
Form_pg_class rd_rel
Definition: rel.h:114
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
static void get_partition_dispatch_recurse(Relation rel, Relation parent, List **pds, List **leaf_part_oids)
Definition: partition.c:1338
#define Assert(condition)
Definition: c.h:681
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
void * palloc(Size size)
Definition: mcxt.c:848
int i
Definition: pg_list.h:45
List* RelationGetPartitionQual ( Relation  rel)

Definition at line 1240 of file partition.c.

References generate_partition_qual(), NIL, and RelationData::rd_rel.

Referenced by ATExecAttachPartition(), get_relation_constraints(), and InitResultRelInfo().

1241 {
1242  /* Quick exit */
1243  if (!rel->rd_rel->relispartition)
1244  return NIL;
1245 
1246  return generate_partition_qual(rel);
1247 }
#define NIL
Definition: pg_list.h:69
Form_pg_class rd_rel
Definition: rel.h:114
static List * generate_partition_qual(Relation rel)
Definition: partition.c:2213
void update_default_partition_oid ( Oid  parentId,
Oid  defaultPartId 
)

Definition at line 2846 of file partition.c.

References CatalogTupleUpdate(), elog, ERROR, GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, ObjectIdGetDatum, PartitionedRelationId, PARTRELID, RowExclusiveLock, SearchSysCacheCopy1, and HeapTupleData::t_self.

Referenced by ATExecAttachPartition(), ATExecDetachPartition(), DefineRelation(), and heap_drop_with_catalog().

2847 {
2848  HeapTuple tuple;
2849  Relation pg_partitioned_table;
2850  Form_pg_partitioned_table part_table_form;
2851 
2852  pg_partitioned_table = heap_open(PartitionedRelationId, RowExclusiveLock);
2853 
2854  tuple = SearchSysCacheCopy1(PARTRELID, ObjectIdGetDatum(parentId));
2855 
2856  if (!HeapTupleIsValid(tuple))
2857  elog(ERROR, "cache lookup failed for partition key of relation %u",
2858  parentId);
2859 
2860  part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
2861  part_table_form->partdefid = defaultPartId;
2862  CatalogTupleUpdate(pg_partitioned_table, &tuple->t_self, tuple);
2863 
2864  heap_freetuple(tuple);
2865  heap_close(pg_partitioned_table, RowExclusiveLock);
2866 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
FormData_pg_partitioned_table * Form_pg_partitioned_table
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define PartitionedRelationId
#define RowExclusiveLock
Definition: lockdefs.h:38
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
#define elog
Definition: elog.h:219