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 1226 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().

1228 {
1229  List *new_part_constraints;
1230  List *def_part_constraints;
1231  List *all_parts;
1232  ListCell *lc;
1233 
1234  new_part_constraints = (new_spec->strategy == PARTITION_STRATEGY_LIST)
1235  ? get_qual_for_list(parent, new_spec)
1236  : get_qual_for_range(parent, new_spec, false);
1237  def_part_constraints =
1238  get_proposed_default_constraint(new_part_constraints);
1239 
1240  /*
1241  * Map the Vars in the constraint expression from parent's attnos to
1242  * default_rel's.
1243  */
1244  def_part_constraints =
1245  map_partition_varattnos(def_part_constraints, 1, default_rel,
1246  parent, NULL);
1247 
1248  /*
1249  * If the existing constraints on the default partition imply that it will
1250  * not contain any row that would belong to the new partition, we can
1251  * avoid scanning the default partition.
1252  */
1253  if (PartConstraintImpliedByRelConstraint(default_rel, def_part_constraints))
1254  {
1255  ereport(DEBUG1,
1256  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
1257  RelationGetRelationName(default_rel))));
1258  return;
1259  }
1260 
1261  /*
1262  * Scan the default partition and its subpartitions, and check for rows
1263  * that do not satisfy the revised partition constraints.
1264  */
1265  if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1266  all_parts = find_all_inheritors(RelationGetRelid(default_rel),
1267  AccessExclusiveLock, NULL);
1268  else
1269  all_parts = list_make1_oid(RelationGetRelid(default_rel));
1270 
1271  foreach(lc, all_parts)
1272  {
1273  Oid part_relid = lfirst_oid(lc);
1274  Relation part_rel;
1275  Expr *partition_constraint;
1276  EState *estate;
1277  ExprState *partqualstate = NULL;
1278  Snapshot snapshot;
1279  ExprContext *econtext;
1280  TableScanDesc scan;
1281  MemoryContext oldCxt;
1282  TupleTableSlot *tupslot;
1283 
1284  /* Lock already taken above. */
1285  if (part_relid != RelationGetRelid(default_rel))
1286  {
1287  part_rel = table_open(part_relid, NoLock);
1288 
1289  /*
1290  * Map the Vars in the constraint expression from default_rel's
1291  * the sub-partition's.
1292  */
1293  partition_constraint = make_ands_explicit(def_part_constraints);
1294  partition_constraint = (Expr *)
1295  map_partition_varattnos((List *) partition_constraint, 1,
1296  part_rel, default_rel, NULL);
1297 
1298  /*
1299  * If the partition constraints on default partition child imply
1300  * that it will not contain any row that would belong to the new
1301  * partition, we can avoid scanning the child table.
1302  */
1304  def_part_constraints))
1305  {
1306  ereport(DEBUG1,
1307  (errmsg("updated partition constraint for default partition \"%s\" is implied by existing constraints",
1308  RelationGetRelationName(part_rel))));
1309 
1310  table_close(part_rel, NoLock);
1311  continue;
1312  }
1313  }
1314  else
1315  {
1316  part_rel = default_rel;
1317  partition_constraint = make_ands_explicit(def_part_constraints);
1318  }
1319 
1320  /*
1321  * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
1322  * scanned.
1323  */
1324  if (part_rel->rd_rel->relkind != RELKIND_RELATION)
1325  {
1326  if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1327  ereport(WARNING,
1328  (errcode(ERRCODE_CHECK_VIOLATION),
1329  errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
1330  RelationGetRelationName(part_rel),
1331  RelationGetRelationName(default_rel))));
1332 
1333  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1334  table_close(part_rel, NoLock);
1335 
1336  continue;
1337  }
1338 
1339  estate = CreateExecutorState();
1340 
1341  /* Build expression execution states for partition check quals */
1342  partqualstate = ExecPrepareExpr(partition_constraint, estate);
1343 
1344  econtext = GetPerTupleExprContext(estate);
1345  snapshot = RegisterSnapshot(GetLatestSnapshot());
1346  tupslot = table_slot_create(part_rel, &estate->es_tupleTable);
1347  scan = table_beginscan(part_rel, snapshot, 0, NULL);
1348 
1349  /*
1350  * Switch to per-tuple memory context and reset it for each tuple
1351  * produced, so we don't leak memory.
1352  */
1354 
1355  while (table_scan_getnextslot(scan, ForwardScanDirection, tupslot))
1356  {
1357  econtext->ecxt_scantuple = tupslot;
1358 
1359  if (!ExecCheck(partqualstate, econtext))
1360  ereport(ERROR,
1361  (errcode(ERRCODE_CHECK_VIOLATION),
1362  errmsg("updated partition constraint for default partition \"%s\" would be violated by some row",
1363  RelationGetRelationName(default_rel))));
1364 
1365  ResetExprContext(econtext);
1367  }
1368 
1369  MemoryContextSwitchTo(oldCxt);
1370  table_endscan(scan);
1371  UnregisterSnapshot(snapshot);
1373  FreeExecutorState(estate);
1374 
1375  if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
1376  table_close(part_rel, NoLock); /* keep the lock until commit */
1377  }
1378 }
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:872
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:501
List * map_partition_varattnos(List *expr, int fromrel_varno, Relation to_rel, Relation from_rel, bool *found_whole_row)
Definition: partition.c:201
#define ERROR
Definition: elog.h:43
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:736
#define NoLock
Definition: lockdefs.h:34
List * get_proposed_default_constraint(List *new_part_constraints)
Definition: partition.c:353
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
#define RelationGetRelationName(relation)
Definition: rel.h:456
#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:551
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:2283
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:223
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:799
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:381
#define GetPerTupleMemoryContext(estate)
Definition: executor.h:506
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:831
#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
#define RelationGetRelid(relation)
Definition: rel.h:422
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:2074
#define ResetExprContext(econtext)
Definition: executor.h:495
#define lfirst_oid(lc)
Definition: pg_list.h:192
bool PartConstraintImpliedByRelConstraint(Relation scanrel, List *partConstraint)
Definition: tablecmds.c:15318

◆ check_new_partition_bound()

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

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

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

◆ compute_partition_hash_value()

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

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

2741 {
2742  int i;
2743  uint64 rowHash = 0;
2745 
2746  for (i = 0; i < partnatts; i++)
2747  {
2748  /* Nulls are just ignored */
2749  if (!isnull[i])
2750  {
2751  Datum hash;
2752 
2753  Assert(OidIsValid(partsupfunc[i].fn_oid));
2754 
2755  /*
2756  * Compute hash for each datum value by calling respective
2757  * datatype-specific hash functions of each partition key
2758  * attribute.
2759  */
2760  hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
2761  values[i], seed);
2762 
2763  /* Form a single 64-bit hash value */
2764  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
2765  }
2766  }
2767 
2768  return rowHash;
2769 }
#define UInt64GetDatum(X)
Definition: postgres.h:648
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
#define OidIsValid(objectId)
Definition: c.h:645
static uint64 hash_combine64(uint64 a, uint64 b)
Definition: hashutils.h:48
uintptr_t Datum
Definition: postgres.h:367
#define DatumGetUInt64(X)
Definition: postgres.h:634
#define Assert(condition)
Definition: c.h:739
#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 1388 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().

1389 {
1390  Assert(bound && bound->strategy == PARTITION_STRATEGY_HASH);
1391  Assert(bound->datums && bound->ndatums > 0);
1392  Assert(DatumGetInt32(bound->datums[bound->ndatums - 1][0]) > 0);
1393 
1394  return DatumGetInt32(bound->datums[bound->ndatums - 1][0]);
1395 }
#define DatumGetInt32(X)
Definition: postgres.h:472
#define PARTITION_STRATEGY_HASH
Definition: parsenodes.h:798
#define Assert(condition)
Definition: c.h:739

◆ get_qual_from_partbound()

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

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

120 {
122  List *my_qual = NIL;
123 
124  Assert(key != NULL);
125 
126  switch (key->strategy)
127  {
130  my_qual = get_qual_for_hash(parent, spec);
131  break;
132 
135  my_qual = get_qual_for_list(parent, spec);
136  break;
137 
140  my_qual = get_qual_for_range(parent, spec, false);
141  break;
142 
143  default:
144  elog(ERROR, "unexpected partition strategy: %d",
145  (int) key->strategy);
146  }
147 
148  return my_qual;
149 }
#define NIL
Definition: pg_list.h:65
static List * get_qual_for_hash(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:1991
#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:2283
#define Assert(condition)
Definition: c.h:739
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:799
#define RelationGetPartitionKey(relation)
Definition: rel.h:603
#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:2074

◆ partition_bounds_copy()

PartitionBoundInfo partition_bounds_copy ( PartitionBoundInfo  src,
PartitionKey  key 
)

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

782 {
784  int i;
785  int ndatums;
786  int partnatts;
787  int num_indexes;
788 
790 
791  dest->strategy = src->strategy;
792  ndatums = dest->ndatums = src->ndatums;
793  partnatts = key->partnatts;
794 
795  num_indexes = get_partition_bound_num_indexes(src);
796 
797  /* List partitioned tables have only a single partition key. */
798  Assert(key->strategy != PARTITION_STRATEGY_LIST || partnatts == 1);
799 
800  dest->datums = (Datum **) palloc(sizeof(Datum *) * ndatums);
801 
802  if (src->kind != NULL)
803  {
804  dest->kind = (PartitionRangeDatumKind **) palloc(ndatums *
805  sizeof(PartitionRangeDatumKind *));
806  for (i = 0; i < ndatums; i++)
807  {
808  dest->kind[i] = (PartitionRangeDatumKind *) palloc(partnatts *
809  sizeof(PartitionRangeDatumKind));
810 
811  memcpy(dest->kind[i], src->kind[i],
812  sizeof(PartitionRangeDatumKind) * key->partnatts);
813  }
814  }
815  else
816  dest->kind = NULL;
817 
818  for (i = 0; i < ndatums; i++)
819  {
820  int j;
821 
822  /*
823  * For a corresponding to hash partition, datums array will have two
824  * elements - modulus and remainder.
825  */
826  bool hash_part = (key->strategy == PARTITION_STRATEGY_HASH);
827  int natts = hash_part ? 2 : partnatts;
828 
829  dest->datums[i] = (Datum *) palloc(sizeof(Datum) * natts);
830 
831  for (j = 0; j < natts; j++)
832  {
833  bool byval;
834  int typlen;
835 
836  if (hash_part)
837  {
838  typlen = sizeof(int32); /* Always int4 */
839  byval = true; /* int4 is pass-by-value */
840  }
841  else
842  {
843  byval = key->parttypbyval[j];
844  typlen = key->parttyplen[j];
845  }
846 
847  if (dest->kind == NULL ||
848  dest->kind[i][j] == PARTITION_RANGE_DATUM_VALUE)
849  dest->datums[i][j] = datumCopy(src->datums[i][j],
850  byval, typlen);
851  }
852  }
853 
854  dest->indexes = (int *) palloc(sizeof(int) * num_indexes);
855  memcpy(dest->indexes, src->indexes, sizeof(int) * num_indexes);
856 
857  dest->null_index = src->null_index;
858  dest->default_index = src->default_index;
859 
860  return dest;
861 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:64
PartitionRangeDatumKind
Definition: parsenodes.h:834
signed int int32
Definition: c.h:347
static int get_partition_bound_num_indexes(PartitionBoundInfo b)
Definition: partbounds.c:1797
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:130
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:739
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 173 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().

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

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

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

Referenced by check_new_partition_bound().

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

◆ partition_list_bsearch()

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

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

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

◆ 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 1665 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().

1668 {
1669  int lo,
1670  hi,
1671  mid;
1672 
1673  lo = -1;
1674  hi = boundinfo->ndatums - 1;
1675  while (lo < hi)
1676  {
1677  int32 cmpval;
1678 
1679  mid = (lo + hi + 1) / 2;
1680  cmpval = partition_rbound_datum_cmp(partsupfunc,
1681  partcollation,
1682  boundinfo->datums[mid],
1683  boundinfo->kind[mid],
1684  values,
1685  nvalues);
1686  if (cmpval <= 0)
1687  {
1688  lo = mid;
1689  *is_equal = (cmpval == 0);
1690 
1691  if (*is_equal)
1692  break;
1693  }
1694  else
1695  hi = mid - 1;
1696  }
1697 
1698  return lo;
1699 }
PartitionRangeDatumKind ** kind
Definition: partbounds.h:64
signed int int32
Definition: c.h:347
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:1525
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 1525 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().

1528 {
1529  int i;
1530  int32 cmpval = -1;
1531 
1532  for (i = 0; i < n_tuple_datums; i++)
1533  {
1534  if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
1535  return -1;
1536  else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
1537  return 1;
1538 
1539  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[i],
1540  partcollation[i],
1541  rb_datums[i],
1542  tuple_datums[i]));
1543  if (cmpval != 0)
1544  break;
1545  }
1546 
1547  return cmpval;
1548 }
#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:347
int i

◆ partitions_are_ordered()

bool partitions_are_ordered ( PartitionBoundInfo  boundinfo,
int  nparts 
)

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

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