PostgreSQL Source Code  git master
partbounds.h File Reference
#include "fmgr.h"
#include "nodes/parsenodes.h"
#include "nodes/pg_list.h"
#include "partitioning/partdefs.h"
#include "utils/relcache.h"
Include dependency graph for partbounds.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PartitionBoundInfoData
 

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
 

Functions

int get_hash_partition_greatest_modulus (PartitionBoundInfo b)
 
uint64 compute_partition_hash_value (int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *values, bool *isnull)
 
Listget_qual_from_partbound (Relation rel, Relation parent, PartitionBoundSpec *spec)
 
PartitionBoundInfo partition_bounds_create (PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
 
bool partition_bounds_equal (int partnatts, int16 *parttyplen, bool *parttypbyval, PartitionBoundInfo b1, PartitionBoundInfo b2)
 
PartitionBoundInfo partition_bounds_copy (PartitionBoundInfo src, PartitionKey key)
 
bool partitions_are_ordered (PartitionBoundInfo boundinfo, int nparts)
 
void check_new_partition_bound (char *relname, Relation parent, PartitionBoundSpec *spec)
 
void check_default_partition_contents (Relation parent, Relation defaultRel, PartitionBoundSpec *new_spec)
 
int32 partition_rbound_datum_cmp (FmgrInfo *partsupfunc, Oid *partcollation, Datum *rb_datums, PartitionRangeDatumKind *rb_kind, Datum *tuple_datums, int n_tuple_datums)
 
int partition_list_bsearch (FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, Datum value, bool *is_equal)
 
int partition_range_datum_bsearch (FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, int nvalues, Datum *values, bool *is_equal)
 
int partition_hash_bsearch (PartitionBoundInfo boundinfo, int modulus, int remainder)
 

Macro Definition Documentation

◆ partition_bound_accepts_nulls

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

◆ partition_bound_has_default

Typedef Documentation

◆ PartitionBoundInfoData

Function Documentation

◆ check_default_partition_contents()

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

Definition at line 1232 of file partbounds.c.

References AccessExclusiveLock, CHECK_FOR_INTERRUPTS, CreateExecutorState(), DEBUG1, ExprContext::ecxt_scantuple, ereport, errcode(), errmsg(), ERROR, EState::es_tupleTable, ExecCheck(), ExecDropSingleTupleTableSlot(), ExecPrepareExpr(), find_all_inheritors(), ForwardScanDirection, FreeExecutorState(), get_proposed_default_constraint(), get_qual_for_list(), get_qual_for_range(), GetLatestSnapshot(), GetPerTupleExprContext, GetPerTupleMemoryContext, lfirst_oid, list_make1_oid, make_ands_explicit(), map_partition_varattnos(), MemoryContextSwitchTo(), NoLock, PartConstraintImpliedByRelConstraint(), PARTITION_STRATEGY_LIST, RelationData::rd_rel, RegisterSnapshot(), RelationGetRelationName, RelationGetRelid, ResetExprContext, PartitionBoundSpec::strategy, table_beginscan(), table_close(), table_endscan(), table_open(), table_scan_getnextslot(), table_slot_create(), UnregisterSnapshot(), and WARNING.

Referenced by DefineRelation().

1234 {
1235  List *new_part_constraints;
1236  List *def_part_constraints;
1237  List *all_parts;
1238  ListCell *lc;
1239 
1240  new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
1241  ? get_qual_for_list(parent, new_spec)
1242  : get_qual_for_range(parent, new_spec, false);
1243  def_part_constraints =
1244  get_proposed_default_constraint(new_part_constraints);
1245 
1246  /*
1247  * Map the Vars in the constraint expression from parent's attnos to
1248  * default_rel's.
1249  */
1250  def_part_constraints =
1251  map_partition_varattnos(def_part_constraints, 1, default_rel,
1252  parent);
1253 
1254  /*
1255  * If the existing constraints on the default partition imply that it will
1256  * not contain any row that would belong to the new partition, we can
1257  * avoid scanning the default partition.
1258  */
1259  if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
1260  {
1261  ereport(DEBUG1,
1262  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
1263  RelationGetRelationName(default_rel))));
1264  return;
1265  }
1266 
1267  /*
1268  * Scan the default partition and its subpartitions, and check for rows
1269  * that do not satisfy the revised partition constraints.
1270  */
1271  if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1272  all_parts = find_all_inheritors(RelationGetRelid(default_rel),
1273  AccessExclusiveLock, NULL);
1274  else
1275  all_parts = list_make1_oid(RelationGetRelid(default_rel));
1276 
1277  foreach(lc, all_parts)
1278  {
1279  Oid part_relid = lfirst_oid(lc);
1280  Relation part_rel;
1281  Expr *partition_constraint;
1282  EState *estate;
1283  ExprState *partqualstate = NULL;
1284  Snapshot snapshot;
1285  ExprContext *econtext;
1286  TableScanDesc scan;
1287  MemoryContext oldCxt;
1288  TupleTableSlot *tupslot;
1289 
1290  /* Lock already taken above. */
1291  if (part_relid != RelationGetRelid(default_rel))
1292  {
1293  part_rel = table_open(part_relid, NoLock);
1294 
1295  /*
1296  * Map the Vars in the constraint expression from default_rel's
1297  * the sub-partition's.
1298  */
1299  partition_constraint = make_ands_explicit(def_part_constraints);
1300  partition_constraint = (Expr *)
1301  map_partition_varattnos((List *) partition_constraint, 1,
1302  part_rel, default_rel);
1303 
1304  /*
1305  * If the partition constraints on default partition child imply
1306  * that it will not contain any row that would belong to the new
1307  * partition, we can avoid scanning the child table.
1308  */
1310  def_part_constraints))
1311  {
1312  ereport(DEBUG1,
1313  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
1314  RelationGetRelationName(part_rel))));
1315 
1316  table_close(part_rel, NoLock);
1317  continue;
1318  }
1319  }
1320  else
1321  {
1322  part_rel = default_rel;
1323  partition_constraint = make_ands_explicit(def_part_constraints);
1324  }
1325 
1326  /*
1327  * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
1328  * scanned.
1329  */
1330  if (part_rel->rd_rel->relkind != RELKIND_RELATION)
1331  {
1332  if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1333  ereport(WARNING,
1334  (errcode(ERRCODE_CHECK_VIOLATION),
1335  errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
1336  RelationGetRelationName(part_rel),
1337  RelationGetRelationName(default_rel))));
1338 
1339  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1340  table_close(part_rel, NoLock);
1341 
1342  continue;
1343  }
1344 
1345  estate = CreateExecutorState();
1346 
1347  /* Build expression execution states for partition check quals */
1348  partqualstate = ExecPrepareExpr(partition_constraint, estate);
1349 
1350  econtext = GetPerTupleExprContext(estate);
1351  snapshot = RegisterSnapshot(GetLatestSnapshot());
1352  tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
1353  scan = table_beginscan(part_rel, snapshot, 0, NULL);
1354 
1355  /*
1356  * Switch to per-tuple memory context and reset it for each tuple
1357  * produced, so we don't leak memory.
1358  */
1360 
1361  while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
1362  {
1363  econtext->ecxt_scantuple = tupslot;
1364 
1365  if (!ExecCheck(partqualstate, econtext))
1366  ereport(ERROR,
1367  (errcode(ERRCODE_CHECK_VIOLATION),
1368  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
1369  RelationGetRelationName(default_rel))));
1370 
1371  ResetExprContext(econtext);
1373  }
1374 
1375  MemoryContextSwitchTo(oldCxt);
1376  table_endscan(scan);
1377  UnregisterSnapshot(snapshot);
1379  FreeExecutorState(estate);
1380 
1381  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1382  table_close(part_rel, NoLock); /* keep the lock until commit */
1383  }
1384 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:77
#define DEBUG1
Definition: elog.h:25
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:865
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:608
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:904
unsigned int Oid
Definition: postgres_ext.h:31
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:490
void FreeExecutorState(EState *estate)
Definition: execUtils.c:190
#define GetPerTupleExprContext(estate)
Definition: executor.h:506
#define ERROR
Definition: elog.h:43
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:755
#define NoLock
Definition: lockdefs.h:34
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:345
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
#define RelationGetRelationName(relation)
Definition: rel.h:462
#define ereport(elevel, rest)
Definition: elog.h:141
EState * CreateExecutorState(void)
Definition: execUtils.c:88
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:907
#define WARNING
Definition: elog.h:40
List * es_tupleTable
Definition: execnodes.h:555
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:705
#define list_make1_oid(x1)
Definition: pg_list.h:249
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partbounds.c:2289
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:224
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:799
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:381
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:511
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:863
#define AccessExclusiveLock
Definition: lockdefs.h:45
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:165
int errmsg(const char *fmt,...)
Definition: elog.c:822
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:597
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel)
Definition: partition.c:198
#define RelationGetRelid(relation)
Definition: rel.h:428
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:2080
#define ResetExprContext(econtext)
Definition: executor.h:500
#define lfirst_oid(lc)
Definition: pg_list.h:192
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:15814

◆ check_new_partition_bound()

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

Definition at line 940 of file partbounds.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_hash_partition_greatest_modulus(), get_range_partbound_string(), get_rel_name(), PartitionBoundInfoData::indexes, PartitionBoundSpec::is_default, sort-test::key, PartitionBoundInfoData::kind, PartitionRangeBound::kind, lfirst, PartitionBoundSpec::listdatums, PartitionBoundSpec::location, lower(), PartitionBoundSpec::lowerdatums, make_one_partition_rbound(), make_parsestate(), PartitionBoundSpec::modulus, PartitionBoundInfoData::ndatums, PartitionDescData::nparts, PartitionBoundInfoData::null_index, PartitionDescData::oids, parser_errposition(), PartitionKeyData::partcollation, 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, PartitionKeyData::partnatts, PartitionKeyData::partsupfunc, RelationGetPartitionDesc(), RelationGetPartitionKey(), PartitionHashBound::remainder, PartitionBoundSpec::remainder, PartitionKeyData::strategy, PartitionBoundInfoData::strategy, PartitionBoundSpec::strategy, upper(), PartitionBoundSpec::upperdatums, and val.

Referenced by ATExecAttachPartition(), and DefineRelation().

942 {
944  PartitionDesc partdesc = RelationGetPartitionDesc(parent);
945  PartitionBoundInfo boundinfo = partdesc->boundinfo;
946  ParseState *pstate = make_parsestate(NULL);
947  int with = -1;
948  bool overlap = false;
949 
950  if (spec->is_default)
951  {
952  /*
953  * The default partition bound never conflicts with any other
954  * partition's; if that's what we're attaching, the only possible
955  * problem is that one already exists, so check for that and we're
956  * done.
957  */
958  if (boundinfo == NULL || !partition_bound_has_default(boundinfo))
959  return;
960 
961  /* Default partition already exists, error out. */
962  ereport(ERROR,
963  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
964  errmsg("partition \"%s\" conflicts with existing default partition \"%s\"",
965  relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
966  parser_errposition(pstate, spec->location)));
967  }
968 
969  switch (key->strategy)
970  {
972  {
974  Assert(spec->remainder >= 0 && spec->remainder < spec->modulus);
975 
976  if (partdesc->nparts > 0)
977  {
978  Datum **datums = boundinfo->datums;
979  int ndatums = boundinfo->ndatums;
980  int greatest_modulus;
981  int remainder;
982  int offset;
983  bool valid_modulus = true;
984  int prev_modulus, /* Previous largest modulus */
985  next_modulus; /* Next largest modulus */
986 
987  /*
988  * Check rule that every modulus must be a factor of the
989  * next larger modulus. For example, if you have a bunch
990  * of partitions that all have modulus 5, you can add a
991  * new partition with modulus 10 or a new partition with
992  * modulus 15, but you cannot add both a partition with
993  * modulus 10 and a partition with modulus 15, because 10
994  * is not a factor of 15.
995  *
996  * Get the greatest (modulus, remainder) pair contained in
997  * boundinfo->datums that is less than or equal to the
998  * (spec->modulus, spec->remainder) pair.
999  */
1000  offset = partition_hash_bsearch(boundinfo,
1001  spec->modulus,
1002  spec->remainder);
1003  if (offset < 0)
1004  {
1005  next_modulus = DatumGetInt32(datums[0][0]);
1006  valid_modulus = (next_modulus % spec->modulus) == 0;
1007  }
1008  else
1009  {
1010  prev_modulus = DatumGetInt32(datums[offset][0]);
1011  valid_modulus = (spec->modulus % prev_modulus) == 0;
1012 
1013  if (valid_modulus && (offset + 1) < ndatums)
1014  {
1015  next_modulus = DatumGetInt32(datums[offset + 1][0]);
1016  valid_modulus = (next_modulus % spec->modulus) == 0;
1017  }
1018  }
1019 
1020  if (!valid_modulus)
1021  ereport(ERROR,
1022  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1023  errmsg("every hash partition modulus must be a factor of the next larger modulus")));
1024 
1025  greatest_modulus = get_hash_partition_greatest_modulus(boundinfo);
1026  remainder = spec->remainder;
1027 
1028  /*
1029  * Normally, the lowest remainder that could conflict with
1030  * the new partition is equal to the remainder specified
1031  * for the new partition, but when the new partition has a
1032  * modulus higher than any used so far, we need to adjust.
1033  */
1034  if (remainder >= greatest_modulus)
1035  remainder = remainder % greatest_modulus;
1036 
1037  /* Check every potentially-conflicting remainder. */
1038  do
1039  {
1040  if (boundinfo->indexes[remainder] != -1)
1041  {
1042  overlap = true;
1043  with = boundinfo->indexes[remainder];
1044  break;
1045  }
1046  remainder += spec->modulus;
1047  } while (remainder < greatest_modulus);
1048  }
1049 
1050  break;
1051  }
1052 
1054  {
1056 
1057  if (partdesc->nparts > 0)
1058  {
1059  ListCell *cell;
1060 
1061  Assert(boundinfo &&
1062  boundinfo->strategy == PARTITION_STRATEGY_LIST &&
1063  (boundinfo->ndatums > 0 ||
1064  partition_bound_accepts_nulls(boundinfo) ||
1065  partition_bound_has_default(boundinfo)));
1066 
1067  foreach(cell, spec->listdatums)
1068  {
1069  Const *val = castNode(Const, lfirst(cell));
1070 
1071  if (!val->constisnull)
1072  {
1073  int offset;
1074  bool equal;
1075 
1076  offset = partition_list_bsearch(&key->partsupfunc[0],
1077  key->partcollation,
1078  boundinfo,
1079  val->constvalue,
1080  &equal);
1081  if (offset >= 0 && equal)
1082  {
1083  overlap = true;
1084  with = boundinfo->indexes[offset];
1085  break;
1086  }
1087  }
1088  else if (partition_bound_accepts_nulls(boundinfo))
1089  {
1090  overlap = true;
1091  with = boundinfo->null_index;
1092  break;
1093  }
1094  }
1095  }
1096 
1097  break;
1098  }
1099 
1101  {
1103  *upper;
1104 
1106  lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
1107  upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
1108 
1109  /*
1110  * First check if the resulting range would be empty with
1111  * specified lower and upper bounds
1112  */
1114  key->partcollation, lower->datums,
1115  lower->kind, true, upper) >= 0)
1116  {
1117  ereport(ERROR,
1118  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1119  errmsg("empty range bound specified for partition \"%s\"",
1120  relname),
1121  errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
1124  parser_errposition(pstate, spec->location)));
1125  }
1126 
1127  if (partdesc->nparts > 0)
1128  {
1129  int offset;
1130  bool equal;
1131 
1132  Assert(boundinfo &&
1133  boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
1134  (boundinfo->ndatums > 0 ||
1135  partition_bound_has_default(boundinfo)));
1136 
1137  /*
1138  * Test whether the new lower bound (which is treated
1139  * inclusively as part of the new partition) lies inside
1140  * an existing partition, or in a gap.
1141  *
1142  * If it's inside an existing partition, the bound at
1143  * offset + 1 will be the upper bound of that partition,
1144  * and its index will be >= 0.
1145  *
1146  * If it's in a gap, the bound at offset + 1 will be the
1147  * lower bound of the next partition, and its index will
1148  * be -1. This is also true if there is no next partition,
1149  * since the index array is initialised with an extra -1
1150  * at the end.
1151  */
1152  offset = partition_range_bsearch(key->partnatts,
1153  key->partsupfunc,
1154  key->partcollation,
1155  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->partnatts,
1178  key->partsupfunc,
1179  key->partcollation,
1180  datums, kind,
1181  is_lower, upper);
1182  if (cmpval < 0)
1183  {
1184  /*
1185  * The new partition overlaps with the
1186  * existing partition between offset + 1 and
1187  * offset + 2.
1188  */
1189  overlap = true;
1190  with = boundinfo->indexes[offset + 2];
1191  }
1192  }
1193  }
1194  else
1195  {
1196  /*
1197  * The new partition overlaps with the existing
1198  * partition between offset and offset + 1.
1199  */
1200  overlap = true;
1201  with = boundinfo->indexes[offset + 1];
1202  }
1203  }
1204 
1205  break;
1206  }
1207 
1208  default:
1209  elog(ERROR, "unexpected partition strategy: %d",
1210  (int) key->strategy);
1211  }
1212 
1213  if (overlap)
1214  {
1215  Assert(with >= 0);
1216  ereport(ERROR,
1217  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1218  errmsg("partition \"%s\" would overlap partition \"%s\"",
1219  relname, get_rel_name(partdesc->oids[with])),
1220  parser_errposition(pstate, spec->location)));
1221  }
1222 }
Datum constvalue
Definition: primnodes.h:214
PartitionRangeDatumKind ** kind
Definition: partbounds.h:64
static int partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, PartitionRangeBound *probe, bool *is_equal)
Definition: partbounds.c:1625
PartitionRangeDatumKind * kind
Definition: partbounds.c:67
#define DatumGetInt32(X)
Definition: postgres.h:472
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3018
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
FmgrInfo * partsupfunc
Definition: partcache.h:35
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
PartitionRangeDatumKind
Definition: parsenodes.h:834
int errcode(int sqlerrcode)
Definition: elog.c:608
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:74
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
NameData relname
Definition: pg_class.h:38
signed int int32
Definition: c.h:355
PartitionBoundInfo boundinfo
Definition: partdesc.h:29
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
static PartitionRangeBound * make_one_partition_rbound(PartitionKey key, int index, List *datums, bool lower)
Definition: partbounds.c:1411
#define ERROR
Definition: elog.h:43
int get_hash_partition_greatest_modulus(PartitionBoundInfo bound)
Definition: partbounds.c:1394
int errdetail(const char *fmt,...)
Definition: elog.c:955
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:65
#define partition_bound_has_default(bi)
Definition: partbounds.h:75
int partition_hash_bsearch(PartitionBoundInfo boundinfo, int modulus, int remainder)
Definition: partbounds.c:1714
#define ereport(elevel, rest)
Definition: elog.h:141
char * get_range_partbound_string(List *bound_datums)
Definition: ruleutils.c:11337
Oid * partcollation
Definition: partcache.h:38
uintptr_t Datum
Definition: postgres.h:367
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:798
#define partition_bound_accepts_nulls(bi)
Definition: partbounds.h:74
int partition_list_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, Datum value, bool *is_equal)
Definition: partbounds.c:1582
static int32 partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc, Oid *partcollation, Datum *datums1, PartitionRangeDatumKind *kind1, bool lower1, PartitionRangeBound *b2)
Definition: partbounds.c:1467
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:799
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:800
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
long val
Definition: informix.c:664
bool constisnull
Definition: primnodes.h:215

◆ compute_partition_hash_value()

uint64 compute_partition_hash_value ( int  partnatts,
FmgrInfo partsupfunc,
Oid partcollation,
Datum values,
bool isnull 
)

Definition at line 2745 of file partbounds.c.

References Assert, DatumGetUInt64, FunctionCall2Coll(), hash(), hash_combine64(), HASH_PARTITION_SEED, i, OidIsValid, and UInt64GetDatum.

Referenced by get_matching_hash_bounds(), and get_partition_for_tuple().

2747 {
2748  int i;
2749  uint64 rowHash = 0;
2751 
2752  for (i = 0; i < partnatts; i++)
2753  {
2754  /* Nulls are just ignored */
2755  if (!isnull[i])
2756  {
2757  Datum hash;
2758 
2759  Assert(OidIsValid(partsupfunc[i].fn_oid));
2760 
2761  /*
2762  * Compute hash for each datum value by calling respective
2763  * datatype-specific hash functions of each partition key
2764  * attribute.
2765  */
2766  hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
2767  values[i], seed);
2768 
2769  /* Form a single 64-bit hash value */
2770  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
2771  }
2772  }
2773 
2774  return rowHash;
2775 }
#define UInt64GetDatum(X)
Definition: postgres.h:648
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
static uint64 hash_combine64(uint64 a, uint64 b)
Definition: hashfn.h:80
#define OidIsValid(objectId)
Definition: c.h:644
uintptr_t Datum
Definition: postgres.h:367
#define DatumGetUInt64(X)
Definition: postgres.h:634
#define Assert(condition)
Definition: c.h:738
#define HASH_PARTITION_SEED
Definition: partition.h:20
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int i
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:541

◆ get_hash_partition_greatest_modulus()

int get_hash_partition_greatest_modulus ( PartitionBoundInfo  b)

Definition at line 1394 of file partbounds.c.

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

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

1395 {
1396  Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
1397  Assert(bound->datums && bound->ndatums > 0);
1398  Assert(DatumGetInt32(bound->datums[bound->ndatums - 1][0]) > 0);
1399 
1400  return DatumGetInt32(bound->datums[bound->ndatums - 1][0]);
1401 }
#define DatumGetInt32(X)
Definition: postgres.h:472
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:798
#define Assert(condition)
Definition: c.h:738

◆ get_qual_from_partbound()

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

Definition at line 117 of file partbounds.c.

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

Referenced by ATExecAttachPartition(), and generate_partition_qual().

119 {
121  List *my_qual = NIL;
122 
123  Assert(key != NULL);
124 
125  switch (key->strategy)
126  {
129  my_qual = get_qual_for_hash(parent, spec);
130  break;
131 
134  my_qual = get_qual_for_list(parent, spec);
135  break;
136 
139  my_qual = get_qual_for_range(parent, spec, false);
140  break;
141 
142  default:
143  elog(ERROR, "unexpected partition strategy: %d",
144  (int) key->strategy);
145  }
146 
147  return my_qual;
148 }
#define NIL
Definition: pg_list.h:65
static List * get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:1997
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
#define ERROR
Definition: elog.h:43
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:798
static List * get_qual_for_range(Relation parent, PartitionBoundSpec *spec, bool for_default)
Definition: partbounds.c:2289
#define Assert(condition)
Definition: c.h:738
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:799
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:800
#define elog(elevel,...)
Definition: elog.h:228
Definition: pg_list.h:50
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:2080

◆ partition_bounds_copy()

PartitionBoundInfo partition_bounds_copy ( PartitionBoundInfo  src,
PartitionKey  key 
)

Definition at line 784 of file partbounds.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 RelationBuildPartitionDesc().

786 {
788  int i;
789  int ndatums;
790  int partnatts;
791  int num_indexes;
792  bool hash_part;
793  int natts;
794 
796 
797  dest->strategy = src->strategy;
798  ndatums = dest->ndatums = src->ndatums;
799  partnatts = key->partnatts;
800 
801  num_indexes = get_partition_bound_num_indexes(src);
802 
803  /* List partitioned tables have only a single partition key. */
804  Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
805 
806  dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
807 
808  if (src->kind != NULL)
809  {
810  dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
811  sizeof(PartitionRangeDatumKind *));
812  for (i = 0; i < ndatums; i++)
813  {
814  dest->kind[i] = (PartitionRangeDatumKind *) palloc(partnatts *
815  sizeof(PartitionRangeDatumKind));
816 
817  memcpy(dest->kind[i], src->kind[i],
818  sizeof(PartitionRangeDatumKind) * key->partnatts);
819  }
820  }
821  else
822  dest->kind = NULL;
823 
824  /*
825  * For hash partitioning, datums array will have two elements - modulus and
826  * remainder.
827  */
828  hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
829  natts = hash_part ? 2 : partnatts;
830 
831  for (i = 0; i < ndatums; i++)
832  {
833  int j;
834 
835  dest->datums[i] = (Datum *) palloc(sizeof(Datum) * natts);
836 
837  for (j = 0; j < natts; j++)
838  {
839  bool byval;
840  int typlen;
841 
842  if (hash_part)
843  {
844  typlen = sizeof(int32); /* Always int4 */
845  byval = true; /* int4 is pass-by-value */
846  }
847  else
848  {
849  byval = key->parttypbyval[j];
850  typlen = key->parttyplen[j];
851  }
852 
853  if (dest->kind == NULL ||
854  dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
855  dest->datums[i][j] = datumCopy(src->datums[i][j],
856  byval, typlen);
857  }
858  }
859 
860  dest->indexes = (int *) palloc(sizeof(int) * num_indexes);
861  memcpy(dest->indexes, src->indexes, sizeof(int) * num_indexes);
862 
863  dest->null_index = src->null_index;
864  dest->default_index = src->default_index;
865 
866  return dest;
867 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:64
PartitionRangeDatumKind
Definition: parsenodes.h:834
signed int int32
Definition: c.h:355
static int get_partition_bound_num_indexes(PartitionBoundInfo b)
Definition: partbounds.c:1803
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:131
uintptr_t Datum
Definition: postgres.h:367
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:798
bool * parttypbyval
Definition: partcache.h:44
#define Assert(condition)
Definition: c.h:738
int16 * parttyplen
Definition: partcache.h:43
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:799
void * palloc(Size size)
Definition: mcxt.c:949
int i
struct PartitionBoundInfoData * PartitionBoundInfo
Definition: partdefs.h:16

◆ partition_bounds_create()

PartitionBoundInfo partition_bounds_create ( PartitionBoundSpec **  boundspecs,
int  nparts,
PartitionKey  key,
int **  mapping 
)

Definition at line 172 of file partbounds.c.

References Assert, create_hash_bounds(), create_list_bounds(), create_range_bounds(), elog, ERROR, i, palloc(), PARTITION_STRATEGY_HASH, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, and PartitionKeyData::strategy.

Referenced by RelationBuildPartitionDesc().

174 {
175  int i;
176 
177  Assert(nparts > 0);
178 
179  /*
180  * For each partitioning method, we first convert the partition bounds
181  * from their parser node representation to the internal representation,
182  * along with any additional preprocessing (such as de-duplicating range
183  * bounds). Resulting bound datums are then added to the 'datums' array
184  * in PartitionBoundInfo. For each datum added, an integer indicating the
185  * canonical partition index is added to the 'indexes' array.
186  *
187  * For each bound, we remember its partition's position (0-based) in the
188  * original list to later map it to the canonical index.
189  */
190 
191  /*
192  * Initialize mapping array with invalid values, this is filled within
193  * each sub-routine below depending on the bound type.
194  */
195  *mapping = (int *) palloc(sizeof(int) * nparts);
196  for (i = 0; i < nparts; i++)
197  (*mapping)[i] = -1;
198 
199  switch (key->strategy)
200  {
202  return create_hash_bounds(boundspecs, nparts, key, mapping);
203 
205  return create_list_bounds(boundspecs, nparts, key, mapping);
206 
208  return create_range_bounds(boundspecs, nparts, key, mapping);
209 
210  default:
211  elog(ERROR, "unexpected partition strategy: %d",
212  (int) key->strategy);
213  break;
214  }
215 
216  Assert(false);
217  return NULL; /* keep compiler quiet */
218 }
#define ERROR
Definition: elog.h:43
static PartitionBoundInfo create_hash_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:225
static PartitionBoundInfo create_list_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:307
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:798
#define Assert(condition)
Definition: c.h:738
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:799
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:800
static PartitionBoundInfo create_range_bounds(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:464
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:228
int i

◆ partition_bounds_equal()

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

Definition at line 666 of file partbounds.c.

References Assert, datumIsEqual(), PartitionBoundInfoData::datums, PartitionBoundInfoData::default_index, get_hash_partition_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(), and try_partitionwise_join().

668 {
669  int i;
670 
671  if (b1->strategy != b2->strategy)
672  return false;
673 
674  if (b1->ndatums != b2->ndatums)
675  return false;
676 
677  if (b1->null_index != b2->null_index)
678  return false;
679 
680  if (b1->default_index != b2->default_index)
681  return false;
682 
684  {
685  int greatest_modulus = get_hash_partition_greatest_modulus(b1);
686 
687  /*
688  * If two hash partitioned tables have different greatest moduli,
689  * their partition schemes don't match.
690  */
691  if (greatest_modulus != get_hash_partition_greatest_modulus(b2))
692  return false;
693 
694  /*
695  * We arrange the partitions in the ascending order of their moduli
696  * and remainders. Also every modulus is factor of next larger
697  * modulus. Therefore we can safely store index of a given partition
698  * in indexes array at remainder of that partition. Also entries at
699  * (remainder + N * modulus) positions in indexes array are all same
700  * for (modulus, remainder) specification for any partition. Thus
701  * datums array from both the given bounds are same, if and only if
702  * their indexes array will be same. So, it suffices to compare
703  * indexes array.
704  */
705  for (i = 0; i < greatest_modulus; i++)
706  if (b1->indexes[i] != b2->indexes[i])
707  return false;
708 
709 #ifdef USE_ASSERT_CHECKING
710 
711  /*
712  * Nonetheless make sure that the bounds are indeed same when the
713  * indexes match. Hash partition bound stores modulus and remainder
714  * at b1->datums[i][0] and b1->datums[i][1] position respectively.
715  */
716  for (i = 0; i < b1->ndatums; i++)
717  Assert((b1->datums[i][0] == b2->datums[i][0] &&
718  b1->datums[i][1] == b2->datums[i][1]));
719 #endif
720  }
721  else
722  {
723  for (i = 0; i < b1->ndatums; i++)
724  {
725  int j;
726 
727  for (j = 0; j < partnatts; j++)
728  {
729  /* For range partitions, the bounds might not be finite. */
730  if (b1->kind != NULL)
731  {
732  /* The different kinds of bound all differ from each other */
733  if (b1->kind[i][j] != b2->kind[i][j])
734  return false;
735 
736  /*
737  * Non-finite bounds are equal without further
738  * examination.
739  */
740  if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
741  continue;
742  }
743 
744  /*
745  * Compare the actual values. Note that it would be both
746  * incorrect and unsafe to invoke the comparison operator
747  * derived from the partitioning specification here. It would
748  * be incorrect because we want the relcache entry to be
749  * updated for ANY change to the partition bounds, not just
750  * those that the partitioning operator thinks are
751  * significant. It would be unsafe because we might reach
752  * this code in the context of an aborted transaction, and an
753  * arbitrary partitioning operator might not be safe in that
754  * context. datumIsEqual() should be simple enough to be
755  * safe.
756  */
757  if (!datumIsEqual(b1->datums[i][j], b2->datums[i][j],
758  parttypbyval[j], parttyplen[j]))
759  return false;
760  }
761 
762  if (b1->indexes[i] != b2->indexes[i])
763  return false;
764  }
765 
766  /* There are ndatums+1 indexes in case of range partitions */
767  if (b1->strategy == PARTITION_STRATEGY_RANGE &&
768  b1->indexes[i] != b2->indexes[i])
769  return false;
770  }
771  return true;
772 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:64
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:222
int get_hash_partition_greatest_modulus(PartitionBoundInfo bound)
Definition: partbounds.c:1394
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:798
#define Assert(condition)
Definition: c.h:738
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:800
int i

◆ partition_hash_bsearch()

int partition_hash_bsearch ( PartitionBoundInfo  boundinfo,
int  modulus,
int  remainder 
)

Definition at line 1714 of file partbounds.c.

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

Referenced by check_new_partition_bound().

1716 {
1717  int lo,
1718  hi,
1719  mid;
1720 
1721  lo = -1;
1722  hi = boundinfo->ndatums - 1;
1723  while (lo < hi)
1724  {
1725  int32 cmpval,
1726  bound_modulus,
1727  bound_remainder;
1728 
1729  mid = (lo + hi + 1) / 2;
1730  bound_modulus = DatumGetInt32(boundinfo->datums[mid][0]);
1731  bound_remainder = DatumGetInt32(boundinfo->datums[mid][1]);
1732  cmpval = partition_hbound_cmp(bound_modulus, bound_remainder,
1733  modulus, remainder);
1734  if (cmpval <= 0)
1735  {
1736  lo = mid;
1737 
1738  if (cmpval == 0)
1739  break;
1740  }
1741  else
1742  hi = mid - 1;
1743  }
1744 
1745  return lo;
1746 }
#define DatumGetInt32(X)
Definition: postgres.h:472
signed int int32
Definition: c.h:355
static int32 partition_hbound_cmp(int modulus1, int remainder1, int modulus2, int remainder2)
Definition: partbounds.c:1562

◆ partition_list_bsearch()

int partition_list_bsearch ( FmgrInfo partsupfunc,
Oid partcollation,
PartitionBoundInfo  boundinfo,
Datum  value,
bool is_equal 
)

Definition at line 1582 of file partbounds.c.

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

Referenced by check_new_partition_bound(), get_matching_list_bounds(), and get_partition_for_tuple().

1585 {
1586  int lo,
1587  hi,
1588  mid;
1589 
1590  lo = -1;
1591  hi = boundinfo->ndatums - 1;
1592  while (lo < hi)
1593  {
1594  int32 cmpval;
1595 
1596  mid = (lo + hi + 1) / 2;
1597  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
1598  partcollation[0],
1599  boundinfo->datums[mid][0],
1600  value));
1601  if (cmpval <= 0)
1602  {
1603  lo = mid;
1604  *is_equal = (cmpval == 0);
1605  if (*is_equal)
1606  break;
1607  }
1608  else
1609  hi = mid - 1;
1610  }
1611 
1612  return lo;
1613 }
#define DatumGetInt32(X)
Definition: postgres.h:472
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
signed int int32
Definition: c.h:355
static struct @143 value

◆ partition_range_datum_bsearch()

int partition_range_datum_bsearch ( FmgrInfo partsupfunc,
Oid partcollation,
PartitionBoundInfo  boundinfo,
int  nvalues,
Datum values,
bool is_equal 
)

Definition at line 1671 of file partbounds.c.

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

Referenced by get_matching_range_bounds(), and get_partition_for_tuple().

1674 {
1675  int lo,
1676  hi,
1677  mid;
1678 
1679  lo = -1;
1680  hi = boundinfo->ndatums - 1;
1681  while (lo < hi)
1682  {
1683  int32 cmpval;
1684 
1685  mid = (lo + hi + 1) / 2;
1686  cmpval = partition_rbound_datum_cmp(partsupfunc,
1687  partcollation,
1688  boundinfo->datums[mid],
1689  boundinfo->kind[mid],
1690  values,
1691  nvalues);
1692  if (cmpval <= 0)
1693  {
1694  lo = mid;
1695  *is_equal = (cmpval == 0);
1696 
1697  if (*is_equal)
1698  break;
1699  }
1700  else
1701  hi = mid - 1;
1702  }
1703 
1704  return lo;
1705 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:64
signed int int32
Definition: c.h:355
int32 partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation, Datum *rb_datums, PartitionRangeDatumKind *rb_kind, Datum *tuple_datums, int n_tuple_datums)
Definition: partbounds.c:1531
static Datum values[MAXATTR]
Definition: bootstrap.c:167

◆ partition_rbound_datum_cmp()

int32 partition_rbound_datum_cmp ( FmgrInfo partsupfunc,
Oid partcollation,
Datum rb_datums,
PartitionRangeDatumKind rb_kind,
Datum tuple_datums,
int  n_tuple_datums 
)

Definition at line 1531 of file partbounds.c.

References DatumGetInt32, FunctionCall2Coll(), i, PARTITION_RANGE_DATUM_MAXVALUE, and PARTITION_RANGE_DATUM_MINVALUE.

Referenced by get_matching_range_bounds(), and partition_range_datum_bsearch().

1534 {
1535  int i;
1536  int32 cmpval = -1;
1537 
1538  for (i = 0; i < n_tuple_datums; i++)
1539  {
1540  if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
1541  return -1;
1542  else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
1543  return 1;
1544 
1545  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
1546  partcollation[i],
1547  rb_datums[i],
1548  tuple_datums[i]));
1549  if (cmpval != 0)
1550  break;
1551  }
1552 
1553  return cmpval;
1554 }
#define DatumGetInt32(X)
Definition: postgres.h:472
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
signed int int32
Definition: c.h:355
int i

◆ partitions_are_ordered()

bool partitions_are_ordered ( PartitionBoundInfo  boundinfo,
int  nparts 
)

Definition at line 881 of file partbounds.c.

References Assert, PartitionBoundInfoData::ndatums, partition_bound_accepts_nulls, partition_bound_has_default, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, and PartitionBoundInfoData::strategy.

Referenced by build_partition_pathkeys(), and generate_orderedappend_paths().

882 {
883  Assert(boundinfo != NULL);
884 
885  switch (boundinfo->strategy)
886  {
888 
889  /*
890  * RANGE-type partitioning guarantees that the partitions can be
891  * scanned in the order that they're defined in the PartitionDesc
892  * to provide sequential, non-overlapping ranges of tuples.
893  * However, if a DEFAULT partition exists then it doesn't work, as
894  * that could contain tuples from either below or above the
895  * defined range, or tuples belonging to gaps between partitions.
896  */
897  if (!partition_bound_has_default(boundinfo))
898  return true;
899  break;
900 
902 
903  /*
904  * LIST partitioning can also guarantee ordering, but only if the
905  * partitions don't accept interleaved values. We could likely
906  * check for this by looping over the PartitionBound's indexes
907  * array to check that the indexes are in order. For now, let's
908  * just keep it simple and just accept LIST partitioning when
909  * there's no DEFAULT partition, exactly one value per partition,
910  * and optionally a NULL partition that does not accept any other
911  * values. Such a NULL partition will come last in the
912  * PartitionDesc, and the other partitions will be properly
913  * ordered. This is a cheap test to make as it does not require
914  * any per-partition processing. Maybe we'd like to handle more
915  * complex cases in the future.
916  */
917  if (partition_bound_has_default(boundinfo))
918  return false;
919 
920  if (boundinfo->ndatums + partition_bound_accepts_nulls(boundinfo)
921  == nparts)
922  return true;
923  break;
924 
925  default:
926  /* HASH, or some other strategy */
927  break;
928  }
929 
930  return false;
931 }
#define partition_bound_has_default(bi)
Definition: partbounds.h:75
#define partition_bound_accepts_nulls(bi)
Definition: partbounds.h:74
#define Assert(condition)
Definition: c.h:738
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:799
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:800