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

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

◆ check_new_partition_bound()

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

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

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

◆ compute_partition_hash_value()

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

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

2742 {
2743  int i;
2744  uint64 rowHash = 0;
2746 
2747  for (i = 0; i < partnatts; i++)
2748  {
2749  /* Nulls are just ignored */
2750  if (!isnull[i])
2751  {
2752  Datum hash;
2753 
2754  Assert(OidIsValid(partsupfunc[i].fn_oid));
2755 
2756  /*
2757  * Compute hash for each datum value by calling respective
2758  * datatype-specific hash functions of each partition key
2759  * attribute.
2760  */
2761  hash = FunctionCall2Coll(&partsupfunc[i], partcollation[i],
2762  values[i], seed);
2763 
2764  /* Form a single 64-bit hash value */
2765  rowHash = hash_combine64(rowHash, DatumGetUInt64(hash));
2766  }
2767  }
2768 
2769  return rowHash;
2770 }
#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:638
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:732
#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 1389 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().

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

◆ 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:1992
#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:2284
#define Assert(condition)
Definition: c.h:732
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:799
#define RelationGetPartitionKey(relation)
Definition: rel.h:600
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:800
#define elog(elevel,...)
Definition: elog.h:226
Definition: pg_list.h:50
static List * get_qual_for_list(Relation parent, PartitionBoundSpec *spec)
Definition: partbounds.c:2075

◆ partition_bounds_copy()

PartitionBoundInfo partition_bounds_copy ( PartitionBoundInfo  src,
PartitionKey  key 
)

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

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

◆ partition_bounds_equal()

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

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

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

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

Referenced by check_new_partition_bound().

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

◆ partition_list_bsearch()

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

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

1580 {
1581  int lo,
1582  hi,
1583  mid;
1584 
1585  lo = -1;
1586  hi = boundinfo->ndatums - 1;
1587  while (lo < hi)
1588  {
1589  int32 cmpval;
1590 
1591  mid = (lo + hi + 1) / 2;
1592  cmpval = DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
1593  partcollation[0],
1594  boundinfo->datums[mid][0],
1595  value));
1596  if (cmpval <= 0)
1597  {
1598  lo = mid;
1599  *is_equal = (cmpval == 0);
1600  if (*is_equal)
1601  break;
1602  }
1603  else
1604  hi = mid - 1;
1605  }
1606 
1607  return lo;
1608 }
#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:346

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

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

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

◆ partitions_are_ordered()

bool partitions_are_ordered ( PartitionBoundInfo  boundinfo,
int  nparts 
)

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

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