PostgreSQL Source Code  git master
partition.c File Reference
#include "postgres.h"
#include "access/hash.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "access/sysattr.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaddress.h"
#include "catalog/partition.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_partitioned_table.h"
#include "catalog/pg_type.h"
#include "commands/tablecmds.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/parsenodes.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "optimizer/prep.h"
#include "optimizer/var.h"
#include "parser/parse_coerce.h"
#include "rewrite/rewriteManip.h"
#include "storage/lmgr.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/hashutils.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/ruleutils.h"
#include "utils/syscache.h"
Include dependency graph for partition.c:

Go to the source code of this file.

Data Structures

struct  PartitionBoundInfoData
 
struct  PartitionHashBound
 
struct  PartitionListValue
 
struct  PartitionRangeBound
 

Macros

#define partition_bound_accepts_nulls(bi)   ((bi)->null_index != -1)
 
#define partition_bound_has_default(bi)   ((bi)->default_index != -1)
 

Typedefs

typedef struct PartitionBoundInfoData PartitionBoundInfoData
 
typedef struct PartitionHashBound PartitionHashBound
 
typedef struct PartitionListValue PartitionListValue
 
typedef struct PartitionRangeBound PartitionRangeBound
 

Functions

static int32 qsort_partition_hbound_cmp (const void *a, const void *b)
 
static int32 qsort_partition_list_value_cmp (const void *a, const void *b, void *arg)
 
static int32 qsort_partition_rbound_cmp (const void *a, const void *b, void *arg)
 
static Oid get_partition_operator (PartitionKey key, int col, StrategyNumber strategy, bool *need_relabel)
 
static Exprmake_partition_op_expr (PartitionKey key, int keynum, uint16 strategy, Expr *arg1, Expr *arg2)
 
static void get_range_key_properties (PartitionKey key, int keynum, PartitionRangeDatum *ldatum, PartitionRangeDatum *udatum, ListCell **partexprs_item, Expr **keyCol, Const **lower_val, Const **upper_val)
 
static Listget_qual_for_hash (Relation parent, PartitionBoundSpec *spec)
 
static Listget_qual_for_list (Relation parent, PartitionBoundSpec *spec)
 
static Listget_qual_for_range (Relation parent, PartitionBoundSpec *spec, bool for_default)
 
static Listget_range_nulltest (PartitionKey key)
 
static Listgenerate_partition_qual (Relation rel)
 
static PartitionRangeBoundmake_one_range_bound (PartitionKey key, int index, List *datums, bool lower)
 
static int32 partition_hbound_cmp (int modulus1, int remainder1, int modulus2, int remainder2)
 
static int32 partition_rbound_cmp (PartitionKey key, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
 
static int32 partition_rbound_datum_cmp (PartitionKey key, Datum *rb_datums, PartitionRangeDatumKind *rb_kind, Datum *tuple_datums, int n_tuple_datums)
 
static int partition_list_bsearch (PartitionKey key, PartitionBoundInfo boundinfo, Datum value, bool *is_equal)
 
static int partition_range_bsearch (PartitionKey key, PartitionBoundInfo boundinfo, PartitionRangeBound *probe, bool *is_equal)
 
static int partition_range_datum_bsearch (PartitionKey key, PartitionBoundInfo boundinfo, int nvalues, Datum *values, bool *is_equal)
 
static int partition_hash_bsearch (PartitionKey key, PartitionBoundInfo boundinfo, int modulus, int remainder)
 
static int get_partition_bound_num_indexes (PartitionBoundInfo b)
 
static int get_greatest_modulus (PartitionBoundInfo b)
 
static uint64 compute_hash_value (PartitionKey key, Datum *values, bool *isnull)
 
void RelationBuildPartitionDesc (Relation rel)
 
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)
 
void check_default_allows_bound (Relation parent, Relation default_rel, PartitionBoundSpec *new_spec)
 
Oid get_partition_parent (Oid relid)
 
Listget_qual_from_partbound (Relation rel, Relation parent, PartitionBoundSpec *spec)
 
Listmap_partition_varattnos (List *expr, int fromrel_varno, Relation to_rel, Relation from_rel, bool *found_whole_row)
 
ListRelationGetPartitionQual (Relation rel)
 
Exprget_partition_qual_relid (Oid relid)
 
int get_partition_for_tuple (Relation relation, Datum *values, bool *isnull)
 
bool has_partition_attrs (Relation rel, Bitmapset *attnums, bool *used_in_expr)
 
Oid get_default_oid_from_partdesc (PartitionDesc partdesc)
 
Oid get_default_partition_oid (Oid parentId)
 
void update_default_partition_oid (Oid parentId, Oid defaultPartId)
 
Listget_proposed_default_constraint (List *new_part_constraints)
 
Datum satisfies_hash_partition (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

◆ partition_bound_accepts_nulls

#define partition_bound_accepts_nulls (   bi)    ((bi)->null_index != -1)

◆ partition_bound_has_default

#define partition_bound_has_default (   bi)    ((bi)->default_index != -1)

Definition at line 110 of file partition.c.

Referenced by check_new_partition_bound(), and get_default_oid_from_partdesc().

Typedef Documentation

◆ PartitionBoundInfoData

◆ PartitionHashBound

◆ PartitionListValue

◆ PartitionRangeBound

Function Documentation

◆ check_default_allows_bound()

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

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

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

◆ check_new_partition_bound()

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

Definition at line 950 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, PartitionBoundInfoData::kind, 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_has_default, partition_hash_bsearch(), partition_list_bsearch(), partition_range_bsearch(), 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().

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

◆ compute_hash_value()

static uint64 compute_hash_value ( PartitionKey  key,
Datum values,
bool isnull 
)
static

Definition at line 3251 of file partition.c.

References Assert, DatumGetUInt64, FmgrInfo::fn_oid, FunctionCall2, hash(), hash_combine64(), HASH_PARTITION_SEED, i, OidIsValid, PartitionKeyData::partnatts, PartitionKeyData::partsupfunc, and UInt64GetDatum.

Referenced by get_partition_for_tuple().

3252 {
3253  int i;
3254  int nkeys = key->partnatts;
3255  uint64 rowHash = 0;
3257 
3258  for (i = 0; i < nkeys; i++)
3259  {
3260  if (!isnull[i])
3261  {
3262  Datum hash;
3263 
3264  Assert(OidIsValid(key->partsupfunc[i].fn_oid));
3265 
3266  /*
3267  * Compute hash for each datum value by calling respective
3268  * datatype-specific hash functions of each partition key
3269  * attribute.
3270  */
3271  hash = FunctionCall2(&key->partsupfunc[i], values[i], seed);
3272 
3273  /* Form a single 64-bit hash value */
3274  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
3275  }
3276  }
3277 
3278  return rowHash;
3279 }
FmgrInfo * partsupfunc
Definition: rel.h:63
#define UInt64GetDatum(X)
Definition: postgres.h:631
#define FunctionCall2(flinfo, arg1, arg2)
Definition: fmgr.h:605
#define OidIsValid(objectId)
Definition: c.h:594
static uint64 hash_combine64(uint64 a, uint64 b)
Definition: hashutils.h:29
uintptr_t Datum
Definition: postgres.h:365
int16 partnatts
Definition: rel.h:55
Oid fn_oid
Definition: fmgr.h:59
#define DatumGetUInt64(X)
Definition: postgres.h:617
#define Assert(condition)
Definition: c.h:688
#define HASH_PARTITION_SEED
Definition: partition.h:23
static Datum values[MAXATTR]
Definition: bootstrap.c:164
int i
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:541

◆ generate_partition_qual()

static List * generate_partition_qual ( Relation  rel)
static

Definition at line 2478 of file partition.c.

References AccessShareLock, Anum_pg_class_relpartbound, CacheMemoryContext, castNode, check_stack_depth(), copyObject, elog, ERROR, get_partition_parent(), get_qual_from_partbound(), heap_close, heap_open(), HeapTupleIsValid, list_concat(), map_partition_varattnos(), MemoryContextSwitchTo(), NIL, NoLock, RelationData::rd_partcheck, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), RELOID, SearchSysCache1(), stringToNode(), SysCacheGetAttr(), and TextDatumGetCString.

Referenced by get_partition_qual_relid(), and RelationGetPartitionQual().

2479 {
2480  HeapTuple tuple;
2481  MemoryContext oldcxt;
2482  Datum boundDatum;
2483  bool isnull;
2484  PartitionBoundSpec *bound;
2485  List *my_qual = NIL,
2486  *result = NIL;
2487  Relation parent;
2488  bool found_whole_row;
2489 
2490  /* Guard against stack overflow due to overly deep partition tree */
2492 
2493  /* Quick copy */
2494  if (rel->rd_partcheck != NIL)
2495  return copyObject(rel->rd_partcheck);
2496 
2497  /* Grab at least an AccessShareLock on the parent table */
2499  AccessShareLock);
2500 
2501  /* Get pg_class.relpartbound */
2502  tuple = SearchSysCache1(RELOID, RelationGetRelid(rel));
2503  if (!HeapTupleIsValid(tuple))
2504  elog(ERROR, "cache lookup failed for relation %u",
2505  RelationGetRelid(rel));
2506 
2507  boundDatum = SysCacheGetAttr(RELOID, tuple,
2509  &isnull);
2510  if (isnull) /* should not happen */
2511  elog(ERROR, "relation \"%s\" has relpartbound = null",
2513  bound = castNode(PartitionBoundSpec,
2514  stringToNode(TextDatumGetCString(boundDatum)));
2515  ReleaseSysCache(tuple);
2516 
2517  my_qual = get_qual_from_partbound(rel, parent, bound);
2518 
2519  /* Add the parent's quals to the list (if any) */
2520  if (parent->rd_rel->relispartition)
2521  result = list_concat(generate_partition_qual(parent), my_qual);
2522  else
2523  result = my_qual;
2524 
2525  /*
2526  * Change Vars to have partition's attnos instead of the parent's. We do
2527  * this after we concatenate the parent's quals, because we want every Var
2528  * in it to bear this relation's attnos. It's safe to assume varno = 1
2529  * here.
2530  */
2531  result = map_partition_varattnos(result, 1, rel, parent,
2532  &found_whole_row);
2533  /* There can never be a whole-row reference here */
2534  if (found_whole_row)
2535  elog(ERROR, "unexpected whole-row reference found in partition key");
2536 
2537  /* Save a copy in the relcache */
2539  rel->rd_partcheck = copyObject(result);
2540  MemoryContextSwitchTo(oldcxt);
2541 
2542  /* Keep the parent locked until commit */
2543  heap_close(parent, NoLock);
2544 
2545  return result;
2546 }
#define NIL
Definition: pg_list.h:69
void * stringToNode(char *str)
Definition: read.c:38
#define castNode(_type_, nodeptr)
Definition: nodes.h:582
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
List * list_concat(List *list1, List *list2)
Definition: list.c:321
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
List * get_qual_from_partbound(Relation rel, Relation parent, PartitionBoundSpec *spec)
Definition: partition.c:1424
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel, bool *found_whole_row)
Definition: partition.c:1475
#define ERROR
Definition: elog.h:43
Oid get_partition_parent(Oid relid)
Definition: partition.c:1382
#define NoLock
Definition: lockdefs.h:34
void check_stack_depth(void)
Definition: postgres.c:3154
#define RelationGetRelationName(relation)
Definition: rel.h:445
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define TextDatumGetCString(d)
Definition: builtins.h:92
uintptr_t Datum
Definition: postgres.h:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define Anum_pg_class_relpartbound
Definition: pg_class.h:135
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
static List * generate_partition_qual(Relation rel)
Definition: partition.c:2478
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:626
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:425
List * rd_partcheck
Definition: rel.h:132
MemoryContext CacheMemoryContext
Definition: mcxt.c:46

◆ get_default_oid_from_partdesc()

Oid get_default_oid_from_partdesc ( PartitionDesc  partdesc)

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

3095 {
3096  if (partdesc && partdesc->boundinfo &&
3098  return partdesc->oids[partdesc->boundinfo->default_index];
3099 
3100  return InvalidOid;
3101 }
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 3111 of file partition.c.

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

Referenced by heap_drop_with_catalog(), and RelationBuildPartitionDesc().

3112 {
3113  HeapTuple tuple;
3114  Oid defaultPartId = InvalidOid;
3115 
3116  tuple = SearchSysCache1(PARTRELID, ObjectIdGetDatum(parentId));
3117 
3118  if (HeapTupleIsValid(tuple))
3119  {
3120  Form_pg_partitioned_table part_table_form;
3121 
3122  part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
3123  defaultPartId = part_table_form->partdefid;
3124  ReleaseSysCache(tuple);
3125  }
3126 
3127  return defaultPartId;
3128 }
#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:490
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_greatest_modulus()

static int get_greatest_modulus ( PartitionBoundInfo  b)
static

Definition at line 3236 of file partition.c.

References Assert, DatumGetInt32, PartitionBoundInfoData::datums, PartitionBoundInfoData::ndatums, PARTITION_STRATEGY_HASH, and PartitionBoundInfoData::strategy.

Referenced by check_new_partition_bound(), get_partition_bound_num_indexes(), get_partition_for_tuple(), and partition_bounds_equal().

3237 {
3238  Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
3239  Assert(bound->datums && bound->ndatums > 0);
3240  Assert(DatumGetInt32(bound->datums[bound->ndatums - 1][0]) > 0);
3241 
3242  return DatumGetInt32(bound->datums[bound->ndatums - 1][0]);
3243 }
#define DatumGetInt32(X)
Definition: postgres.h:455
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:795
#define Assert(condition)
Definition: c.h:688

◆ get_partition_bound_num_indexes()

static int get_partition_bound_num_indexes ( PartitionBoundInfo  b)
static

Definition at line 3194 of file partition.c.

References Assert, elog, ERROR, get_greatest_modulus(), PartitionBoundInfoData::ndatums, PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, and PartitionBoundInfoData::strategy.

Referenced by partition_bounds_copy().

3195 {
3196  int num_indexes;
3197 
3198  Assert(bound);
3199 
3200  switch (bound->strategy)
3201  {
3203 
3204  /*
3205  * The number of the entries in the indexes array is same as the
3206  * greatest modulus.
3207  */
3208  num_indexes = get_greatest_modulus(bound);
3209  break;
3210 
3212  num_indexes = bound->ndatums;
3213  break;
3214 
3216  /* Range partitioned table has an extra index. */
3217  num_indexes = bound->ndatums + 1;
3218  break;
3219 
3220  default:
3221  elog(ERROR, "unexpected partition strategy: %d",
3222  (int) bound->strategy);
3223  }
3224 
3225  return num_indexes;
3226 }
static int get_greatest_modulus(PartitionBoundInfo b)
Definition: partition.c:3236
#define ERROR
Definition: elog.h:43
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:795
#define Assert(condition)
Definition: c.h:688
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:796
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:797
#define elog
Definition: elog.h:219

◆ get_partition_for_tuple()

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

Definition at line 2557 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_list_bsearch(), partition_range_datum_bsearch(), PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partnatts, RelationGetPartitionDesc, RelationGetPartitionKey, and PartitionKeyData::strategy.

Referenced by ExecFindPartition().

2558 {
2559  int bound_offset;
2560  int part_index = -1;
2561  PartitionKey key = RelationGetPartitionKey(relation);
2562  PartitionDesc partdesc = RelationGetPartitionDesc(relation);
2563 
2564  /* Route as appropriate based on partitioning strategy. */
2565  switch (key->strategy)
2566  {
2568  {
2569  PartitionBoundInfo boundinfo = partdesc->boundinfo;
2570  int greatest_modulus = get_greatest_modulus(boundinfo);
2571  uint64 rowHash = compute_hash_value(key, values, isnull);
2572 
2573  part_index = boundinfo->indexes[rowHash % greatest_modulus];
2574  }
2575  break;
2576 
2578  if (isnull[0])
2579  {
2581  part_index = partdesc->boundinfo->null_index;
2582  }
2583  else
2584  {
2585  bool equal = false;
2586 
2587  bound_offset = partition_list_bsearch(key,
2588  partdesc->boundinfo,
2589  values[0], &equal);
2590  if (bound_offset >= 0 && equal)
2591  part_index = partdesc->boundinfo->indexes[bound_offset];
2592  }
2593  break;
2594 
2596  {
2597  bool equal = false,
2598  range_partkey_has_null = false;
2599  int i;
2600 
2601  /*
2602  * No range includes NULL, so this will be accepted by the
2603  * default partition if there is one, and otherwise rejected.
2604  */
2605  for (i = 0; i < key->partnatts; i++)
2606  {
2607  if (isnull[i])
2608  {
2609  range_partkey_has_null = true;
2610  break;
2611  }
2612  }
2613 
2614  if (!range_partkey_has_null)
2615  {
2616  bound_offset = partition_range_datum_bsearch(key,
2617  partdesc->boundinfo,
2618  key->partnatts,
2619  values,
2620  &equal);
2621  /*
2622  * The bound at bound_offset is less than or equal to the
2623  * tuple value, so the bound at offset+1 is the upper
2624  * bound of the partition we're looking for, if there
2625  * actually exists one.
2626  */
2627  part_index = partdesc->boundinfo->indexes[bound_offset + 1];
2628  }
2629  }
2630  break;
2631 
2632  default:
2633  elog(ERROR, "unexpected partition strategy: %d",
2634  (int) key->strategy);
2635  }
2636 
2637  /*
2638  * part_index < 0 means we failed to find a partition of this parent. Use
2639  * the default partition, if there is one.
2640  */
2641  if (part_index < 0)
2642  part_index = partdesc->boundinfo->default_index;
2643 
2644  return part_index;
2645 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2991
static int get_greatest_modulus(PartitionBoundInfo b)
Definition: partition.c:3236
#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_range_datum_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, int nvalues, Datum *values, bool *is_equal)
Definition: partition.c:3010
int16 partnatts
Definition: rel.h:55
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:795
static uint64 compute_hash_value(PartitionKey key, Datum *values, bool *isnull)
Definition: partition.c:3251
static int partition_list_bsearch(PartitionKey key, PartitionBoundInfo boundinfo, Datum value, bool *is_equal)
Definition: partition.c:2923
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:796
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:797
int i
#define elog
Definition: elog.h:219
#define RelationGetPartitionDesc(relation)
Definition: rel.h:641

◆ get_partition_operator()

static Oid get_partition_operator ( PartitionKey  key,
int  col,
StrategyNumber  strategy,
bool need_relabel 
)
static

Definition at line 1559 of file partition.c.

References elog, ERROR, get_opfamily_member(), OidIsValid, PartitionKeyData::partopcintype, PartitionKeyData::partopfamily, and PartitionKeyData::parttypid.

Referenced by make_partition_op_expr().

1561 {
1562  Oid operoid;
1563 
1564  /*
1565  * First check if there exists an operator of the given strategy, with
1566  * this column's type as both its lefttype and righttype, in the
1567  * partitioning operator family specified for the column.
1568  */
1569  operoid = get_opfamily_member(key->partopfamily[col],
1570  key->parttypid[col],
1571  key->parttypid[col],
1572  strategy);
1573 
1574  /*
1575  * If one doesn't exist, we must resort to using an operator in the same
1576  * operator family but with the operator class declared input type. It is
1577  * OK to do so, because the column's type is known to be binary-coercible
1578  * with the operator class input type (otherwise, the operator class in
1579  * question would not have been accepted as the partitioning operator
1580  * class). We must however inform the caller to wrap the non-Const
1581  * expression with a RelabelType node to denote the implicit coercion. It
1582  * ensures that the resulting expression structurally matches similarly
1583  * processed expressions within the optimizer.
1584  */
1585  if (!OidIsValid(operoid))
1586  {
1587  operoid = get_opfamily_member(key->partopfamily[col],
1588  key->partopcintype[col],
1589  key->partopcintype[col],
1590  strategy);
1591  if (!OidIsValid(operoid))
1592  elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
1593  strategy, key->partopcintype[col], key->partopcintype[col],
1594  key->partopfamily[col]);
1595  *need_relabel = true;
1596  }
1597  else
1598  *need_relabel = false;
1599 
1600  return operoid;
1601 }
Oid * partopfamily
Definition: rel.h:61
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:594
#define ERROR
Definition: elog.h:43
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
Oid * parttypid
Definition: rel.h:69
Oid * partopcintype
Definition: rel.h:62
#define elog
Definition: elog.h:219

◆ get_partition_parent()

Oid get_partition_parent ( Oid  relid)

Definition at line 1382 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 ATExecAttachPartitionIdx(), ATExecDetachPartition(), ATExecDropNotNull(), generate_partition_qual(), heap_drop_with_catalog(), RangeVarCallbackForDropRelation(), and validatePartitionedIndex().

1383 {
1384  Form_pg_inherits form;
1385  Relation catalogRelation;
1386  SysScanDesc scan;
1387  ScanKeyData key[2];
1388  HeapTuple tuple;
1389  Oid result;
1390 
1391  catalogRelation = heap_open(InheritsRelationId, AccessShareLock);
1392 
1393  ScanKeyInit(&key[0],
1395  BTEqualStrategyNumber, F_OIDEQ,
1396  ObjectIdGetDatum(relid));
1397  ScanKeyInit(&key[1],
1399  BTEqualStrategyNumber, F_INT4EQ,
1400  Int32GetDatum(1));
1401 
1402  scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true,
1403  NULL, 2, key);
1404 
1405  tuple = systable_getnext(scan);
1406  if (!HeapTupleIsValid(tuple))
1407  elog(ERROR, "could not find tuple for parent of relation %u", relid);
1408 
1409  form = (Form_pg_inherits) GETSTRUCT(tuple);
1410  result = form->inhparent;
1411 
1412  systable_endscan(scan);
1413  heap_close(catalogRelation, AccessShareLock);
1414 
1415  return result;
1416 }
#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:490
#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:462
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 1525 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().

1526 {
1527  Relation rel = heap_open(relid, AccessShareLock);
1528  Expr *result = NULL;
1529  List *and_args;
1530 
1531  /* Do the work only if this relation is a partition. */
1532  if (rel->rd_rel->relispartition)
1533  {
1534  and_args = generate_partition_qual(rel);
1535 
1536  if (and_args == NIL)
1537  result = NULL;
1538  else if (list_length(and_args) > 1)
1539  result = makeBoolExpr(AND_EXPR, and_args, -1);
1540  else
1541  result = linitial(and_args);
1542  }
1543 
1544  /* Keep the lock. */
1545  heap_close(rel, NoLock);
1546 
1547  return result;
1548 }
#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:2478
Definition: pg_list.h:45

◆ get_proposed_default_constraint()

List* get_proposed_default_constraint ( List new_part_constraints)

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

3167 {
3168  Expr *defPartConstraint;
3169 
3170  defPartConstraint = make_ands_explicit(new_part_constraints);
3171 
3172  /*
3173  * Derive the partition constraints of default partition by negating the
3174  * given partition constraints. The partition constraint never evaluates
3175  * to NULL, so negating it like this is safe.
3176  */
3177  defPartConstraint = makeBoolExpr(NOT_EXPR,
3178  list_make1(defPartConstraint),
3179  -1);
3180  defPartConstraint =
3181  (Expr *) eval_const_expressions(NULL,
3182  (Node *) defPartConstraint);
3183  defPartConstraint = canonicalize_qual(defPartConstraint);
3184 
3185  return list_make1(defPartConstraint);
3186 }
Definition: nodes.h:513
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2462
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:368
Expr * make_ands_explicit(List *andclauses)
Definition: clauses.c:370
#define list_make1(x1)
Definition: pg_list.h:139
Expr * canonicalize_qual(Expr *qual)
Definition: prepqual.c:286

◆ get_qual_for_hash()

static List * get_qual_for_hash ( Relation  parent,
PartitionBoundSpec spec 
)
static

Definition at line 1725 of file partition.c.

References generate_unaccent_rules::args, BOOLOID, COERCE_EXPLICIT_CALL, copyObject, i, Int32GetDatum, INT4OID, InvalidOid, lappend(), lfirst, list_head(), list_make1, list_make3, lnext, makeConst(), makeFuncExpr(), makeVar(), PartitionBoundSpec::modulus, ObjectIdGetDatum, OIDOID, PartitionKeyData::partattrs, PartitionKeyData::partexprs, PartitionKeyData::partnatts, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, PartitionKeyData::parttypmod, RelationGetPartitionKey, RelationGetRelid, and PartitionBoundSpec::remainder.

Referenced by get_qual_from_partbound().

1726 {
1727  PartitionKey key = RelationGetPartitionKey(parent);
1728  FuncExpr *fexpr;
1729  Node *relidConst;
1730  Node *modulusConst;
1731  Node *remainderConst;
1732  List *args;
1733  ListCell *partexprs_item;
1734  int i;
1735 
1736  /* Fixed arguments. */
1737  relidConst = (Node *) makeConst(OIDOID,
1738  -1,
1739  InvalidOid,
1740  sizeof(Oid),
1742  false,
1743  true);
1744 
1745  modulusConst = (Node *) makeConst(INT4OID,
1746  -1,
1747  InvalidOid,
1748  sizeof(int32),
1749  Int32GetDatum(spec->modulus),
1750  false,
1751  true);
1752 
1753  remainderConst = (Node *) makeConst(INT4OID,
1754  -1,
1755  InvalidOid,
1756  sizeof(int32),
1757  Int32GetDatum(spec->remainder),
1758  false,
1759  true);
1760 
1761  args = list_make3(relidConst, modulusConst, remainderConst);
1762  partexprs_item = list_head(key->partexprs);
1763 
1764  /* Add an argument for each key column. */
1765  for (i = 0; i < key->partnatts; i++)
1766  {
1767  Node *keyCol;
1768 
1769  /* Left operand */
1770  if (key->partattrs[i] != 0)
1771  {
1772  keyCol = (Node *) makeVar(1,
1773  key->partattrs[i],
1774  key->parttypid[i],
1775  key->parttypmod[i],
1776  key->parttypcoll[i],
1777  0);
1778  }
1779  else
1780  {
1781  keyCol = (Node *) copyObject(lfirst(partexprs_item));
1782  partexprs_item = lnext(partexprs_item);
1783  }
1784 
1785  args = lappend(args, keyCol);
1786  }
1787 
1788  fexpr = makeFuncExpr(F_SATISFIES_HASH_PARTITION,
1789  BOOLOID,
1790  args,
1791  InvalidOid,
1792  InvalidOid,
1794 
1795  return list_make1(fexpr);
1796 }
#define list_make3(x1, x2, x3)
Definition: pg_list.h:141
#define OIDOID
Definition: pg_type.h:328
#define INT4OID
Definition: pg_type.h:316
Definition: nodes.h:513
List * partexprs
Definition: rel.h:58
unsigned int Oid
Definition: postgres_ext.h:31
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:298
signed int int32
Definition: c.h:302
#define list_make1(x1)
Definition: pg_list.h:139
Oid * parttypcoll
Definition: rel.h:74
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Oid * parttypid
Definition: rel.h:69
List * lappend(List *list, void *datum)
Definition: list.c:128
AttrNumber * partattrs
Definition: rel.h:56
int16 partnatts
Definition: rel.h:55
int32 * parttypmod
Definition: rel.h:70
#define InvalidOid
Definition: postgres_ext.h:36
#define lfirst(lc)
Definition: pg_list.h:106
#define BOOLOID
Definition: pg_type.h:288
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
#define Int32GetDatum(X)
Definition: postgres.h:462
int i
#define copyObject(obj)
Definition: nodes.h:626
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:425
FuncExpr * makeFuncExpr(Oid funcid, Oid rettype, List *args, Oid funccollid, Oid inputcollid, CoercionForm fformat)
Definition: makefuncs.c:519

◆ get_qual_for_list()

static List * get_qual_for_list ( Relation  parent,
PartitionBoundSpec spec 
)
static

Definition at line 1808 of file partition.c.

References NullTest::arg, NullTest::argisrow, Assert, PartitionDescData::boundinfo, BTEqualStrategyNumber, castNode, Const::constisnull, copyObject, datumCopy(), PartitionBoundInfoData::datums, i, PartitionBoundSpec::is_default, IS_NOT_NULL, IS_NULL, lappend(), lfirst, linitial, list_make1, list_make2, PartitionBoundSpec::listdatums, NullTest::location, make_ands_explicit(), make_partition_op_expr(), makeBoolExpr(), makeConst(), makeNode, makeVar(), PartitionBoundInfoData::ndatums, NIL, NOT_EXPR, NullTest::nulltesttype, OR_EXPR, PartitionKeyData::partattrs, PartitionKeyData::partexprs, partition_bound_accepts_nulls, PartitionKeyData::partnatts, PartitionKeyData::parttypbyval, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, PartitionKeyData::parttyplen, PartitionKeyData::parttypmod, RelationGetPartitionDesc, RelationGetPartitionKey, and val.

Referenced by check_default_allows_bound(), and get_qual_from_partbound().

1809 {
1810  PartitionKey key = RelationGetPartitionKey(parent);
1811  List *result;
1812  Expr *keyCol;
1813  Expr *opexpr;
1814  NullTest *nulltest;
1815  ListCell *cell;
1816  List *elems = NIL;
1817  bool list_has_null = false;
1818 
1819  /*
1820  * Only single-column list partitioning is supported, so we are worried
1821  * only about the partition key with index 0.
1822  */
1823  Assert(key->partnatts == 1);
1824 
1825  /* Construct Var or expression representing the partition column */
1826  if (key->partattrs[0] != 0)
1827  keyCol = (Expr *) makeVar(1,
1828  key->partattrs[0],
1829  key->parttypid[0],
1830  key->parttypmod[0],
1831  key->parttypcoll[0],
1832  0);
1833  else
1834  keyCol = (Expr *) copyObject(linitial(key->partexprs));
1835 
1836  /*
1837  * For default list partition, collect datums for all the partitions. The
1838  * default partition constraint should check that the partition key is
1839  * equal to none of those.
1840  */
1841  if (spec->is_default)
1842  {
1843  int i;
1844  int ndatums = 0;
1845  PartitionDesc pdesc = RelationGetPartitionDesc(parent);
1846  PartitionBoundInfo boundinfo = pdesc->boundinfo;
1847 
1848  if (boundinfo)
1849  {
1850  ndatums = boundinfo->ndatums;
1851 
1852  if (partition_bound_accepts_nulls(boundinfo))
1853  list_has_null = true;
1854  }
1855 
1856  /*
1857  * If default is the only partition, there need not be any partition
1858  * constraint on it.
1859  */
1860  if (ndatums == 0 && !list_has_null)
1861  return NIL;
1862 
1863  for (i = 0; i < ndatums; i++)
1864  {
1865  Const *val;
1866 
1867  /*
1868  * Construct Const from known-not-null datum. We must be careful
1869  * to copy the value, because our result has to be able to outlive
1870  * the relcache entry we're copying from.
1871  */
1872  val = makeConst(key->parttypid[0],
1873  key->parttypmod[0],
1874  key->parttypcoll[0],
1875  key->parttyplen[0],
1876  datumCopy(*boundinfo->datums[i],
1877  key->parttypbyval[0],
1878  key->parttyplen[0]),
1879  false, /* isnull */
1880  key->parttypbyval[0]);
1881 
1882  elems = lappend(elems, val);
1883  }
1884  }
1885  else
1886  {
1887  /*
1888  * Create list of Consts for the allowed values, excluding any nulls.
1889  */
1890  foreach(cell, spec->listdatums)
1891  {
1892  Const *val = castNode(Const, lfirst(cell));
1893 
1894  if (val->constisnull)
1895  list_has_null = true;
1896  else
1897  elems = lappend(elems, copyObject(val));
1898  }
1899  }
1900 
1901  if (elems)
1902  {
1903  /*
1904  * Generate the operator expression from the non-null partition
1905  * values.
1906  */
1908  keyCol, (Expr *) elems);
1909  }
1910  else
1911  {
1912  /*
1913  * If there are no partition values, we don't need an operator
1914  * expression.
1915  */
1916  opexpr = NULL;
1917  }
1918 
1919  if (!list_has_null)
1920  {
1921  /*
1922  * Gin up a "col IS NOT NULL" test that will be AND'd with the main
1923  * expression. This might seem redundant, but the partition routing
1924  * machinery needs it.
1925  */
1926  nulltest = makeNode(NullTest);
1927  nulltest->arg = keyCol;
1928  nulltest->nulltesttype = IS_NOT_NULL;
1929  nulltest->argisrow = false;
1930  nulltest->location = -1;
1931 
1932  result = opexpr ? list_make2(nulltest, opexpr) : list_make1(nulltest);
1933  }
1934  else
1935  {
1936  /*
1937  * Gin up a "col IS NULL" test that will be OR'd with the main
1938  * expression.
1939  */
1940  nulltest = makeNode(NullTest);
1941  nulltest->arg = keyCol;
1942  nulltest->nulltesttype = IS_NULL;
1943  nulltest->argisrow = false;
1944  nulltest->location = -1;
1945 
1946  if (opexpr)
1947  {
1948  Expr *or;
1949 
1950  or = makeBoolExpr(OR_EXPR, list_make2(nulltest, opexpr), -1);
1951  result = list_make1(or);
1952  }
1953  else
1954  result = list_make1(nulltest);
1955  }
1956 
1957  /*
1958  * Note that, in general, applying NOT to a constraint expression doesn't
1959  * necessarily invert the set of rows it accepts, because NOT (NULL) is
1960  * NULL. However, the partition constraints we construct here never
1961  * evaluate to NULL, so applying NOT works as intended.
1962  */
1963  if (spec->is_default)
1964  {
1965  result = list_make1(make_ands_explicit(result));
1966  result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
1967  }
1968 
1969  return result;
1970 }
#define list_make2(x1, x2)
Definition: pg_list.h:140
#define NIL
Definition: pg_list.h:69
static Expr * make_partition_op_expr(PartitionKey key, int keynum, uint16 strategy, Expr *arg1, Expr *arg2)
Definition: partition.c:1609
#define castNode(_type_, nodeptr)
Definition: nodes.h:582
#define partition_bound_accepts_nulls(bi)
Definition: partition.c:109
List * partexprs
Definition: rel.h:58
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:298
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:368
PartitionBoundInfo boundinfo
Definition: partition.h:40
Expr * make_ands_explicit(List *andclauses)
Definition: clauses.c:370
#define list_make1(x1)
Definition: pg_list.h:139
Oid * parttypcoll
Definition: rel.h:74
#define linitial(l)
Definition: pg_list.h:111
Expr * arg
Definition: primnodes.h:1187
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
Oid * parttypid
Definition: rel.h:69
List * lappend(List *list, void *datum)
Definition: list.c:128
AttrNumber * partattrs
Definition: rel.h:56
int16 partnatts
Definition: rel.h:55
NullTestType nulltesttype
Definition: primnodes.h:1188
int32 * parttypmod
Definition: rel.h:70
#define makeNode(_type_)
Definition: nodes.h:561
bool * parttypbyval
Definition: rel.h:72
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
int16 * parttyplen
Definition: rel.h:71
int location
Definition: primnodes.h:1190
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
int i
bool argisrow
Definition: primnodes.h:1189
#define copyObject(obj)
Definition: nodes.h:626
Definition: pg_list.h:45
long val
Definition: informix.c:689
bool constisnull
Definition: primnodes.h:197
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define RelationGetPartitionDesc(relation)
Definition: rel.h:641

◆ get_qual_for_range()

static List * get_qual_for_range ( Relation  parent,
PartitionBoundSpec spec,
bool  for_default 
)
static

Definition at line 2117 of file partition.c.

References AND_EXPR, Anum_pg_class_relpartbound, Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, castNode, CreateExecutorState(), DatumGetBool, elog, ERROR, EState::es_query_cxt, ExecEvalExprSwitchContext(), ExecInitExpr(), fix_opfuncids(), for_both_cell, forboth, FreeExecutorState(), get_range_key_properties(), get_range_nulltest(), GetPerTupleExprContext, HeapTupleIsValid, i, PartitionBoundSpec::is_default, IsA, PartitionRangeDatum::kind, lappend(), lfirst, linitial, list_head(), list_length(), list_make1, lnext, PartitionBoundSpec::lowerdatums, make_partition_op_expr(), makeBoolConst(), makeBoolExpr(), MemoryContextSwitchTo(), NIL, NOT_EXPR, PartitionDescData::nparts, PartitionDescData::oids, OR_EXPR, PartitionKeyData::partexprs, PARTITION_RANGE_DATUM_MAXVALUE, PARTITION_RANGE_DATUM_MINVALUE, PARTITION_RANGE_DATUM_VALUE, PartitionKeyData::partnatts, RelationGetPartitionDesc, RelationGetPartitionKey, ReleaseSysCache(), RELOID, SearchSysCache1(), PartitionBoundInfoData::strategy, stringToNode(), SysCacheGetAttr(), TextDatumGetCString, and PartitionBoundSpec::upperdatums.

Referenced by check_default_allows_bound(), and get_qual_from_partbound().

2119 {
2120  List *result = NIL;
2121  ListCell *cell1,
2122  *cell2,
2123  *partexprs_item,
2124  *partexprs_item_saved;
2125  int i,
2126  j;
2127  PartitionRangeDatum *ldatum,
2128  *udatum;
2129  PartitionKey key = RelationGetPartitionKey(parent);
2130  Expr *keyCol;
2131  Const *lower_val,
2132  *upper_val;
2133  List *lower_or_arms,
2134  *upper_or_arms;
2135  int num_or_arms,
2136  current_or_arm;
2137  ListCell *lower_or_start_datum,
2138  *upper_or_start_datum;
2139  bool need_next_lower_arm,
2140  need_next_upper_arm;
2141 
2142  if (spec->is_default)
2143  {
2144  List *or_expr_args = NIL;
2145  PartitionDesc pdesc = RelationGetPartitionDesc(parent);
2146  Oid *inhoids = pdesc->oids;
2147  int nparts = pdesc->nparts,
2148  i;
2149 
2150  for (i = 0; i < nparts; i++)
2151  {
2152  Oid inhrelid = inhoids[i];
2153  HeapTuple tuple;
2154  Datum datum;
2155  bool isnull;
2156  PartitionBoundSpec *bspec;
2157 
2158  tuple = SearchSysCache1(RELOID, inhrelid);
2159  if (!HeapTupleIsValid(tuple))
2160  elog(ERROR, "cache lookup failed for relation %u", inhrelid);
2161 
2162  datum = SysCacheGetAttr(RELOID, tuple,
2164  &isnull);
2165 
2166  Assert(!isnull);
2167  bspec = (PartitionBoundSpec *)
2169  if (!IsA(bspec, PartitionBoundSpec))
2170  elog(ERROR, "expected PartitionBoundSpec");
2171 
2172  if (!bspec->is_default)
2173  {
2174  List *part_qual;
2175 
2176  part_qual = get_qual_for_range(parent, bspec, true);
2177 
2178  /*
2179  * AND the constraints of the partition and add to
2180  * or_expr_args
2181  */
2182  or_expr_args = lappend(or_expr_args, list_length(part_qual) > 1
2183  ? makeBoolExpr(AND_EXPR, part_qual, -1)
2184  : linitial(part_qual));
2185  }
2186  ReleaseSysCache(tuple);
2187  }
2188 
2189  if (or_expr_args != NIL)
2190  {
2191  Expr *other_parts_constr;
2192 
2193  /*
2194  * Combine the constraints obtained for non-default partitions
2195  * using OR. As requested, each of the OR's args doesn't include
2196  * the NOT NULL test for partition keys (which is to avoid its
2197  * useless repetition). Add the same now.
2198  */
2199  other_parts_constr =
2202  list_length(or_expr_args) > 1
2203  ? makeBoolExpr(OR_EXPR, or_expr_args,
2204  -1)
2205  : linitial(or_expr_args)),
2206  -1);
2207 
2208  /*
2209  * Finally, the default partition contains everything *NOT*
2210  * contained in the non-default partitions.
2211  */
2212  result = list_make1(makeBoolExpr(NOT_EXPR,
2213  list_make1(other_parts_constr), -1));
2214  }
2215 
2216  return result;
2217  }
2218 
2219  lower_or_start_datum = list_head(spec->lowerdatums);
2220  upper_or_start_datum = list_head(spec->upperdatums);
2221  num_or_arms = key->partnatts;
2222 
2223  /*
2224  * If it is the recursive call for default, we skip the get_range_nulltest
2225  * to avoid accumulating the NullTest on the same keys for each partition.
2226  */
2227  if (!for_default)
2228  result = get_range_nulltest(key);
2229 
2230  /*
2231  * Iterate over the key columns and check if the corresponding lower and
2232  * upper datums are equal using the btree equality operator for the
2233  * column's type. If equal, we emit single keyCol = common_value
2234  * expression. Starting from the first column for which the corresponding
2235  * lower and upper bound datums are not equal, we generate OR expressions
2236  * as shown in the function's header comment.
2237  */
2238  i = 0;
2239  partexprs_item = list_head(key->partexprs);
2240  partexprs_item_saved = partexprs_item; /* placate compiler */
2241  forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
2242  {
2243  EState *estate;
2244  MemoryContext oldcxt;
2245  Expr *test_expr;
2246  ExprState *test_exprstate;
2247  Datum test_result;
2248  bool isNull;
2249 
2250  ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
2251  udatum = castNode(PartitionRangeDatum, lfirst(cell2));
2252 
2253  /*
2254  * Since get_range_key_properties() modifies partexprs_item, and we
2255  * might need to start over from the previous expression in the later
2256  * part of this function, save away the current value.
2257  */
2258  partexprs_item_saved = partexprs_item;
2259 
2260  get_range_key_properties(key, i, ldatum, udatum,
2261  &partexprs_item,
2262  &keyCol,
2263  &lower_val, &upper_val);
2264 
2265  /*
2266  * If either value is NULL, the corresponding partition bound is
2267  * either MINVALUE or MAXVALUE, and we treat them as unequal, because
2268  * even if they're the same, there is no common value to equate the
2269  * key column with.
2270  */
2271  if (!lower_val || !upper_val)
2272  break;
2273 
2274  /* Create the test expression */
2275  estate = CreateExecutorState();
2276  oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
2277  test_expr = make_partition_op_expr(key, i, BTEqualStrategyNumber,
2278  (Expr *) lower_val,
2279  (Expr *) upper_val);
2280  fix_opfuncids((Node *) test_expr);
2281  test_exprstate = ExecInitExpr(test_expr, NULL);
2282  test_result = ExecEvalExprSwitchContext(test_exprstate,
2283  GetPerTupleExprContext(estate),
2284  &isNull);
2285  MemoryContextSwitchTo(oldcxt);
2286  FreeExecutorState(estate);
2287 
2288  /* If not equal, go generate the OR expressions */
2289  if (!DatumGetBool(test_result))
2290  break;
2291 
2292  /*
2293  * The bounds for the last key column can't be equal, because such a
2294  * range partition would never be allowed to be defined (it would have
2295  * an empty range otherwise).
2296  */
2297  if (i == key->partnatts - 1)
2298  elog(ERROR, "invalid range bound specification");
2299 
2300  /* Equal, so generate keyCol = lower_val expression */
2301  result = lappend(result,
2303  keyCol, (Expr *) lower_val));
2304 
2305  i++;
2306  }
2307 
2308  /* First pair of lower_val and upper_val that are not equal. */
2309  lower_or_start_datum = cell1;
2310  upper_or_start_datum = cell2;
2311 
2312  /* OR will have as many arms as there are key columns left. */
2313  num_or_arms = key->partnatts - i;
2314  current_or_arm = 0;
2315  lower_or_arms = upper_or_arms = NIL;
2316  need_next_lower_arm = need_next_upper_arm = true;
2317  while (current_or_arm < num_or_arms)
2318  {
2319  List *lower_or_arm_args = NIL,
2320  *upper_or_arm_args = NIL;
2321 
2322  /* Restart scan of columns from the i'th one */
2323  j = i;
2324  partexprs_item = partexprs_item_saved;
2325 
2326  for_both_cell(cell1, lower_or_start_datum, cell2, upper_or_start_datum)
2327  {
2328  PartitionRangeDatum *ldatum_next = NULL,
2329  *udatum_next = NULL;
2330 
2331  ldatum = castNode(PartitionRangeDatum, lfirst(cell1));
2332  if (lnext(cell1))
2333  ldatum_next = castNode(PartitionRangeDatum,
2334  lfirst(lnext(cell1)));
2335  udatum = castNode(PartitionRangeDatum, lfirst(cell2));
2336  if (lnext(cell2))
2337  udatum_next = castNode(PartitionRangeDatum,
2338  lfirst(lnext(cell2)));
2339  get_range_key_properties(key, j, ldatum, udatum,
2340  &partexprs_item,
2341  &keyCol,
2342  &lower_val, &upper_val);
2343 
2344  if (need_next_lower_arm && lower_val)
2345  {
2346  uint16 strategy;
2347 
2348  /*
2349  * For the non-last columns of this arm, use the EQ operator.
2350  * For the last column of this arm, use GT, unless this is the
2351  * last column of the whole bound check, or the next bound
2352  * datum is MINVALUE, in which case use GE.
2353  */
2354  if (j - i < current_or_arm)
2355  strategy = BTEqualStrategyNumber;
2356  else if (j == key->partnatts - 1 ||
2357  (ldatum_next &&
2358  ldatum_next->kind == PARTITION_RANGE_DATUM_MINVALUE))
2359  strategy = BTGreaterEqualStrategyNumber;
2360  else
2361  strategy = BTGreaterStrategyNumber;
2362 
2363  lower_or_arm_args = lappend(lower_or_arm_args,
2364  make_partition_op_expr(key, j,
2365  strategy,
2366  keyCol,
2367  (Expr *) lower_val));
2368  }
2369 
2370  if (need_next_upper_arm && upper_val)
2371  {
2372  uint16 strategy;
2373 
2374  /*
2375  * For the non-last columns of this arm, use the EQ operator.
2376  * For the last column of this arm, use LT, unless the next
2377  * bound datum is MAXVALUE, in which case use LE.
2378  */
2379  if (j - i < current_or_arm)
2380  strategy = BTEqualStrategyNumber;
2381  else if (udatum_next &&
2382  udatum_next->kind == PARTITION_RANGE_DATUM_MAXVALUE)
2383  strategy = BTLessEqualStrategyNumber;
2384  else
2385  strategy = BTLessStrategyNumber;
2386 
2387  upper_or_arm_args = lappend(upper_or_arm_args,
2388  make_partition_op_expr(key, j,
2389  strategy,
2390  keyCol,
2391  (Expr *) upper_val));
2392  }
2393 
2394  /*
2395  * Did we generate enough of OR's arguments? First arm considers
2396  * the first of the remaining columns, second arm considers first
2397  * two of the remaining columns, and so on.
2398  */
2399  ++j;
2400  if (j - i > current_or_arm)
2401  {
2402  /*
2403  * We must not emit any more arms if the new column that will
2404  * be considered is unbounded, or this one was.
2405  */
2406  if (!lower_val || !ldatum_next ||
2407  ldatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
2408  need_next_lower_arm = false;
2409  if (!upper_val || !udatum_next ||
2410  udatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
2411  need_next_upper_arm = false;
2412  break;
2413  }
2414  }
2415 
2416  if (lower_or_arm_args != NIL)
2417  lower_or_arms = lappend(lower_or_arms,
2418  list_length(lower_or_arm_args) > 1
2419  ? makeBoolExpr(AND_EXPR, lower_or_arm_args, -1)
2420  : linitial(lower_or_arm_args));
2421 
2422  if (upper_or_arm_args != NIL)
2423  upper_or_arms = lappend(upper_or_arms,
2424  list_length(upper_or_arm_args) > 1
2425  ? makeBoolExpr(AND_EXPR, upper_or_arm_args, -1)
2426  : linitial(upper_or_arm_args));
2427 
2428  /* If no work to do in the next iteration, break away. */
2429  if (!need_next_lower_arm && !need_next_upper_arm)
2430  break;
2431 
2432  ++current_or_arm;
2433  }
2434 
2435  /*
2436  * Generate the OR expressions for each of lower and upper bounds (if
2437  * required), and append to the list of implicitly ANDed list of
2438  * expressions.
2439  */
2440  if (lower_or_arms != NIL)
2441  result = lappend(result,
2442  list_length(lower_or_arms) > 1
2443  ? makeBoolExpr(OR_EXPR, lower_or_arms, -1)
2444  : linitial(lower_or_arms));
2445  if (upper_or_arms != NIL)
2446  result = lappend(result,
2447  list_length(upper_or_arms) > 1
2448  ? makeBoolExpr(OR_EXPR, upper_or_arms, -1)
2449  : linitial(upper_or_arms));
2450 
2451  /*
2452  * As noted above, for non-default, we return list with constant TRUE. If
2453  * the result is NIL during the recursive call for default, it implies
2454  * this is the only other partition which can hold every value of the key
2455  * except NULL. Hence we return the NullTest result skipped earlier.
2456  */
2457  if (result == NIL)
2458  result = for_default
2459  ? get_range_nulltest(key)
2461 
2462  return result;
2463 }
#define NIL
Definition: pg_list.h:69
void * stringToNode(char *str)
Definition: read.c:38
#define IsA(nodeptr, _type_)
Definition: nodes.h:564
static Expr * make_partition_op_expr(PartitionKey key, int keynum, uint16 strategy, Expr *arg1, Expr *arg2)
Definition: partition.c:1609
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:297
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:180
#define castNode(_type_, nodeptr)
Definition: nodes.h:582
void fix_opfuncids(Node *node)
Definition: nodeFuncs.c:1582
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
PartitionRangeDatumKind kind
Definition: parsenodes.h:842
Definition: nodes.h:513
#define false
Definition: c.h:273
List * partexprs
Definition: rel.h:58
unsigned int Oid
Definition: postgres_ext.h:31
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:368
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
#define list_make1(x1)
Definition: pg_list.h:139
void FreeExecutorState(EState *estate)
Definition: execUtils.c:185
#define GetPerTupleExprContext(estate)
Definition: executor.h:490
#define true
Definition: c.h:269
unsigned short uint16
Definition: c.h:313
MemoryContext es_query_cxt
Definition: execnodes.h:488
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
Node * makeBoolConst(bool value, bool isnull)
Definition: makefuncs.c:356
static void get_range_key_properties(PartitionKey key, int keynum, PartitionRangeDatum *ldatum, PartitionRangeDatum *udatum, ListCell **partexprs_item, Expr **keyCol, Const **lower_val, Const **upper_val)
Definition: partition.c:1988
#define DatumGetBool(X)
Definition: postgres.h:376
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partition.c:2117
EState * CreateExecutorState(void)
Definition: execUtils.c:80
List * lappend(List *list, void *datum)
Definition: list.c:128
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define TextDatumGetCString(d)
Definition: builtins.h:92
uintptr_t Datum
Definition: postgres.h:365
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 for_both_cell(cell1, initcell1, cell2, initcell2)
Definition: pg_list.h:194
#define Anum_pg_class_relpartbound
Definition: pg_class.h:135
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
int i
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:118
#define elog
Definition: elog.h:219
static List * get_range_nulltest(PartitionKey key)
Definition: partition.c:2032
#define BTLessStrategyNumber
Definition: stratnum.h:29
Definition: pg_list.h:45
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
#define RelationGetPartitionDesc(relation)
Definition: rel.h:641

◆ get_qual_from_partbound()

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

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

1426 {
1427  PartitionKey key = RelationGetPartitionKey(parent);
1428  List *my_qual = NIL;
1429 
1430  Assert(key != NULL);
1431 
1432  switch (key->strategy)
1433  {
1436  my_qual = get_qual_for_hash(parent, spec);
1437  break;
1438 
1441  my_qual = get_qual_for_list(parent, spec);
1442  break;
1443 
1446  my_qual = get_qual_for_range(parent, spec, false);
1447  break;
1448 
1449  default:
1450  elog(ERROR, "unexpected partition strategy: %d",
1451  (int) key->strategy);
1452  }
1453 
1454  return my_qual;
1455 }
#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:1808
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partition.c:2117
static List * get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
Definition: partition.c:1725
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:795
#define Assert(condition)
Definition: c.h:688
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:796
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:797
#define elog
Definition: elog.h:219
Definition: pg_list.h:45

◆ get_range_key_properties()

static void get_range_key_properties ( PartitionKey  key,
int  keynum,
PartitionRangeDatum ldatum,
PartitionRangeDatum udatum,
ListCell **  partexprs_item,
Expr **  keyCol,
Const **  lower_val,
Const **  upper_val 
)
static

Definition at line 1988 of file partition.c.

References castNode, copyObject, elog, ERROR, PartitionRangeDatum::kind, lfirst, lnext, makeVar(), PartitionKeyData::partattrs, PARTITION_RANGE_DATUM_VALUE, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, PartitionKeyData::parttypmod, and PartitionRangeDatum::value.

Referenced by get_qual_for_range().

1994 {
1995  /* Get partition key expression for this column */
1996  if (key->partattrs[keynum] != 0)
1997  {
1998  *keyCol = (Expr *) makeVar(1,
1999  key->partattrs[keynum],
2000  key->parttypid[keynum],
2001  key->parttypmod[keynum],
2002  key->parttypcoll[keynum],
2003  0);
2004  }
2005  else
2006  {
2007  if (*partexprs_item == NULL)
2008  elog(ERROR, "wrong number of partition key expressions");
2009  *keyCol = copyObject(lfirst(*partexprs_item));
2010  *partexprs_item = lnext(*partexprs_item);
2011  }
2012 
2013  /* Get appropriate Const nodes for the bounds */
2014  if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
2015  *lower_val = castNode(Const, copyObject(ldatum->value));
2016  else
2017  *lower_val = NULL;
2018 
2019  if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
2020  *upper_val = castNode(Const, copyObject(udatum->value));
2021  else
2022  *upper_val = NULL;
2023 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:582
PartitionRangeDatumKind kind
Definition: parsenodes.h:842
Oid * parttypcoll
Definition: rel.h:74
#define ERROR
Definition: elog.h:43
#define lnext(lc)
Definition: pg_list.h:105
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Oid * parttypid
Definition: rel.h:69
AttrNumber * partattrs
Definition: rel.h:56
int32 * parttypmod
Definition: rel.h:70
#define lfirst(lc)
Definition: pg_list.h:106
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:626

◆ get_range_nulltest()

static List * get_range_nulltest ( PartitionKey  key)
static

Definition at line 2032 of file partition.c.

References NullTest::arg, NullTest::argisrow, copyObject, elog, ERROR, i, IS_NOT_NULL, lappend(), lfirst, list_head(), lnext, NullTest::location, makeNode, makeVar(), NIL, NullTest::nulltesttype, PartitionKeyData::partattrs, PartitionKeyData::partexprs, PartitionKeyData::partnatts, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, and PartitionKeyData::parttypmod.

Referenced by get_qual_for_range().

2033 {
2034  List *result = NIL;
2035  NullTest *nulltest;
2036  ListCell *partexprs_item;
2037  int i;
2038 
2039  partexprs_item = list_head(key->partexprs);
2040  for (i = 0; i < key->partnatts; i++)
2041  {
2042  Expr *keyCol;
2043 
2044  if (key->partattrs[i] != 0)
2045  {
2046  keyCol = (Expr *) makeVar(1,
2047  key->partattrs[i],
2048  key->parttypid[i],
2049  key->parttypmod[i],
2050  key->parttypcoll[i],
2051  0);
2052  }
2053  else
2054  {
2055  if (partexprs_item == NULL)
2056  elog(ERROR, "wrong number of partition key expressions");
2057  keyCol = copyObject(lfirst(partexprs_item));
2058  partexprs_item = lnext(partexprs_item);
2059  }
2060 
2061  nulltest = makeNode(NullTest);
2062  nulltest->arg = keyCol;
2063  nulltest->nulltesttype = IS_NOT_NULL;
2064  nulltest->argisrow = false;
2065  nulltest->location = -1;
2066  result = lappend(result, nulltest);
2067  }
2068 
2069  return result;
2070 }
#define NIL
Definition: pg_list.h:69
List * partexprs
Definition: rel.h:58
Oid * parttypcoll
Definition: rel.h:74
#define ERROR
Definition: elog.h:43
Expr * arg
Definition: primnodes.h:1187
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Oid * parttypid
Definition: rel.h:69
List * lappend(List *list, void *datum)
Definition: list.c:128
AttrNumber * partattrs
Definition: rel.h:56
int16 partnatts
Definition: rel.h:55
NullTestType nulltesttype
Definition: primnodes.h:1188
int32 * parttypmod
Definition: rel.h:70
#define makeNode(_type_)
Definition: nodes.h:561
#define lfirst(lc)
Definition: pg_list.h:106
int location
Definition: primnodes.h:1190
int i
bool argisrow
Definition: primnodes.h:1189
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:626
Definition: pg_list.h:45

◆ has_partition_attrs()

bool has_partition_attrs ( Relation  rel,
Bitmapset attnums,
bool used_in_expr 
)

Definition at line 2658 of file partition.c.

References bms_is_member(), bms_overlap(), FirstLowInvalidHeapAttributeNumber, get_partition_col_attnum(), get_partition_exprs(), get_partition_natts(), i, lfirst, list_head(), lnext, pull_varattnos(), RelationData::rd_rel, RelationGetPartitionKey, and RELKIND_PARTITIONED_TABLE.

Referenced by ATExecDropColumn(), ATPrepAlterColumnType(), and expand_partitioned_rtentry().

2660 {
2661  PartitionKey key;
2662  int partnatts;
2663  List *partexprs;
2664  ListCell *partexprs_item;
2665  int i;
2666 
2667  if (attnums == NULL || rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
2668  return false;
2669 
2670  key = RelationGetPartitionKey(rel);
2671  partnatts = get_partition_natts(key);
2672  partexprs = get_partition_exprs(key);
2673 
2674  partexprs_item = list_head(partexprs);
2675  for (i = 0; i < partnatts; i++)
2676  {
2677  AttrNumber partattno = get_partition_col_attnum(key, i);
2678 
2679  if (partattno != 0)
2680  {
2682  attnums))
2683  {
2684  if (used_in_expr)
2685  *used_in_expr = false;
2686  return true;
2687  }
2688  }
2689  else
2690  {
2691  /* Arbitrary expression */
2692  Node *expr = (Node *) lfirst(partexprs_item);
2693  Bitmapset *expr_attrs = NULL;
2694 
2695  /* Find all attributes referenced */
2696  pull_varattnos(expr, 1, &expr_attrs);
2697  partexprs_item = lnext(partexprs_item);
2698 
2699  if (bms_overlap(attnums, expr_attrs))
2700  {
2701  if (used_in_expr)
2702  *used_in_expr = true;
2703  return true;
2704  }
2705  }
2706  }
2707 
2708  return false;
2709 }
Definition: nodes.h:513
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
Form_pg_class rd_rel
Definition: rel.h:114
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:219
static int get_partition_natts(PartitionKey key)
Definition: rel.h:605
static int16 get_partition_col_attnum(PartitionKey key, int col)
Definition: rel.h:620
static List * get_partition_exprs(PartitionKey key)
Definition: rel.h:611
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define lfirst(lc)
Definition: pg_list.h:106
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:487
int i
Definition: pg_list.h:45
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:464
int16 AttrNumber
Definition: attnum.h:21

◆ make_one_range_bound()

static PartitionRangeBound * make_one_range_bound ( PartitionKey  key,
int  index,
List datums,
bool  lower 
)
static

Definition at line 2768 of file partition.c.

References Assert, castNode, Const::constisnull, Const::constvalue, PartitionRangeBound::datums, elog, ERROR, i, PartitionRangeBound::index, PartitionRangeBound::kind, PartitionRangeDatum::kind, lfirst, lower(), PartitionRangeBound::lower, NIL, palloc0(), PARTITION_RANGE_DATUM_VALUE, PartitionKeyData::partnatts, val, and PartitionRangeDatum::value.

Referenced by check_new_partition_bound(), and RelationBuildPartitionDesc().

2769 {
2770  PartitionRangeBound *bound;
2771  ListCell *lc;
2772  int i;
2773 
2774  Assert(datums != NIL);
2775 
2776  bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
2777  bound->index = index;
2778  bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
2779  bound->kind = (PartitionRangeDatumKind *) palloc0(key->partnatts *
2780  sizeof(PartitionRangeDatumKind));
2781  bound->lower = lower;
2782 
2783  i = 0;
2784  foreach(lc, datums)
2785  {
2787 
2788  /* What's contained in this range datum? */
2789  bound->kind[i] = datum->kind;
2790 
2791  if (datum->kind == PARTITION_RANGE_DATUM_VALUE)
2792  {
2793  Const *val = castNode(Const, datum->value);
2794 
2795  if (val->constisnull)
2796  elog(ERROR, "invalid range bound datum");
2797  bound->datums[i] = val->constvalue;
2798  }
2799 
2800  i++;
2801  }
2802 
2803  return bound;
2804 }
Datum constvalue
Definition: primnodes.h:196
#define NIL
Definition: pg_list.h:69
PartitionRangeDatumKind * kind
Definition: partition.c:137
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:44
#define castNode(_type_, nodeptr)
Definition: nodes.h:582
PartitionRangeDatumKind
Definition: parsenodes.h:831
PartitionRangeDatumKind kind
Definition: parsenodes.h:842
Definition: type.h:89
#define ERROR
Definition: elog.h:43
void * palloc0(Size size)
Definition: mcxt.c:864
uintptr_t Datum
Definition: postgres.h:365
int16 partnatts
Definition: rel.h:55
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
int i
#define elog
Definition: elog.h:219
long val
Definition: informix.c:689
bool constisnull
Definition: primnodes.h:197

◆ make_partition_op_expr()

static Expr * make_partition_op_expr ( PartitionKey  key,
int  keynum,
uint16  strategy,
Expr arg1,
Expr arg2 
)
static

Definition at line 1609 of file partition.c.

References ScalarArrayOpExpr::args, ArrayExpr::array_collid, ArrayExpr::array_typeid, Assert, BOOLOID, COERCE_EXPLICIT_CAST, ArrayExpr::element_typeid, ArrayExpr::elements, elog, ERROR, get_array_type(), get_opcode(), get_partition_operator(), ScalarArrayOpExpr::inputcollid, InvalidOid, IsA, lappend(), lfirst, linitial, list_length(), list_make2, ScalarArrayOpExpr::location, ArrayExpr::location, make_opclause(), makeBoolExpr(), makeNode, makeRelabelType(), ArrayExpr::multidims, NIL, ScalarArrayOpExpr::opfuncid, ScalarArrayOpExpr::opno, OR_EXPR, PartitionKeyData::partcollation, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, PartitionKeyData::partopcintype, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, PartitionKeyData::strategy, type_is_array, and ScalarArrayOpExpr::useOr.

Referenced by get_qual_for_list(), and get_qual_for_range().

1611 {
1612  Oid operoid;
1613  bool need_relabel = false;
1614  Expr *result = NULL;
1615 
1616  /* Get the correct btree operator for this partitioning column */
1617  operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
1618 
1619  /*
1620  * Chosen operator may be such that the non-Const operand needs to be
1621  * coerced, so apply the same; see the comment in
1622  * get_partition_operator().
1623  */
1624  if (!IsA(arg1, Const) &&
1625  (need_relabel ||
1626  key->partcollation[keynum] != key->parttypcoll[keynum]))
1627  arg1 = (Expr *) makeRelabelType(arg1,
1628  key->partopcintype[keynum],
1629  -1,
1630  key->partcollation[keynum],
1632 
1633  /* Generate the actual expression */
1634  switch (key->strategy)
1635  {
1637  {
1638  List *elems = (List *) arg2;
1639  int nelems = list_length(elems);
1640 
1641  Assert(nelems >= 1);
1642  Assert(keynum == 0);
1643 
1644  if (nelems > 1 &&
1645  !type_is_array(key->parttypid[keynum]))
1646  {
1647  ArrayExpr *arrexpr;
1648  ScalarArrayOpExpr *saopexpr;
1649 
1650  /* Construct an ArrayExpr for the right-hand inputs */
1651  arrexpr = makeNode(ArrayExpr);
1652  arrexpr->array_typeid =
1653  get_array_type(key->parttypid[keynum]);
1654  arrexpr->array_collid = key->parttypcoll[keynum];
1655  arrexpr->element_typeid = key->parttypid[keynum];
1656  arrexpr->elements = elems;
1657  arrexpr->multidims = false;
1658  arrexpr->location = -1;
1659 
1660  /* Build leftop = ANY (rightop) */
1661  saopexpr = makeNode(ScalarArrayOpExpr);
1662  saopexpr->opno = operoid;
1663  saopexpr->opfuncid = get_opcode(operoid);
1664  saopexpr->useOr = true;
1665  saopexpr->inputcollid = key->partcollation[keynum];
1666  saopexpr->args = list_make2(arg1, arrexpr);
1667  saopexpr->location = -1;
1668 
1669  result = (Expr *) saopexpr;
1670  }
1671  else
1672  {
1673  List *elemops = NIL;
1674  ListCell *lc;
1675 
1676  foreach (lc, elems)
1677  {
1678  Expr *elem = lfirst(lc),
1679  *elemop;
1680 
1681  elemop = make_opclause(operoid,
1682  BOOLOID,
1683  false,
1684  arg1, elem,
1685  InvalidOid,
1686  key->partcollation[keynum]);
1687  elemops = lappend(elemops, elemop);
1688  }
1689 
1690  result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops);
1691  }
1692  break;
1693  }
1694 
1696  result = make_opclause(operoid,
1697  BOOLOID,
1698  false,
1699  arg1, arg2,
1700  InvalidOid,
1701  key->partcollation[keynum]);
1702  break;
1703 
1704  default:
1705  elog(ERROR, "invalid partitioning strategy");
1706  break;
1707  }
1708 
1709  return result;
1710 }
#define list_make2(x1, x2)
Definition: pg_list.h:140
bool multidims
Definition: primnodes.h:960
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:564
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2530
static Oid get_partition_operator(PartitionKey key, int col, StrategyNumber strategy, bool *need_relabel)
Definition: partition.c:1559
Oid array_typeid
Definition: primnodes.h:956
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition: clauses.c:175
char strategy
Definition: rel.h:54
unsigned int Oid
Definition: postgres_ext.h:31
Expr * makeBoolExpr(BoolExprType boolop, List *args, int location)
Definition: makefuncs.c:368
Oid * parttypcoll
Definition: rel.h:74
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
RelabelType * makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat)
Definition: makefuncs.c:401
List * elements
Definition: primnodes.h:959
Oid * parttypid
Definition: rel.h:69
List * lappend(List *list, void *datum)
Definition: list.c:128
Oid * partcollation
Definition: rel.h:66
int location
Definition: primnodes.h:961
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1079
#define makeNode(_type_)
Definition: nodes.h:561
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
Oid array_collid
Definition: primnodes.h:957
static int list_length(const List *l)
Definition: pg_list.h:89
#define type_is_array(typid)
Definition: lsyscache.h:180
#define BOOLOID
Definition: pg_type.h:288
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:796
Oid element_typeid
Definition: primnodes.h:958
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:797
Oid * partopcintype
Definition: rel.h:62
#define elog
Definition: elog.h:219
Definition: pg_list.h:45

◆ map_partition_varattnos()

List* map_partition_varattnos ( List expr,
int  fromrel_varno,
Relation  to_rel,
Relation  from_rel,
bool found_whole_row 
)

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

1478 {
1479  bool my_found_whole_row = false;
1480 
1481  if (expr != NIL)
1482  {
1483  AttrNumber *part_attnos;
1484 
1485  part_attnos = convert_tuples_by_name_map(RelationGetDescr(to_rel),
1486  RelationGetDescr(from_rel),
1487  gettext_noop("could not convert row type"));
1488  expr = (List *) map_variable_attnos((Node *) expr,
1489  fromrel_varno, 0,
1490  part_attnos,
1491  RelationGetDescr(from_rel)->natts,
1492  RelationGetForm(to_rel)->reltype,
1493  &my_found_whole_row);
1494  }
1495 
1496  if (found_whole_row)
1497  *found_whole_row = my_found_whole_row;
1498 
1499  return expr;
1500 }
#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:1025
Definition: nodes.h:513
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 860 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().

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

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

◆ partition_hash_bsearch()

static int partition_hash_bsearch ( PartitionKey  key,
PartitionBoundInfo  boundinfo,
int  modulus,
int  remainder 
)
static

Definition at line 3052 of file partition.c.

References DatumGetInt32, PartitionBoundInfoData::datums, PartitionBoundInfoData::ndatums, and partition_hbound_cmp().

Referenced by check_new_partition_bound().

3055 {
3056  int lo,
3057  hi,
3058  mid;
3059 
3060  lo = -1;
3061  hi = boundinfo->ndatums - 1;
3062  while (lo < hi)
3063  {
3064  int32 cmpval,
3065  bound_modulus,
3066  bound_remainder;
3067 
3068  mid = (lo + hi + 1) / 2;
3069  bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
3070  bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
3071  cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
3072  modulus, remainder);
3073  if (cmpval <= 0)
3074  {
3075  lo = mid;
3076 
3077  if (cmpval == 0)
3078  break;
3079  }
3080  else
3081  hi = mid - 1;
3082  }
3083 
3084  return lo;
3085 }
#define DatumGetInt32(X)
Definition: postgres.h:455
signed int int32
Definition: c.h:302
static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
Definition: partition.c:2732

◆ partition_hbound_cmp()

static int32 partition_hbound_cmp ( int  modulus1,
int  remainder1,
int  modulus2,
int  remainder2 
)
static

Definition at line 2732 of file partition.c.

Referenced by partition_hash_bsearch(), and qsort_partition_hbound_cmp().

2733 {
2734  if (modulus1 < modulus2)
2735  return -1;
2736  if (modulus1 > modulus2)
2737  return 1;
2738  if (modulus1 == modulus2 && remainder1 != remainder2)
2739  return (remainder1 > remainder2) ? 1 : -1;
2740  return 0;
2741 }

◆ partition_list_bsearch()

static int partition_list_bsearch ( PartitionKey  key,
PartitionBoundInfo  boundinfo,
Datum  value,
bool is_equal 
)
static

Definition at line 2923 of file partition.c.

References DatumGetInt32, PartitionBoundInfoData::datums, FunctionCall2Coll(), PartitionBoundInfoData::ndatums, PartitionKeyData::partcollation, and PartitionKeyData::partsupfunc.

Referenced by check_new_partition_bound(), and get_partition_for_tuple().

2926 {
2927  int lo,
2928  hi,
2929  mid;
2930 
2931  lo = -1;
2932  hi = boundinfo->ndatums - 1;
2933  while (lo < hi)
2934  {
2935  int32 cmpval;
2936 
2937  mid = (lo + hi + 1) / 2;
2938  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
2939  key->partcollation[0],
2940  boundinfo->datums[mid][0],
2941  value));
2942  if (cmpval <= 0)
2943  {
2944  lo = mid;
2945  *is_equal = (cmpval == 0);
2946  if (*is_equal)
2947  break;
2948  }
2949  else
2950  hi = mid - 1;
2951  }
2952 
2953  return lo;
2954 }
static struct @130 value
#define DatumGetInt32(X)
Definition: postgres.h:455
FmgrInfo * partsupfunc
Definition: rel.h:63
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1042
signed int int32
Definition: c.h:302
Oid * partcollation
Definition: rel.h:66

◆ partition_range_bsearch()

static int partition_range_bsearch ( PartitionKey  key,
PartitionBoundInfo  boundinfo,
PartitionRangeBound probe,
bool is_equal 
)
static

Definition at line 2966 of file partition.c.

References PartitionBoundInfoData::datums, PartitionBoundInfoData::indexes, PartitionBoundInfoData::kind, PartitionBoundInfoData::ndatums, and partition_rbound_cmp().

Referenced by check_new_partition_bound().

2969 {
2970  int lo,
2971  hi,
2972  mid;
2973 
2974  lo = -1;
2975  hi = boundinfo->ndatums - 1;
2976  while (lo < hi)
2977  {
2978  int32 cmpval;
2979 
2980  mid = (lo + hi + 1) / 2;
2981  cmpval = partition_rbound_cmp(key,
2982  boundinfo->datums[mid],
2983  boundinfo->kind[mid],
2984  (boundinfo->indexes[mid] == -1),
2985  probe);
2986  if (cmpval <= 0)
2987  {
2988  lo = mid;
2989  *is_equal = (cmpval == 0);
2990 
2991  if (*is_equal)
2992  break;
2993  }
2994  else
2995  hi = mid - 1;
2996  }
2997 
2998  return lo;
2999 }
PartitionRangeDatumKind ** kind
Definition: partition.c:99
signed int int32
Definition: c.h:302
static int32 partition_rbound_cmp(PartitionKey key, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partition.c:2831

◆ partition_range_datum_bsearch()

static int partition_range_datum_bsearch ( PartitionKey  key,
PartitionBoundInfo  boundinfo,
int  nvalues,
Datum values,
bool is_equal 
)
static

Definition at line 3010 of file partition.c.

References PartitionBoundInfoData::datums, PartitionBoundInfoData::kind, PartitionBoundInfoData::ndatums, and partition_rbound_datum_cmp().

Referenced by get_partition_for_tuple().

3013 {
3014  int lo,
3015  hi,
3016  mid;
3017 
3018  lo = -1;
3019  hi = boundinfo->ndatums - 1;
3020  while (lo < hi)
3021  {
3022  int32 cmpval;
3023 
3024  mid = (lo + hi + 1) / 2;
3025  cmpval = partition_rbound_datum_cmp(key,
3026  boundinfo->datums[mid],
3027  boundinfo->kind[mid],
3028  values,
3029  nvalues);
3030  if (cmpval <= 0)
3031  {
3032  lo = mid;
3033  *is_equal = (cmpval == 0);
3034 
3035  if (*is_equal)
3036  break;
3037  }
3038  else
3039  hi = mid - 1;
3040  }
3041 
3042  return lo;
3043 }
PartitionRangeDatumKind ** kind
Definition: partition.c:99
static int32 partition_rbound_datum_cmp(PartitionKey key, Datum *rb_datums, PartitionRangeDatumKind *rb_kind, Datum *tuple_datums, int n_tuple_datums)
Definition: partition.c:2889
signed int int32
Definition: c.h:302
static Datum values[MAXATTR]
Definition: bootstrap.c:164

◆ partition_rbound_cmp()

static int32 partition_rbound_cmp ( PartitionKey  key,
Datum datums1,
PartitionRangeDatumKind kind1,
bool  lower1,
PartitionRangeBound b2 
)
static

Definition at line 2831 of file partition.c.

References DatumGetInt32, PartitionRangeBound::datums, FunctionCall2Coll(), i, PartitionRangeBound::kind, PartitionRangeBound::lower, PartitionKeyData::partcollation, PARTITION_RANGE_DATUM_VALUE, PartitionKeyData::partnatts, and PartitionKeyData::partsupfunc.

Referenced by check_new_partition_bound(), partition_range_bsearch(), and qsort_partition_rbound_cmp().

2834 {
2835  int32 cmpval = 0; /* placate compiler */
2836  int i;
2837  Datum *datums2 = b2->datums;
2838  PartitionRangeDatumKind *kind2 = b2->kind;
2839  bool lower2 = b2->lower;
2840 
2841  for (i = 0; i < key->partnatts; i++)
2842  {
2843  /*
2844  * First, handle cases where the column is unbounded, which should not
2845  * invoke the comparison procedure, and should not consider any later
2846  * columns. Note that the PartitionRangeDatumKind enum elements
2847  * compare the same way as the values they represent.
2848  */
2849  if (kind1[i] < kind2[i])
2850  return -1;
2851  else if (kind1[i] > kind2[i])
2852  return 1;
2853  else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE)
2854 
2855  /*
2856  * The column bounds are both MINVALUE or both MAXVALUE. No later
2857  * columns should be considered, but we still need to compare
2858  * whether they are upper or lower bounds.
2859  */
2860  break;
2861 
2862  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
2863  key->partcollation[i],
2864  datums1[i],
2865  datums2[i]));
2866  if (cmpval != 0)
2867  break;
2868  }
2869 
2870  /*
2871  * If the comparison is anything other than equal, we're done. If they
2872  * compare equal though, we still have to consider whether the boundaries
2873  * are inclusive or exclusive. Exclusive one is considered smaller of the
2874  * two.
2875  */
2876  if (cmpval == 0 && lower1 != lower2)
2877  cmpval = lower1 ? 1 : -1;
2878 
2879  return cmpval;
2880 }
PartitionRangeDatumKind * kind
Definition: partition.c:137
#define DatumGetInt32(X)
Definition: postgres.h:455
FmgrInfo * partsupfunc
Definition: rel.h:63
PartitionRangeDatumKind
Definition: parsenodes.h:831
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1042
signed int int32
Definition: c.h:302
Oid * partcollation
Definition: rel.h:66
uintptr_t Datum
Definition: postgres.h:365
int16 partnatts
Definition: rel.h:55
int i

◆ partition_rbound_datum_cmp()

static int32 partition_rbound_datum_cmp ( PartitionKey  key,
Datum rb_datums,
PartitionRangeDatumKind rb_kind,
Datum tuple_datums,
int  n_tuple_datums 
)
static

Definition at line 2889 of file partition.c.

References DatumGetInt32, FunctionCall2Coll(), i, PartitionKeyData::partcollation, PARTITION_RANGE_DATUM_MAXVALUE, PARTITION_RANGE_DATUM_MINVALUE, and PartitionKeyData::partsupfunc.

Referenced by partition_range_datum_bsearch().

2892 {
2893  int i;
2894  int32 cmpval = -1;
2895 
2896  for (i = 0; i < n_tuple_datums; i++)
2897  {
2898  if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
2899  return -1;
2900  else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
2901  return 1;
2902 
2903  cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
2904  key->partcollation[i],
2905  rb_datums[i],
2906  tuple_datums[i]));
2907  if (cmpval != 0)
2908  break;
2909  }
2910 
2911  return cmpval;
2912 }
#define DatumGetInt32(X)
Definition: postgres.h:455
FmgrInfo * partsupfunc
Definition: rel.h:63
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1042
signed int int32
Definition: c.h:302
Oid * partcollation
Definition: rel.h:66
int i

◆ qsort_partition_hbound_cmp()

static int32 qsort_partition_hbound_cmp ( const void *  a,
const void *  b 
)
static

Definition at line 2717 of file partition.c.

References PartitionHashBound::modulus, partition_hbound_cmp(), and PartitionHashBound::remainder.

Referenced by RelationBuildPartitionDesc().

2718 {
2719  PartitionHashBound *h1 = (*(PartitionHashBound *const *) a);
2720  PartitionHashBound *h2 = (*(PartitionHashBound *const *) b);
2721 
2722  return partition_hbound_cmp(h1->modulus, h1->remainder,
2723  h2->modulus, h2->remainder);
2724 }
static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
Definition: partition.c:2732

◆ qsort_partition_list_value_cmp()

static int32 qsort_partition_list_value_cmp ( const void *  a,
const void *  b,
void *  arg 
)
static

Definition at line 2749 of file partition.c.

References DatumGetInt32, FunctionCall2Coll(), PartitionKeyData::partcollation, and PartitionKeyData::partsupfunc.

Referenced by RelationBuildPartitionDesc().

2750 {
2751  Datum val1 = (*(const PartitionListValue **) a)->value,
2752  val2 = (*(const PartitionListValue **) b)->value;
2753  PartitionKey key = (PartitionKey) arg;
2754 
2756  key->partcollation[0],
2757  val1, val2));
2758 }
#define DatumGetInt32(X)
Definition: postgres.h:455
FmgrInfo * partsupfunc
Definition: rel.h:63
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1042
Oid * partcollation
Definition: rel.h:66
uintptr_t Datum
Definition: postgres.h:365
struct PartitionKeyData * PartitionKey
Definition: rel.h:77
void * arg

◆ qsort_partition_rbound_cmp()

static int32 qsort_partition_rbound_cmp ( const void *  a,
const void *  b,
void *  arg 
)
static

Definition at line 2808 of file partition.c.

References PartitionRangeBound::datums, PartitionRangeBound::kind, PartitionRangeBound::lower, and partition_rbound_cmp().

Referenced by RelationBuildPartitionDesc().

2809 {
2810  PartitionRangeBound *b1 = (*(PartitionRangeBound *const *) a);
2811  PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
2812  PartitionKey key = (PartitionKey) arg;
2813 
2814  return partition_rbound_cmp(key, b1->datums, b1->kind, b1->lower, b2);
2815 }
PartitionRangeDatumKind * kind
Definition: partition.c:137
static int32 partition_rbound_cmp(PartitionKey key, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partition.c:2831
struct PartitionKeyData * PartitionKey
Definition: rel.h:77
void * arg

◆ RelationBuildPartitionDesc()

void RelationBuildPartitionDesc ( Relation  rel)

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

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

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

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

1509 {
1510  /* Quick exit */
1511  if (!rel->rd_rel->relispartition)
1512  return NIL;
1513 
1514  return generate_partition_qual(rel);
1515 }
#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:2478

◆ satisfies_hash_partition()

Datum satisfies_hash_partition ( PG_FUNCTION_ARGS  )

Definition at line 3296 of file partition.c.

References AccessShareLock, ARR_ELEMTYPE, Assert, DatumGetUInt64, deconstruct_array(), ereport, errcode(), errmsg(), ERROR, fmgr_info_copy(), FmgrInfo::fn_mcxt, format_type_be(), FunctionCall2, get_fn_expr_argtype(), get_fn_expr_variadic(), get_rel_name(), get_typlenbyvalalign(), hash(), hash_combine64(), HASH_PARTITION_SEED, i, IsBinaryCoercible(), MemoryContextAllocZero(), NoLock, offsetof, OidIsValid, PARTITION_MAX_KEYS, PARTITION_STRATEGY_HASH, PartitionKeyData::partnatts, PartitionKeyData::partsupfunc, PartitionKeyData::parttypid, PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_GETARG_INT32, PG_GETARG_OID, PG_NARGS, PG_RETURN_BOOL, PG_RETURN_NULL, RelationData::rd_rel, relation_close(), RelationGetPartitionKey, RELKIND_PARTITIONED_TABLE, PartitionKeyData::strategy, try_relation_open(), and UInt64GetDatum.

3297 {
3298  typedef struct ColumnsHashData
3299  {
3300  Oid relid;
3301  int nkeys;
3302  Oid variadic_type;
3303  int16 variadic_typlen;
3304  bool variadic_typbyval;
3305  char variadic_typalign;
3306  FmgrInfo partsupfunc[PARTITION_MAX_KEYS];
3307  } ColumnsHashData;
3308  Oid parentId;
3309  int modulus;
3310  int remainder;
3312  ColumnsHashData *my_extra;
3313  uint64 rowHash = 0;
3314 
3315  /* Return null if the parent OID, modulus, or remainder is NULL. */
3316  if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
3317  PG_RETURN_NULL();
3318  parentId = PG_GETARG_OID(0);
3319  modulus = PG_GETARG_INT32(1);
3320  remainder = PG_GETARG_INT32(2);
3321 
3322  /* Sanity check modulus and remainder. */
3323  if (modulus <= 0)
3324  ereport(ERROR,
3325  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3326  errmsg("modulus for hash partition must be a positive integer")));
3327  if (remainder < 0)
3328  ereport(ERROR,
3329  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3330  errmsg("remainder for hash partition must be a non-negative integer")));
3331  if (remainder >= modulus)
3332  ereport(ERROR,
3333  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3334  errmsg("remainder for hash partition must be less than modulus")));
3335 
3336  /*
3337  * Cache hash function information.
3338  */
3339  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
3340  if (my_extra == NULL || my_extra->relid != parentId)
3341  {
3342  Relation parent;
3343  PartitionKey key;
3344  int j;
3345 
3346  /* Open parent relation and fetch partition keyinfo */
3347  parent = try_relation_open(parentId, AccessShareLock);
3348  if (parent == NULL)
3349  PG_RETURN_NULL();
3350  key = RelationGetPartitionKey(parent);
3351 
3352  /* Reject parent table that is not hash-partitioned. */
3353  if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE ||
3355  ereport(ERROR,
3356  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3357  errmsg("\"%s\" is not a hash partitioned table",
3358  get_rel_name(parentId))));
3359 
3360  if (!get_fn_expr_variadic(fcinfo->flinfo))
3361  {
3362  int nargs = PG_NARGS() - 3;
3363 
3364  /* complain if wrong number of column values */
3365  if (key->partnatts != nargs)
3366  ereport(ERROR,
3367  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3368  errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
3369  key->partnatts, nargs)));
3370 
3371  /* allocate space for our cache */
3372  fcinfo->flinfo->fn_extra =
3373  MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
3374  offsetof(ColumnsHashData, partsupfunc) +
3375  sizeof(FmgrInfo) * nargs);
3376  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
3377  my_extra->relid = parentId;
3378  my_extra->nkeys = key->partnatts;
3379 
3380  /* check argument types and save fmgr_infos */
3381  for (j = 0; j < key->partnatts; ++j)
3382  {
3383  Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, j + 3);
3384 
3385  if (argtype != key->parttypid[j] && !IsBinaryCoercible(argtype, key->parttypid[j]))
3386  ereport(ERROR,
3387  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3388  errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
3389  j + 1, format_type_be(key->parttypid[j]), format_type_be(argtype))));
3390 
3391  fmgr_info_copy(&my_extra->partsupfunc[j],
3392  &key->partsupfunc[j],
3393  fcinfo->flinfo->fn_mcxt);
3394  }
3395 
3396  }
3397  else
3398  {
3399  ArrayType *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
3400 
3401  /* allocate space for our cache -- just one FmgrInfo in this case */
3402  fcinfo->flinfo->fn_extra =
3403  MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
3404  offsetof(ColumnsHashData, partsupfunc) +
3405  sizeof(FmgrInfo));
3406  my_extra = (ColumnsHashData *) fcinfo->flinfo->fn_extra;
3407  my_extra->relid = parentId;
3408  my_extra->nkeys = key->partnatts;
3409  my_extra->variadic_type = ARR_ELEMTYPE(variadic_array);
3410  get_typlenbyvalalign(my_extra->variadic_type,
3411  &my_extra->variadic_typlen,
3412  &my_extra->variadic_typbyval,
3413  &my_extra->variadic_typalign);
3414 
3415  /* check argument types */
3416  for (j = 0; j < key->partnatts; ++j)
3417  if (key->parttypid[j] != my_extra->variadic_type)
3418  ereport(ERROR,
3419  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3420  errmsg("column %d of the partition key has type \"%s\", but supplied value is of type \"%s\"",
3421  j + 1,
3422  format_type_be(key->parttypid[j]),
3423  format_type_be(my_extra->variadic_type))));
3424 
3425  fmgr_info_copy(&my_extra->partsupfunc[0],
3426  &key->partsupfunc[0],
3427  fcinfo->flinfo->fn_mcxt);
3428  }
3429 
3430  /* Hold lock until commit */
3431  relation_close(parent, NoLock);
3432  }
3433 
3434  if (!OidIsValid(my_extra->variadic_type))
3435  {
3436  int nkeys = my_extra->nkeys;
3437  int i;
3438 
3439  /*
3440  * For a non-variadic call, neither the number of arguments nor their
3441  * types can change across calls, so avoid the expense of rechecking
3442  * here.
3443  */
3444 
3445  for (i = 0; i < nkeys; i++)
3446  {
3447  Datum hash;
3448 
3449  /* keys start from fourth argument of function. */
3450  int argno = i + 3;
3451 
3452  if (PG_ARGISNULL(argno))
3453  continue;
3454 
3455  Assert(OidIsValid(my_extra->partsupfunc[i].fn_oid));
3456 
3457  hash = FunctionCall2(&my_extra->partsupfunc[i],
3458  PG_GETARG_DATUM(argno),
3459  seed);
3460 
3461  /* Form a single 64-bit hash value */
3462  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
3463  }
3464  }
3465  else
3466  {
3467  ArrayType *variadic_array = PG_GETARG_ARRAYTYPE_P(3);
3468  int i;
3469  int nelems;
3470  Datum *datum;
3471  bool *isnull;
3472 
3473  deconstruct_array(variadic_array,
3474  my_extra->variadic_type,
3475  my_extra->variadic_typlen,
3476  my_extra->variadic_typbyval,
3477  my_extra->variadic_typalign,
3478  &datum, &isnull, &nelems);
3479 
3480  /* complain if wrong number of column values */
3481  if (nelems != my_extra->nkeys)
3482  ereport(ERROR,
3483  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3484  errmsg("number of partitioning columns (%d) does not match number of partition keys provided (%d)",
3485  my_extra->nkeys, nelems)));
3486 
3487  for (i = 0; i < nelems; i++)
3488  {
3489  Datum hash;
3490 
3491  if (isnull[i])
3492  continue;
3493 
3494  Assert(OidIsValid(my_extra->partsupfunc[0].fn_oid));
3495 
3496  hash = FunctionCall2(&my_extra->partsupfunc[0],
3497  datum[i],
3498  seed);
3499 
3500  /* Form a single 64-bit hash value */
3501  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
3502  }
3503  }
3504 
3505  PG_RETURN_BOOL(rowHash % modulus == remainder);
3506 }
signed short int16
Definition: c.h:301
#define PG_GETARG_INT32(n)
Definition: fmgr.h:234
Definition: fmgr.h:56
MemoryContext fn_mcxt
Definition: fmgr.h:65
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1153
FmgrInfo * partsupfunc
Definition: rel.h:63
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2025
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:233
#define UInt64GetDatum(X)
Definition: postgres.h:631
#define FunctionCall2(flinfo, arg1, arg2)
Definition: fmgr.h:605
#define AccessShareLock
Definition: lockdefs.h:36
bool get_fn_expr_variadic(FmgrInfo *flinfo)
Definition: fmgr.c:2038
int errcode(int sqlerrcode)
Definition: elog.c:575
#define PARTITION_MAX_KEYS
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
char * format_type_be(Oid type_oid)
Definition: format_type.c:320
char strategy
Definition: rel.h:54
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:594
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:248
#define ERROR
Definition: elog.h:43
Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)
Definition: fmgr.c:1904
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:519
#define NoLock
Definition: lockdefs.h:34
#define PG_GETARG_OID(n)
Definition: fmgr.h:240
#define ereport(elevel, rest)
Definition: elog.h:122
Oid * parttypid
Definition: rel.h:69
bool IsBinaryCoercible(Oid srctype, Oid targettype)
static uint64 hash_combine64(uint64 a, uint64 b)
Definition: hashutils.h:29
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:319
uintptr_t Datum
Definition: postgres.h:365
int16 partnatts
Definition: rel.h:55
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:795
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:728
#define DatumGetUInt64(X)
Definition: postgres.h:617
#define PG_ARGISNULL(n)
Definition: fmgr.h:174
#define Assert(condition)
Definition: c.h:688
#define PG_NARGS()
Definition: fmgr.h:168
#define HASH_PARTITION_SEED
Definition: partition.h:23
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3449
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:541
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
#define ARR_ELEMTYPE(a)
Definition: array.h:277
#define PG_RETURN_NULL()
Definition: fmgr.h:305
#define offsetof(type, field)
Definition: c.h:611

◆ update_default_partition_oid()

void update_default_partition_oid ( Oid  parentId,
Oid  defaultPartId 
)

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

3137 {
3138  HeapTuple tuple;
3139  Relation pg_partitioned_table;
3140  Form_pg_partitioned_table part_table_form;
3141 
3142  pg_partitioned_table = heap_open(PartitionedRelationId, RowExclusiveLock);
3143 
3144  tuple = SearchSysCacheCopy1(PARTRELID, ObjectIdGetDatum(parentId));
3145 
3146  if (!HeapTupleIsValid(tuple))
3147  elog(ERROR, "cache lookup failed for partition key of relation %u",
3148  parentId);
3149 
3150  part_table_form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
3151  part_table_form->partdefid = defaultPartId;
3152  CatalogTupleUpdate(pg_partitioned_table, &tuple->t_self, tuple);
3153 
3154  heap_freetuple(tuple);
3155  heap_close(pg_partitioned_table, RowExclusiveLock);
3156 }
#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:490
#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