PostgreSQL Source Code  git master
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
 

Macros

#define HASH_PARTITION_SEED   UINT64CONST(0x7A5B22367996DCFD)
 

Typedefs

typedef struct PartitionBoundInfoDataPartitionBoundInfo
 
typedef struct PartitionDescData PartitionDescData
 
typedef struct PartitionDescDataPartitionDesc
 

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)
 
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)
 
int get_partition_for_tuple (Relation relation, Datum *values, bool *isnull)
 

Macro Definition Documentation

◆ HASH_PARTITION_SEED

#define HASH_PARTITION_SEED   UINT64CONST(0x7A5B22367996DCFD)

Definition at line 23 of file partition.h.

Referenced by compute_hash_value(), and satisfies_hash_partition().

Typedef Documentation

◆ PartitionBoundInfo

Definition at line 31 of file partition.h.

◆ PartitionDesc

Definition at line 43 of file partition.h.

◆ PartitionDescData

Function Documentation

◆ check_default_allows_bound()

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

Definition at line 1219 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().

1221 {
1222  List *new_part_constraints;
1223  List *def_part_constraints;
1224  List *all_parts;
1225  ListCell *lc;
1226 
1227  new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
1228  ? get_qual_for_list(parent, new_spec)
1229  : get_qual_for_range(parent, new_spec, false);
1230  def_part_constraints =
1231  get_proposed_default_constraint(new_part_constraints);
1232 
1233  /*
1234  * If the existing constraints on the default partition imply that it will
1235  * not contain any row that would belong to the new partition, we can
1236  * avoid scanning the default partition.
1237  */
1238  if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
1239  {
1240  ereport(INFO,
1241  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
1242  RelationGetRelationName(default_rel))));
1243  return;
1244  }
1245 
1246  /*
1247  * Scan the default partition and its subpartitions, and check for rows
1248  * that do not satisfy the revised partition constraints.
1249  */
1250  if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1251  all_parts = find_all_inheritors(RelationGetRelid(default_rel),
1252  AccessExclusiveLock, NULL);
1253  else
1254  all_parts = list_make1_oid(RelationGetRelid(default_rel));
1255 
1256  foreach(lc, all_parts)
1257  {
1258  Oid part_relid = lfirst_oid(lc);
1259  Relation part_rel;
1260  Expr *constr;
1261  Expr *partition_constraint;
1262  EState *estate;
1263  HeapTuple tuple;
1264  ExprState *partqualstate = NULL;
1265  Snapshot snapshot;
1266  TupleDesc tupdesc;
1267  ExprContext *econtext;
1268  HeapScanDesc scan;
1269  MemoryContext oldCxt;
1270  TupleTableSlot *tupslot;
1271 
1272  /* Lock already taken above. */
1273  if (part_relid != RelationGetRelid(default_rel))
1274  {
1275  part_rel = heap_open(part_relid, NoLock);
1276 
1277  /*
1278  * If the partition constraints on default partition child imply
1279  * that it will not contain any row that would belong to the new
1280  * partition, we can avoid scanning the child table.
1281  */
1283  def_part_constraints))
1284  {
1285  ereport(INFO,
1286  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
1287  RelationGetRelationName(part_rel))));
1288 
1289  heap_close(part_rel, NoLock);
1290  continue;
1291  }
1292  }
1293  else
1294  part_rel = default_rel;
1295 
1296  /*
1297  * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
1298  * scanned.
1299  */
1300  if (part_rel->rd_rel->relkind != RELKIND_RELATION)
1301  {
1302  if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1303  ereport(WARNING,
1304  (errcode(ERRCODE_CHECK_VIOLATION),
1305  errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
1306  RelationGetRelationName(part_rel),
1307  RelationGetRelationName(default_rel))));
1308 
1309  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1310  heap_close(part_rel, NoLock);
1311 
1312  continue;
1313  }
1314 
1315  tupdesc = CreateTupleDescCopy(RelationGetDescr(part_rel));
1316  constr = linitial(def_part_constraints);
1317  partition_constraint = (Expr *)
1318  map_partition_varattnos((List *) constr,
1319  1, part_rel, parent, NULL);
1320  estate = CreateExecutorState();
1321 
1322  /* Build expression execution states for partition check quals */
1323  partqualstate = ExecPrepareExpr(partition_constraint, estate);
1324 
1325  econtext = GetPerTupleExprContext(estate);
1326  snapshot = RegisterSnapshot(GetLatestSnapshot());
1327  scan = heap_beginscan(part_rel, snapshot, 0, NULL);
1328  tupslot = MakeSingleTupleTableSlot(tupdesc);
1329 
1330  /*
1331  * Switch to per-tuple memory context and reset it for each tuple
1332  * produced, so we don't leak memory.
1333  */
1335 
1336  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1337  {
1338  ExecStoreTuple(tuple, tupslot, InvalidBuffer, false);
1339  econtext->ecxt_scantuple = tupslot;
1340 
1341  if (!ExecCheck(partqualstate, econtext))
1342  ereport(ERROR,
1343  (errcode(ERRCODE_CHECK_VIOLATION),
1344  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
1345  RelationGetRelationName(default_rel))));
1346 
1347  ResetExprContext(econtext);
1349  }
1350 
1351  MemoryContextSwitchTo(oldCxt);
1352  heap_endscan(scan);
1353  UnregisterSnapshot(snapshot);
1355  FreeExecutorState(estate);
1356 
1357  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1358  heap_close(part_rel, NoLock); /* keep the lock until commit */
1359  }
1360 }
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:437
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:1462
void FreeExecutorState(EState *estate)
Definition: execUtils.c:186
#define GetPerTupleExprContext(estate)
Definition: executor.h:468
#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:1753
#define NoLock
Definition: lockdefs.h:34
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:2991
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:216
#define RelationGetRelationName(relation)
Definition: rel.h:445
#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:2068
EState * CreateExecutorState(void)
Definition: execUtils.c:81
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:198
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:788
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:379
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:473
#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:425
#define ResetExprContext(econtext)
Definition: executor.h:462
#define lfirst_oid(lc)
Definition: pg_list.h:108
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:13628

◆ check_new_partition_bound()

void check_new_partition_bound ( char *  relname,
Relation  parent,
PartitionBoundSpec spec 
)

Definition at line 946 of file partition.c.

References Assert, PartitionDescData::boundinfo, castNode, Const::constisnull, Const::constvalue, DatumGetInt32, PartitionBoundInfoData::datums, PartitionRangeBound::datums, PartitionBoundInfoData::default_index, elog, equal(), ereport, errcode(), errdetail(), errmsg(), ERROR, get_greatest_modulus(), 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(), PartitionBoundSpec::modulus, 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_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, RelationGetPartitionDesc, RelationGetPartitionKey, PartitionBoundSpec::remainder, PartitionKeyData::strategy, PartitionBoundInfoData::strategy, PartitionBoundSpec::strategy, upper(), PartitionBoundSpec::upperdatums, and val.

Referenced by ATExecAttachPartition(), and DefineRelation().

948 {
950  PartitionDesc partdesc = RelationGetPartitionDesc(parent);
951  PartitionBoundInfo boundinfo = partdesc->boundinfo;
952  ParseState *pstate = make_parsestate(NULL);
953  int with = -1;
954  bool overlap = false;
955 
956  if (spec->is_default)
957  {
958  if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
959  return;
960 
961  /* Default partition already exists, error out. */
962  ereport(ERROR,
963  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
964  errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
965  relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
966  parser_errposition(pstate, spec->location)));
967  }
968 
969  switch (key->strategy)
970  {
972  {
974  Assert(spec->remainder >= 0 && spec->remainder < spec->modulus);
975 
976  if (partdesc->nparts > 0)
977  {
978  PartitionBoundInfo boundinfo = partdesc->boundinfo;
979  Datum **datums = boundinfo->datums;
980  int ndatums = boundinfo->ndatums;
981  int greatest_modulus;
982  int remainder;
983  int offset;
984  bool equal,
985  valid_modulus = true;
986  int prev_modulus, /* Previous largest modulus */
987  next_modulus; /* Next largest modulus */
988 
989  /*
990  * Check rule that every modulus must be a factor of the
991  * next larger modulus. For example, if you have a bunch
992  * of partitions that all have modulus 5, you can add a
993  * new partition with modulus 10 or a new partition with
994  * modulus 15, but you cannot add both a partition with
995  * modulus 10 and a partition with modulus 15, because 10
996  * is not a factor of 15.
997  *
998  * Get greatest bound in array boundinfo->datums which is
999  * less than or equal to spec->modulus and
1000  * spec->remainder.
1001  */
1002  offset = partition_bound_bsearch(key, boundinfo, spec,
1003  true, &equal);
1004  if (offset < 0)
1005  {
1006  next_modulus = DatumGetInt32(datums[0][0]);
1007  valid_modulus = (next_modulus % spec->modulus) == 0;
1008  }
1009  else
1010  {
1011  prev_modulus = DatumGetInt32(datums[offset][0]);
1012  valid_modulus = (spec->modulus % prev_modulus) == 0;
1013 
1014  if (valid_modulus && (offset + 1) < ndatums)
1015  {
1016  next_modulus = DatumGetInt32(datums[offset + 1][0]);
1017  valid_modulus = (next_modulus % spec->modulus) == 0;
1018  }
1019  }
1020 
1021  if (!valid_modulus)
1022  ereport(ERROR,
1023  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1024  errmsg("every hash partition modulus must be a factor of the next larger modulus")));
1025 
1026  greatest_modulus = get_greatest_modulus(boundinfo);
1027  remainder = spec->remainder;
1028 
1029  /*
1030  * Normally, the lowest remainder that could conflict with
1031  * the new partition is equal to the remainder specified
1032  * for the new partition, but when the new partition has a
1033  * modulus higher than any used so far, we need to adjust.
1034  */
1035  if (remainder >= greatest_modulus)
1036  remainder = remainder % greatest_modulus;
1037 
1038  /* Check every potentially-conflicting remainder. */
1039  do
1040  {
1041  if (boundinfo->indexes[remainder] != -1)
1042  {
1043  overlap = true;
1044  with = boundinfo->indexes[remainder];
1045  break;
1046  }
1047  remainder += spec->modulus;
1048  } while (remainder < greatest_modulus);
1049  }
1050 
1051  break;
1052  }
1053 
1055  {
1057 
1058  if (partdesc->nparts > 0)
1059  {
1060  ListCell *cell;
1061 
1062  Assert(boundinfo &&
1063  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
1064  (boundinfo->ndatums > 0 ||
1065  partition_bound_accepts_nulls(boundinfo) ||
1066  partition_bound_has_default(boundinfo)));
1067 
1068  foreach(cell, spec->listdatums)
1069  {
1070  Const *val = castNode(Const, lfirst(cell));
1071 
1072  if (!val->constisnull)
1073  {
1074  int offset;
1075  bool equal;
1076 
1077  offset = partition_bound_bsearch(key, boundinfo,
1078  &val->constvalue,
1079  true, &equal);
1080  if (offset >= 0 && equal)
1081  {
1082  overlap = true;
1083  with = boundinfo->indexes[offset];
1084  break;
1085  }
1086  }
1087  else if (partition_bound_accepts_nulls(boundinfo))
1088  {
1089  overlap = true;
1090  with = boundinfo->null_index;
1091  break;
1092  }
1093  }
1094  }
1095 
1096  break;
1097  }
1098 
1100  {
1102  *upper;
1103 
1105  lower = make_one_range_bound(key, -1, spec->lowerdatums, true);
1106  upper = make_one_range_bound(key, -1, spec->upperdatums, false);
1107 
1108  /*
1109  * First check if the resulting range would be empty with
1110  * specified lower and upper bounds
1111  */
1112  if (partition_rbound_cmp(key, lower->datums, lower->kind, true,
1113  upper) >= 0)
1114  {
1115  ereport(ERROR,
1116  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1117  errmsg("empty range bound specified for partition \"%s\"",
1118  relname),
1119  errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
1122  parser_errposition(pstate, spec->location)));
1123  }
1124 
1125  if (partdesc->nparts > 0)
1126  {
1127  PartitionBoundInfo boundinfo = partdesc->boundinfo;
1128  int offset;
1129  bool equal;
1130 
1131  Assert(boundinfo &&
1132  boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
1133  (boundinfo->ndatums > 0 ||
1134  partition_bound_has_default(boundinfo)));
1135 
1136  /*
1137  * Test whether the new lower bound (which is treated
1138  * inclusively as part of the new partition) lies inside
1139  * an existing partition, or in a gap.
1140  *
1141  * If it's inside an existing partition, the bound at
1142  * offset + 1 will be the upper bound of that partition,
1143  * and its index will be >= 0.
1144  *
1145  * If it's in a gap, the bound at offset + 1 will be the
1146  * lower bound of the next partition, and its index will
1147  * be -1. This is also true if there is no next partition,
1148  * since the index array is initialised with an extra -1
1149  * at the end.
1150  */
1151  offset = partition_bound_bsearch(key, boundinfo, lower,
1152  true, &equal);
1153 
1154  if (boundinfo->indexes[offset + 1] < 0)
1155  {
1156  /*
1157  * Check that the new partition will fit in the gap.
1158  * For it to fit, the new upper bound must be less
1159  * than or equal to the lower bound of the next
1160  * partition, if there is one.
1161  */
1162  if (offset + 1 < boundinfo->ndatums)
1163  {
1164  int32 cmpval;
1165 
1166  cmpval = partition_bound_cmp(key, boundinfo,
1167  offset + 1, upper,
1168  true);
1169  if (cmpval < 0)
1170  {
1171  /*
1172  * The new partition overlaps with the
1173  * existing partition between offset + 1 and
1174  * offset + 2.
1175  */
1176  overlap = true;
1177  with = boundinfo->indexes[offset + 2];
1178  }
1179  }
1180  }
1181  else
1182  {
1183  /*
1184  * The new partition overlaps with the existing
1185  * partition between offset and offset + 1.
1186  */
1187  overlap = true;
1188  with = boundinfo->indexes[offset + 1];
1189  }
1190  }
1191 
1192  break;
1193  }
1194 
1195  default:
1196  elog(ERROR, "unexpected partition strategy: %d",
1197  (int) key->strategy);
1198  }
1199 
1200  if (overlap)
1201  {
1202  Assert(with >= 0);
1203  ereport(ERROR,
1204  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1205  errmsg("partition \"%s\" would overlap partition \"%s\"",
1206  relname, get_rel_name(partdesc->oids[with])),
1207  parser_errposition(pstate, spec->location)));
1208  }
1209 }
Datum constvalue
Definition: primnodes.h:196
PartitionRangeDatumKind * kind
Definition: partition.c:137
#define DatumGetInt32(X)
Definition: postgres.h:478
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2984
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:44
static int get_greatest_modulus(PartitionBoundInfo b)
Definition: partition.c:3061
#define castNode(_type_, nodeptr)
Definition: nodes.h:581
#define partition_bound_accepts_nulls(bi)
Definition: partition.c:109
int errcode(int sqlerrcode)
Definition: elog.c:575
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:75
char strategy
Definition: rel.h:54
signed int int32
Definition: c.h:294
PartitionBoundInfo boundinfo
Definition: partition.h:40
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:110
static int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, void *probe, bool probe_is_bound, bool *is_equal)
Definition: partition.c:2881
static int32 partition_rbound_cmp(PartitionKey key, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partition.c:2721
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:10981
static PartitionRangeBound * make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
Definition: partition.c:2658
uintptr_t Datum
Definition: postgres.h:372
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:787
#define Assert(condition)
Definition: c.h:680
#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:788
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:789
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1745
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:2811
bool constisnull
Definition: primnodes.h:197
#define RelationGetPartitionDesc(relation)
Definition: rel.h:641

◆ get_default_oid_from_partdesc()

Oid get_default_oid_from_partdesc ( PartitionDesc  partdesc)

Definition at line 2919 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().

2920 {
2921  if (partdesc && partdesc->boundinfo &&
2923  return partdesc->oids[partdesc->boundinfo->default_index];
2924 
2925  return InvalidOid;
2926 }
PartitionBoundInfo boundinfo
Definition: partition.h:40
#define partition_bound_has_default(bi)
Definition: partition.c:110
#define InvalidOid
Definition: postgres_ext.h:36

◆ get_default_partition_oid()

Oid get_default_partition_oid ( Oid  parentId)

Definition at line 2936 of file partition.c.

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

Referenced by heap_drop_with_catalog(), and RelationBuildPartitionDesc().

2937 {
2938  HeapTuple tuple;
2939  Oid defaultPartId = InvalidOid;
2940 
2941  tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(parentId));
2942 
2943  if (HeapTupleIsValid(tuple))
2944  {
2945  Form_pg_partitioned_table part_table_form;
2946 
2947  part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
2948  defaultPartId = part_table_form->partdefid;
2949  ReleaseSysCache(tuple);
2950  }
2951 
2952  return defaultPartId;
2953 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
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

◆ get_partition_for_tuple()

int get_partition_for_tuple ( Relation  relation,
Datum values,
bool isnull 
)

Definition at line 2508 of file partition.c.

References PartitionDescData::boundinfo, compute_hash_value(), PartitionBoundInfoData::default_index, elog, equal(), ERROR, get_greatest_modulus(), i, PartitionBoundInfoData::indexes, PartitionBoundInfoData::null_index, partition_bound_accepts_nulls, partition_bound_bsearch(), PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partnatts, RelationGetPartitionDesc, RelationGetPartitionKey, and PartitionKeyData::strategy.

Referenced by ExecFindPartition().

2509 {
2510  int bound_offset;
2511  int part_index = -1;
2512  PartitionKey key = RelationGetPartitionKey(relation);
2513  PartitionDesc partdesc = RelationGetPartitionDesc(relation);
2514 
2515  /* Route as appropriate based on partitioning strategy. */
2516  switch (key->strategy)
2517  {
2519  {
2520  PartitionBoundInfo boundinfo = partdesc->boundinfo;
2521  int greatest_modulus = get_greatest_modulus(boundinfo);
2522  uint64 rowHash = compute_hash_value(key, values, isnull);
2523 
2524  part_index = boundinfo->indexes[rowHash % greatest_modulus];
2525  }
2526  break;
2527 
2529  if (isnull[0])
2530  {
2532  part_index = partdesc->boundinfo->null_index;
2533  }
2534  else
2535  {
2536  bool equal = false;
2537 
2538  bound_offset = partition_bound_bsearch(key,
2539  partdesc->boundinfo,
2540  values,
2541  false,
2542  &equal);
2543  if (bound_offset >= 0 && equal)
2544  part_index = partdesc->boundinfo->indexes[bound_offset];
2545  }
2546  break;
2547 
2549  {
2550  bool equal = false,
2551  range_partkey_has_null = false;
2552  int i;
2553 
2554  /*
2555  * No range includes NULL, so this will be accepted by the
2556  * default partition if there is one, and otherwise rejected.
2557  */
2558  for (i = 0; i < key->partnatts; i++)
2559  {
2560  if (isnull[i])
2561  {
2562  range_partkey_has_null = true;
2563  break;
2564  }
2565  }
2566 
2567  if (!range_partkey_has_null)
2568  {
2569  bound_offset = partition_bound_bsearch(key,
2570  partdesc->boundinfo,
2571  values,
2572  false,
2573  &equal);
2574 
2575  /*
2576  * The bound at bound_offset is less than or equal to the
2577  * tuple value, so the bound at offset+1 is the upper
2578  * bound of the partition we're looking for, if there
2579  * actually exists one.
2580  */
2581  part_index = partdesc->boundinfo->indexes[bound_offset + 1];
2582  }
2583  }
2584  break;
2585 
2586  default:
2587  elog(ERROR, "unexpected partition strategy: %d",
2588  (int) key->strategy);
2589  }
2590 
2591  /*
2592  * part_index < 0 means we failed to find a partition of this parent. Use
2593  * the default partition, if there is one.
2594  */
2595  if (part_index < 0)
2596  part_index = partdesc->boundinfo->default_index;
2597 
2598  return part_index;
2599 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2984
static int get_greatest_modulus(PartitionBoundInfo b)
Definition: partition.c:3061
#define partition_bound_accepts_nulls(bi)
Definition: partition.c:109
char strategy
Definition: rel.h:54
PartitionBoundInfo boundinfo
Definition: partition.h:40
#define ERROR
Definition: elog.h:43
static int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, void *probe, bool probe_is_bound, bool *is_equal)
Definition: partition.c:2881
int16 partnatts
Definition: rel.h:55
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:787
static uint64 compute_hash_value(PartitionKey key, Datum *values, bool *isnull)
Definition: partition.c:3076
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:788
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:789
int i
#define elog
Definition: elog.h:219
#define RelationGetPartitionDesc(relation)
Definition: rel.h:641

◆ get_partition_parent()

Oid get_partition_parent ( Oid  relid)

Definition at line 1372 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().

1373 {
1374  Form_pg_inherits form;
1375  Relation catalogRelation;
1376  SysScanDesc scan;
1377  ScanKeyData key[2];
1378  HeapTuple tuple;
1379  Oid result;
1380 
1381  catalogRelation = heap_open(InheritsRelationId, AccessShareLock);
1382 
1383  ScanKeyInit(&key[0],
1385  BTEqualStrategyNumber, F_OIDEQ,
1386  ObjectIdGetDatum(relid));
1387  ScanKeyInit(&key[1],
1389  BTEqualStrategyNumber, F_INT4EQ,
1390  Int32GetDatum(1));
1391 
1392  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
1393  NULL, 2, key);
1394 
1395  tuple = systable_getnext(scan);
1396  if (!HeapTupleIsValid(tuple))
1397  elog(ERROR, "could not find tuple for parent of relation %u", relid);
1398 
1399  form = (Form_pg_inherits) GETSTRUCT(tuple);
1400  result = form->inhparent;
1401 
1402  systable_endscan(scan);
1403  heap_close(catalogRelation, AccessShareLock);
1404 
1405  return result;
1406 }
#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:661
#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

◆ get_partition_qual_relid()

Expr* get_partition_qual_relid ( Oid  relid)

Definition at line 1512 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().

1513 {
1514  Relation rel = heap_open(relid, AccessShareLock);
1515  Expr *result = NULL;
1516  List *and_args;
1517 
1518  /* Do the work only if this relation is a partition. */
1519  if (rel->rd_rel->relispartition)
1520  {
1521  and_args = generate_partition_qual(rel);
1522 
1523  if (and_args == NIL)
1524  result = NULL;
1525  else if (list_length(and_args) > 1)
1526  result = makeBoolExpr(AND_EXPR, and_args, -1);
1527  else
1528  result = linitial(and_args);
1529  }
1530 
1531  /* Keep the lock. */
1532  heap_close(rel, NoLock);
1533 
1534  return result;
1535 }
#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:368
#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:2429
Definition: pg_list.h:45

◆ get_proposed_default_constraint()

List* get_proposed_default_constraint ( List new_part_constaints)

Definition at line 2991 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().

2992 {
2993  Expr *defPartConstraint;
2994 
2995  defPartConstraint = make_ands_explicit(new_part_constraints);
2996 
2997  /*
2998  * Derive the partition constraints of default partition by negating the
2999  * given partition constraints. The partition constraint never evaluates
3000  * to NULL, so negating it like this is safe.
3001  */
3002  defPartConstraint = makeBoolExpr(NOT_EXPR,
3003  list_make1(defPartConstraint),
3004  -1);
3005  defPartConstraint =
3006  (Expr *) eval_const_expressions(NULL,
3007  (Node *) defPartConstraint);
3008  defPartConstraint = canonicalize_qual(defPartConstraint);
3009 
3010  return list_make1(defPartConstraint);
3011 }
Definition: nodes.h:512
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2459
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:368
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

◆ get_qual_from_partbound()

List* get_qual_from_partbound ( Relation  rel,
Relation  parent,
PartitionBoundSpec spec 
)

Definition at line 1414 of file partition.c.

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

Referenced by ATExecAttachPartition(), and generate_partition_qual().

1416 {
1417  PartitionKey key = RelationGetPartitionKey(parent);
1418  List *my_qual = NIL;
1419 
1420  Assert(key != NULL);
1421 
1422  switch (key->strategy)
1423  {
1426  my_qual = get_qual_for_hash(parent, spec);
1427  break;
1428 
1431  my_qual = get_qual_for_list(parent, spec);
1432  break;
1433 
1436  my_qual = get_qual_for_range(parent, spec, false);
1437  break;
1438 
1439  default:
1440  elog(ERROR, "unexpected partition strategy: %d",
1441  (int) key->strategy);
1442  }
1443 
1444  return my_qual;
1445 }
#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:1753
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partition.c:2068
static List * get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
Definition: partition.c:1670
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:787
#define Assert(condition)
Definition: c.h:680
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:788
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:789
#define elog
Definition: elog.h:219
Definition: pg_list.h:45

◆ map_partition_varattnos()

List* map_partition_varattnos ( List expr,
int  target_varno,
Relation  partrel,
Relation  parent,
bool found_whole_row 
)

Definition at line 1462 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().

1465 {
1466  bool my_found_whole_row = false;
1467 
1468  if (expr != NIL)
1469  {
1470  AttrNumber *part_attnos;
1471 
1472  part_attnos = convert_tuples_by_name_map(RelationGetDescr(partrel),
1473  RelationGetDescr(parent),
1474  gettext_noop("could not convert row type"));
1475  expr = (List *) map_variable_attnos((Node *) expr,
1476  target_varno, 0,
1477  part_attnos,
1478  RelationGetDescr(parent)->natts,
1479  RelationGetForm(partrel)->reltype,
1480  &my_found_whole_row);
1481  }
1482 
1483  if (found_whole_row)
1484  *found_whole_row = my_found_whole_row;
1485 
1486  return expr;
1487 }
#define NIL
Definition: pg_list.h:69
#define RelationGetDescr(relation)
Definition: rel.h:437
#define RelationGetForm(relation)
Definition: rel.h:419
#define gettext_noop(x)
Definition: c.h:991
Definition: nodes.h:512
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

◆ partition_bounds_copy()

PartitionBoundInfo partition_bounds_copy ( PartitionBoundInfo  src,
PartitionKey  key 
)

Definition at line 856 of file partition.c.

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

Referenced by set_relation_partition_info().

858 {
860  int i;
861  int ndatums;
862  int partnatts;
863  int num_indexes;
864 
866 
867  dest->strategy = src->strategy;
868  ndatums = dest->ndatums = src->ndatums;
869  partnatts = key->partnatts;
870 
871  num_indexes = get_partition_bound_num_indexes(src);
872 
873  /* List partitioned tables have only a single partition key. */
874  Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
875 
876  dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
877 
878  if (src->kind != NULL)
879  {
880  dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
881  sizeof(PartitionRangeDatumKind *));
882  for (i = 0; i < ndatums; i++)
883  {
884  dest->kind[i] = (PartitionRangeDatumKind *) palloc(partnatts *
885  sizeof(PartitionRangeDatumKind));
886 
887  memcpy(dest->kind[i], src->kind[i],
888  sizeof(PartitionRangeDatumKind) * key->partnatts);
889  }
890  }
891  else
892  dest->kind = NULL;
893 
894  for (i = 0; i < ndatums; i++)
895  {
896  int j;
897 
898  /*
899  * For a corresponding to hash partition, datums array will have two
900  * elements - modulus and remainder.
901  */
902  bool hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
903  int natts = hash_part ? 2 : partnatts;
904 
905  dest->datums[i] = (Datum *) palloc(sizeof(Datum) * natts);
906 
907  for (j = 0; j < natts; j++)
908  {
909  bool byval;
910  int typlen;
911 
912  if (hash_part)
913  {
914  typlen = sizeof(int32); /* Always int4 */
915  byval = true; /* int4 is pass-by-value */
916  }
917  else
918  {
919  byval = key->parttypbyval[j];
920  typlen = key->parttyplen[j];
921  }
922 
923  if (dest->kind == NULL ||
924  dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
925  dest->datums[i][j] = datumCopy(src->datums[i][j],
926  byval, typlen);
927  }
928  }
929 
930  dest->indexes = (int *) palloc(sizeof(int) * num_indexes);
931  memcpy(dest->indexes, src->indexes, sizeof(int) * num_indexes);
932 
933  dest->null_index = src->null_index;
934  dest->default_index = src->default_index;
935 
936  return dest;
937 }
PartitionRangeDatumKind ** kind
Definition: partition.c:99
PartitionRangeDatumKind
Definition: parsenodes.h:823
static int get_partition_bound_num_indexes(PartitionBoundInfo b)
Definition: partition.c:3019
char strategy
Definition: rel.h:54
signed int int32
Definition: c.h:294
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
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:787
bool * parttypbyval
Definition: rel.h:72
struct PartitionBoundInfoData * PartitionBoundInfo
Definition: partition.h:31
#define Assert(condition)
Definition: c.h:680
int16 * parttyplen
Definition: rel.h:71
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:788
void * palloc(Size size)
Definition: mcxt.c:835
int i

◆ partition_bounds_equal()

bool partition_bounds_equal ( int  partnatts,
int16 parttyplen,
bool parttypbyval,
PartitionBoundInfo  b1,
PartitionBoundInfo  b2 
)

Definition at line 743 of file partition.c.

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

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

745 {
746  int i;
747 
748  if (b1->strategy != b2->strategy)
749  return false;
750 
751  if (b1->ndatums != b2->ndatums)
752  return false;
753 
754  if (b1->null_index != b2->null_index)
755  return false;
756 
757  if (b1->default_index != b2->default_index)
758  return false;
759 
761  {
762  int greatest_modulus = get_greatest_modulus(b1);
763 
764  /*
765  * If two hash partitioned tables have different greatest moduli,
766  * their partition schemes don't match.
767  */
768  if (greatest_modulus != get_greatest_modulus(b2))
769  return false;
770 
771  /*
772  * We arrange the partitions in the ascending order of their modulus
773  * and remainders. Also every modulus is factor of next larger
774  * modulus. Therefore we can safely store index of a given partition
775  * in indexes array at remainder of that partition. Also entries at
776  * (remainder + N * modulus) positions in indexes array are all same
777  * for (modulus, remainder) specification for any partition. Thus
778  * datums array from both the given bounds are same, if and only if
779  * their indexes array will be same. So, it suffices to compare
780  * indexes array.
781  */
782  for (i = 0; i < greatest_modulus; i++)
783  if (b1->indexes[i] != b2->indexes[i])
784  return false;
785 
786 #ifdef USE_ASSERT_CHECKING
787 
788  /*
789  * Nonetheless make sure that the bounds are indeed same when the
790  * indexes match. Hash partition bound stores modulus and remainder
791  * at b1->datums[i][0] and b1->datums[i][1] position respectively.
792  */
793  for (i = 0; i < b1->ndatums; i++)
794  Assert((b1->datums[i][0] == b2->datums[i][0] &&
795  b1->datums[i][1] == b2->datums[i][1]));
796 #endif
797  }
798  else
799  {
800  for (i = 0; i < b1->ndatums; i++)
801  {
802  int j;
803 
804  for (j = 0; j < partnatts; j++)
805  {
806  /* For range partitions, the bounds might not be finite. */
807  if (b1->kind != NULL)
808  {
809  /* The different kinds of bound all differ from each other */
810  if (b1->kind[i][j] != b2->kind[i][j])
811  return false;
812 
813  /*
814  * Non-finite bounds are equal without further
815  * examination.
816  */
817  if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
818  continue;
819  }
820 
821  /*
822  * Compare the actual values. Note that it would be both
823  * incorrect and unsafe to invoke the comparison operator
824  * derived from the partitioning specification here. It would
825  * be incorrect because we want the relcache entry to be
826  * updated for ANY change to the partition bounds, not just
827  * those that the partitioning operator thinks are
828  * significant. It would be unsafe because we might reach
829  * this code in the context of an aborted transaction, and an
830  * arbitrary partitioning operator might not be safe in that
831  * context. datumIsEqual() should be simple enough to be
832  * safe.
833  */
834  if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
835  parttypbyval[j], parttyplen[j]))
836  return false;
837  }
838 
839  if (b1->indexes[i] != b2->indexes[i])
840  return false;
841  }
842 
843  /* There are ndatums+1 indexes in case of range partitions */
844  if (b1->strategy == PARTITION_STRATEGY_RANGE &&
845  b1->indexes[i] != b2->indexes[i])
846  return false;
847  }
848  return true;
849 }
PartitionRangeDatumKind ** kind
Definition: partition.c:99
static int get_greatest_modulus(PartitionBoundInfo b)
Definition: partition.c:3061
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:219
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:787
#define Assert(condition)
Definition: c.h:680
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:789
int i

◆ RelationBuildPartitionDesc()

void RelationBuildPartitionDesc ( Relation  relation)

Definition at line 196 of file partition.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreateExtended(), 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, PartitionHashBound::index, PartitionListValue::index, PartitionRangeBound::index, PartitionBoundInfoData::indexes, Int32GetDatum, PartitionBoundSpec::is_default, PartitionBoundInfoData::kind, PartitionRangeBound::kind, lappend(), lappend_oid(), lfirst, lfirst_oid, list_length(), PartitionBoundSpec::listdatums, lower(), PartitionBoundSpec::lowerdatums, make_one_range_bound(), MEMCONTEXT_COPY_NAME, MemoryContextSwitchTo(), PartitionHashBound::modulus, PartitionBoundSpec::modulus, PartitionBoundInfoData::ndatums, NIL, NoLock, PartitionDescData::nparts, PartitionBoundInfoData::null_index, PartitionDescData::oids, palloc(), palloc0(), PARTITION_RANGE_DATUM_VALUE, PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partnatts, PartitionKeyData::parttypbyval, PartitionKeyData::parttyplen, pfree(), qsort, qsort_arg(), qsort_partition_hbound_cmp(), qsort_partition_list_value_cmp(), qsort_partition_rbound_cmp(), RelationData::rd_partdesc, RelationData::rd_pdcxt, RelationGetPartitionKey, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), RELOID, PartitionHashBound::remainder, PartitionBoundSpec::remainder, SearchSysCache1(), PartitionKeyData::strategy, PartitionBoundInfoData::strategy, PartitionBoundSpec::strategy, stringToNode(), SysCacheGetAttr(), TextDatumGetCString, upper(), PartitionBoundSpec::upperdatums, val, PartitionListValue::value, and value.

Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().

197 {
198  List *inhoids,
199  *partoids;
200  Oid *oids = NULL;
201  List *boundspecs = NIL;
202  ListCell *cell;
203  int i,
204  nparts;
206  PartitionDesc result;
207  MemoryContext oldcxt;
208 
209  int ndatums = 0;
210  int default_index = -1;
211 
212  /* Hash partitioning specific */
213  PartitionHashBound **hbounds = NULL;
214 
215  /* List partitioning specific */
216  PartitionListValue **all_values = NULL;
217  int null_index = -1;
218 
219  /* Range partitioning specific */
220  PartitionRangeBound **rbounds = NULL;
221 
222  /*
223  * The following could happen in situations where rel has a pg_class entry
224  * but not the pg_partitioned_table entry yet.
225  */
226  if (key == NULL)
227  return;
228 
229  /* Get partition oids from pg_inherits */
231 
232  /* Collect bound spec nodes in a list */
233  i = 0;
234  partoids = NIL;
235  foreach(cell, inhoids)
236  {
237  Oid inhrelid = lfirst_oid(cell);
238  HeapTuple tuple;
239  Datum datum;
240  bool isnull;
241  Node *boundspec;
242 
243  tuple = SearchSysCache1(RELOID, inhrelid);
244  if (!HeapTupleIsValid(tuple))
245  elog(ERROR, "cache lookup failed for relation %u", inhrelid);
246 
247  /*
248  * It is possible that the pg_class tuple of a partition has not been
249  * updated yet to set its relpartbound field. The only case where
250  * this happens is when we open the parent relation to check using its
251  * partition descriptor that a new partition's bound does not overlap
252  * some existing partition.
253  */
254  if (!((Form_pg_class) GETSTRUCT(tuple))->relispartition)
255  {
256  ReleaseSysCache(tuple);
257  continue;
258  }
259 
260  datum = SysCacheGetAttr(RELOID, tuple,
262  &isnull);
263  Assert(!isnull);
264  boundspec = (Node *) stringToNode(TextDatumGetCString(datum));
265 
266  /*
267  * Sanity check: If the PartitionBoundSpec says this is the default
268  * partition, its OID should correspond to whatever's stored in
269  * pg_partitioned_table.partdefid; if not, the catalog is corrupt.
270  */
271  if (castNode(PartitionBoundSpec, boundspec)->is_default)
272  {
273  Oid partdefid;
274 
276  if (partdefid != inhrelid)
277  elog(ERROR, "expected partdefid %u, but got %u",
278  inhrelid, partdefid);
279  }
280 
281  boundspecs = lappend(boundspecs, boundspec);
282  partoids = lappend_oid(partoids, inhrelid);
283  ReleaseSysCache(tuple);
284  }
285 
286  nparts = list_length(partoids);
287 
288  if (nparts > 0)
289  {
290  oids = (Oid *) palloc(nparts * sizeof(Oid));
291  i = 0;
292  foreach(cell, partoids)
293  oids[i++] = lfirst_oid(cell);
294 
295  /* Convert from node to the internal representation */
296  if (key->strategy == PARTITION_STRATEGY_HASH)
297  {
298  ndatums = nparts;
299  hbounds = (PartitionHashBound **)
300  palloc(nparts * sizeof(PartitionHashBound *));
301 
302  i = 0;
303  foreach(cell, boundspecs)
304  {
306  lfirst(cell));
307 
308  if (spec->strategy != PARTITION_STRATEGY_HASH)
309  elog(ERROR, "invalid strategy in partition bound spec");
310 
311  hbounds[i] = (PartitionHashBound *)
312  palloc(sizeof(PartitionHashBound));
313 
314  hbounds[i]->modulus = spec->modulus;
315  hbounds[i]->remainder = spec->remainder;
316  hbounds[i]->index = i;
317  i++;
318  }
319 
320  /* Sort all the bounds in ascending order */
321  qsort(hbounds, nparts, sizeof(PartitionHashBound *),
323  }
324  else if (key->strategy == PARTITION_STRATEGY_LIST)
325  {
326  List *non_null_values = NIL;
327 
328  /*
329  * Create a unified list of non-null values across all partitions.
330  */
331  i = 0;
332  null_index = -1;
333  foreach(cell, boundspecs)
334  {
336  lfirst(cell));
337  ListCell *c;
338 
339  if (spec->strategy != PARTITION_STRATEGY_LIST)
340  elog(ERROR, "invalid strategy in partition bound spec");
341 
342  /*
343  * Note the index of the partition bound spec for the default
344  * partition. There's no datum to add to the list of non-null
345  * datums for this partition.
346  */
347  if (spec->is_default)
348  {
349  default_index = i;
350  i++;
351  continue;
352  }
353 
354  foreach(c, spec->listdatums)
355  {
356  Const *val = castNode(Const, lfirst(c));
357  PartitionListValue *list_value = NULL;
358 
359  if (!val->constisnull)
360  {
361  list_value = (PartitionListValue *)
362  palloc0(sizeof(PartitionListValue));
363  list_value->index = i;
364  list_value->value = val->constvalue;
365  }
366  else
367  {
368  /*
369  * Never put a null into the values array, flag
370  * instead for the code further down below where we
371  * construct the actual relcache struct.
372  */
373  if (null_index != -1)
374  elog(ERROR, "found null more than once");
375  null_index = i;
376  }
377 
378  if (list_value)
379  non_null_values = lappend(non_null_values,
380  list_value);
381  }
382 
383  i++;
384  }
385 
386  ndatums = list_length(non_null_values);
387 
388  /*
389  * Collect all list values in one array. Alongside the value, we
390  * also save the index of partition the value comes from.
391  */
392  all_values = (PartitionListValue **) palloc(ndatums *
393  sizeof(PartitionListValue *));
394  i = 0;
395  foreach(cell, non_null_values)
396  {
397  PartitionListValue *src = lfirst(cell);
398 
399  all_values[i] = (PartitionListValue *)
400  palloc(sizeof(PartitionListValue));
401  all_values[i]->value = src->value;
402  all_values[i]->index = src->index;
403  i++;
404  }
405 
406  qsort_arg(all_values, ndatums, sizeof(PartitionListValue *),
407  qsort_partition_list_value_cmp, (void *) key);
408  }
409  else if (key->strategy == PARTITION_STRATEGY_RANGE)
410  {
411  int k;
412  PartitionRangeBound **all_bounds,
413  *prev;
414 
415  all_bounds = (PartitionRangeBound **) palloc0(2 * nparts *
416  sizeof(PartitionRangeBound *));
417 
418  /*
419  * Create a unified list of range bounds across all the
420  * partitions.
421  */
422  i = ndatums = 0;
423  foreach(cell, boundspecs)
424  {
426  lfirst(cell));
428  *upper;
429 
430  if (spec->strategy != PARTITION_STRATEGY_RANGE)
431  elog(ERROR, "invalid strategy in partition bound spec");
432 
433  /*
434  * Note the index of the partition bound spec for the default
435  * partition. There's no datum to add to the allbounds array
436  * for this partition.
437  */
438  if (spec->is_default)
439  {
440  default_index = i++;
441  continue;
442  }
443 
444  lower = make_one_range_bound(key, i, spec->lowerdatums,
445  true);
446  upper = make_one_range_bound(key, i, spec->upperdatums,
447  false);
448  all_bounds[ndatums++] = lower;
449  all_bounds[ndatums++] = upper;
450  i++;
451  }
452 
453  Assert(ndatums == nparts * 2 ||
454  (default_index != -1 && ndatums == (nparts - 1) * 2));
455 
456  /* Sort all the bounds in ascending order */
457  qsort_arg(all_bounds, ndatums,
458  sizeof(PartitionRangeBound *),
460  (void *) key);
461 
462  /* Save distinct bounds from all_bounds into rbounds. */
463  rbounds = (PartitionRangeBound **)
464  palloc(ndatums * sizeof(PartitionRangeBound *));
465  k = 0;
466  prev = NULL;
467  for (i = 0; i < ndatums; i++)
468  {
469  PartitionRangeBound *cur = all_bounds[i];
470  bool is_distinct = false;
471  int j;
472 
473  /* Is the current bound distinct from the previous one? */
474  for (j = 0; j < key->partnatts; j++)
475  {
476  Datum cmpval;
477 
478  if (prev == NULL || cur->kind[j] != prev->kind[j])
479  {
480  is_distinct = true;
481  break;
482  }
483 
484  /*
485  * If the bounds are both MINVALUE or MAXVALUE, stop now
486  * and treat them as equal, since any values after this
487  * point must be ignored.
488  */
489  if (cur->kind[j] != PARTITION_RANGE_DATUM_VALUE)
490  break;
491 
492  cmpval = FunctionCall2Coll(&key->partsupfunc[j],
493  key->partcollation[j],
494  cur->datums[j],
495  prev->datums[j]);
496  if (DatumGetInt32(cmpval) != 0)
497  {
498  is_distinct = true;
499  break;
500  }
501  }
502 
503  /*
504  * Only if the bound is distinct save it into a temporary
505  * array i.e. rbounds which is later copied into boundinfo
506  * datums array.
507  */
508  if (is_distinct)
509  rbounds[k++] = all_bounds[i];
510 
511  prev = cur;
512  }
513 
514  /* Update ndatums to hold the count of distinct datums. */
515  ndatums = k;
516  }
517  else
518  elog(ERROR, "unexpected partition strategy: %d",
519  (int) key->strategy);
520  }
521 
522  /* Now build the actual relcache partition descriptor */
527  oldcxt = MemoryContextSwitchTo(rel->rd_pdcxt);
528 
529  result = (PartitionDescData *) palloc0(sizeof(PartitionDescData));
530  result->nparts = nparts;
531  if (nparts > 0)
532  {
533  PartitionBoundInfo boundinfo;
534  int *mapping;
535  int next_index = 0;
536 
537  result->oids = (Oid *) palloc0(nparts * sizeof(Oid));
538 
539  boundinfo = (PartitionBoundInfoData *)
541  boundinfo->strategy = key->strategy;
542  boundinfo->default_index = -1;
543  boundinfo->ndatums = ndatums;
544  boundinfo->null_index = -1;
545  boundinfo->datums = (Datum **) palloc0(ndatums * sizeof(Datum *));
546 
547  /* Initialize mapping array with invalid values */
548  mapping = (int *) palloc(sizeof(int) * nparts);
549  for (i = 0; i < nparts; i++)
550  mapping[i] = -1;
551 
552  switch (key->strategy)
553  {
555  {
556  /* Modulus are stored in ascending order */
557  int greatest_modulus = hbounds[ndatums - 1]->modulus;
558 
559  boundinfo->indexes = (int *) palloc(greatest_modulus *
560  sizeof(int));
561 
562  for (i = 0; i < greatest_modulus; i++)
563  boundinfo->indexes[i] = -1;
564 
565  for (i = 0; i < nparts; i++)
566  {
567  int modulus = hbounds[i]->modulus;
568  int remainder = hbounds[i]->remainder;
569 
570  boundinfo->datums[i] = (Datum *) palloc(2 *
571  sizeof(Datum));
572  boundinfo->datums[i][0] = Int32GetDatum(modulus);
573  boundinfo->datums[i][1] = Int32GetDatum(remainder);
574 
575  while (remainder < greatest_modulus)
576  {
577  /* overlap? */
578  Assert(boundinfo->indexes[remainder] == -1);
579  boundinfo->indexes[remainder] = i;
580  remainder += modulus;
581  }
582 
583  mapping[hbounds[i]->index] = i;
584  pfree(hbounds[i]);
585  }
586  pfree(hbounds);
587  break;
588  }
589 
591  {
592  boundinfo->indexes = (int *) palloc(ndatums * sizeof(int));
593 
594  /*
595  * Copy values. Indexes of individual values are mapped
596  * to canonical values so that they match for any two list
597  * partitioned tables with same number of partitions and
598  * same lists per partition. One way to canonicalize is
599  * to assign the index in all_values[] of the smallest
600  * value of each partition, as the index of all of the
601  * partition's values.
602  */
603  for (i = 0; i < ndatums; i++)
604  {
605  boundinfo->datums[i] = (Datum *) palloc(sizeof(Datum));
606  boundinfo->datums[i][0] = datumCopy(all_values[i]->value,
607  key->parttypbyval[0],
608  key->parttyplen[0]);
609 
610  /* If the old index has no mapping, assign one */
611  if (mapping[all_values[i]->index] == -1)
612  mapping[all_values[i]->index] = next_index++;
613 
614  boundinfo->indexes[i] = mapping[all_values[i]->index];
615  }
616 
617  /*
618  * If null-accepting partition has no mapped index yet,
619  * assign one. This could happen if such partition
620  * accepts only null and hence not covered in the above
621  * loop which only handled non-null values.
622  */
623  if (null_index != -1)
624  {
625  Assert(null_index >= 0);
626  if (mapping[null_index] == -1)
627  mapping[null_index] = next_index++;
628  boundinfo->null_index = mapping[null_index];
629  }
630 
631  /* Assign mapped index for the default partition. */
632  if (default_index != -1)
633  {
634  /*
635  * The default partition accepts any value not
636  * specified in the lists of other partitions, hence
637  * it should not get mapped index while assigning
638  * those for non-null datums.
639  */
640  Assert(default_index >= 0 &&
641  mapping[default_index] == -1);
642  mapping[default_index] = next_index++;
643  boundinfo->default_index = mapping[default_index];
644  }
645 
646  /* All partition must now have a valid mapping */
647  Assert(next_index == nparts);
648  break;
649  }
650 
652  {
653  boundinfo->kind = (PartitionRangeDatumKind **)
654  palloc(ndatums *
655  sizeof(PartitionRangeDatumKind *));
656  boundinfo->indexes = (int *) palloc((ndatums + 1) *
657  sizeof(int));
658 
659  for (i = 0; i < ndatums; i++)
660  {
661  int j;
662 
663  boundinfo->datums[i] = (Datum *) palloc(key->partnatts *
664  sizeof(Datum));
665  boundinfo->kind[i] = (PartitionRangeDatumKind *)
666  palloc(key->partnatts *
667  sizeof(PartitionRangeDatumKind));
668  for (j = 0; j < key->partnatts; j++)
669  {
670  if (rbounds[i]->kind[j] == PARTITION_RANGE_DATUM_VALUE)
671  boundinfo->datums[i][j] =
672  datumCopy(rbounds[i]->datums[j],
673  key->parttypbyval[j],
674  key->parttyplen[j]);
675  boundinfo->kind[i][j] = rbounds[i]->kind[j];
676  }
677 
678  /*
679  * There is no mapping for invalid indexes.
680  *
681  * Any lower bounds in the rbounds array have invalid
682  * indexes assigned, because the values between the
683  * previous bound (if there is one) and this (lower)
684  * bound are not part of the range of any existing
685  * partition.
686  */
687  if (rbounds[i]->lower)
688  boundinfo->indexes[i] = -1;
689  else
690  {
691  int orig_index = rbounds[i]->index;
692 
693  /* If the old index has no mapping, assign one */
694  if (mapping[orig_index] == -1)
695  mapping[orig_index] = next_index++;
696 
697  boundinfo->indexes[i] = mapping[orig_index];
698  }
699  }
700 
701  /* Assign mapped index for the default partition. */
702  if (default_index != -1)
703  {
704  Assert(default_index >= 0 && mapping[default_index] == -1);
705  mapping[default_index] = next_index++;
706  boundinfo->default_index = mapping[default_index];
707  }
708  boundinfo->indexes[i] = -1;
709  break;
710  }
711 
712  default:
713  elog(ERROR, "unexpected partition strategy: %d",
714  (int) key->strategy);
715  }
716 
717  result->boundinfo = boundinfo;
718 
719  /*
720  * Now assign OIDs from the original array into mapped indexes of the
721  * result array. Order of OIDs in the former is defined by the
722  * catalog scan that retrieved them, whereas that in the latter is
723  * defined by canonicalized representation of the partition bounds.
724  */
725  for (i = 0; i < nparts; i++)
726  result->oids[mapping[i]] = oids[i];
727  pfree(mapping);
728  }
729 
730  MemoryContextSwitchTo(oldcxt);
731  rel->rd_partdesc = result;
732 }
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:99
PartitionRangeDatumKind * kind
Definition: partition.c:137
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
static int32 qsort_partition_hbound_cmp(const void *a, const void *b)
Definition: partition.c:2607
#define DatumGetInt32(X)
Definition: postgres.h:478
#define MEMCONTEXT_COPY_NAME
Definition: memutils.h:188
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:44
FmgrInfo * partsupfunc
Definition: rel.h:63
#define castNode(_type_, nodeptr)
Definition: nodes.h:581
PartitionRangeDatumKind
Definition: parsenodes.h:823
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:2698
Definition: nodes.h:512
struct cursor * cur
Definition: ecpg.c:28
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:75
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:40
Definition: type.h:89
void pfree(void *pointer)
Definition: mcxt.c:936
#define ERROR
Definition: elog.h:43
MemoryContext AllocSetContextCreateExtended(MemoryContext parent, const char *name, int flags, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:394
static struct @121 value
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:197
static int32 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg)
Definition: partition.c:2639
char * c
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:445
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
Oid get_default_partition_oid(Oid parentId)
Definition: partition.c:2936
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:2658
void * palloc0(Size size)
Definition: mcxt.c:864
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
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:787
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:680
#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:788
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:789
#define Int32GetDatum(X)
Definition: postgres.h:485
void * palloc(Size size)
Definition: mcxt.c:835
int i
#define elog
Definition: elog.h:219
#define qsort(a, b, c, d)
Definition: port.h:408
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:425
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

◆ RelationGetPartitionQual()

List* RelationGetPartitionQual ( Relation  rel)

Definition at line 1495 of file partition.c.

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

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

1496 {
1497  /* Quick exit */
1498  if (!rel->rd_rel->relispartition)
1499  return NIL;
1500 
1501  return generate_partition_qual(rel);
1502 }
#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:2429

◆ update_default_partition_oid()

void update_default_partition_oid ( Oid  parentId,
Oid  defaultPartId 
)

Definition at line 2961 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().

2962 {
2963  HeapTuple tuple;
2964  Relation pg_partitioned_table;
2965  Form_pg_partitioned_table part_table_form;
2966 
2967  pg_partitioned_table = heap_open(PartitionedRelationId, RowExclusiveLock);
2968 
2969  tuple = SearchSysCacheCopy1(PARTRELID, ObjectIdGetDatum(parentId));
2970 
2971  if (!HeapTupleIsValid(tuple))
2972  elog(ERROR, "cache lookup failed for partition key of relation %u",
2973  parentId);
2974 
2975  part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
2976  part_table_form->partdefid = defaultPartId;
2977  CatalogTupleUpdate(pg_partitioned_table, &tuple->t_self, tuple);
2978 
2979  heap_freetuple(tuple);
2980  heap_close(pg_partitioned_table, RowExclusiveLock);
2981 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#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