mirror of
https://github.com/HypoPG/hypopg
synced 2026-05-24 09:38:21 +00:00
Add some postgres function that are imported as-is
This commit is contained in:
parent
01aa5accc8
commit
bfb7c74eff
2 changed files with 400 additions and 1 deletions
383
hypopg_import.c
383
hypopg_import.c
|
|
@ -34,7 +34,7 @@
|
|||
#include "catalog/pg_type.h"
|
||||
#include "nodes/nodeFuncs.h"
|
||||
#include "utils/ruleutils.h"
|
||||
#endif
|
||||
\#endif
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/planner.h"
|
||||
#include "optimizer/var.h"
|
||||
|
|
@ -51,6 +51,9 @@
|
|||
#include "include/hypopg_import.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Copied from src/backend/optimizer/util/plancat.c, not exported.
|
||||
*
|
||||
* Build a targetlist representing the columns of the specified index.
|
||||
|
|
@ -1183,4 +1186,382 @@ validateInfiniteBounds(ParseState *pstate, List *blist)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Imported from src/backend/catalog/partition.c, not exported
|
||||
*
|
||||
* get_partition_operator
|
||||
*
|
||||
* Return oid of the operator of given strategy for a given partition key
|
||||
* column.
|
||||
*/
|
||||
static Oid
|
||||
get_partition_operator(PartitionKey key, int col, StrategyNumber strategy,
|
||||
bool *need_relabel)
|
||||
{
|
||||
Oid operoid;
|
||||
|
||||
/*
|
||||
* First check if there exists an operator of the given strategy, with
|
||||
* this column's type as both its lefttype and righttype, in the
|
||||
* partitioning operator family specified for the column.
|
||||
*/
|
||||
operoid = get_opfamily_member(key->partopfamily[col],
|
||||
key->parttypid[col],
|
||||
key->parttypid[col],
|
||||
strategy);
|
||||
|
||||
/*
|
||||
* If one doesn't exist, we must resort to using an operator in the same
|
||||
* operator family but with the operator class declared input type. It is
|
||||
* OK to do so, because the column's type is known to be binary-coercible
|
||||
* with the operator class input type (otherwise, the operator class in
|
||||
* question would not have been accepted as the partitioning operator
|
||||
* class). We must however inform the caller to wrap the non-Const
|
||||
* expression with a RelabelType node to denote the implicit coercion. It
|
||||
* ensures that the resulting expression structurally matches similarly
|
||||
* processed expressions within the optimizer.
|
||||
*/
|
||||
if (!OidIsValid(operoid))
|
||||
{
|
||||
operoid = get_opfamily_member(key->partopfamily[col],
|
||||
key->partopcintype[col],
|
||||
key->partopcintype[col],
|
||||
strategy);
|
||||
if (!OidIsValid(operoid))
|
||||
elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
|
||||
strategy, key->partopcintype[col], key->partopcintype[col],
|
||||
key->partopfamily[col]);
|
||||
*need_relabel = true;
|
||||
}
|
||||
else
|
||||
*need_relabel = false;
|
||||
|
||||
return operoid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Copied from src/backend/catalog/partition.c, not exported
|
||||
*
|
||||
* make_partition_op_expr
|
||||
* Returns an Expr for the given partition key column with arg1 and
|
||||
* arg2 as its leftop and rightop, respectively
|
||||
*/
|
||||
static Expr *
|
||||
make_partition_op_expr(PartitionKey key, int keynum,
|
||||
uint16 strategy, Expr *arg1, Expr *arg2)
|
||||
{
|
||||
Oid operoid;
|
||||
bool need_relabel = false;
|
||||
Expr *result = NULL;
|
||||
|
||||
/* Get the correct btree operator for this partitioning column */
|
||||
operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
|
||||
|
||||
/*
|
||||
* Chosen operator may be such that the non-Const operand needs to be
|
||||
* coerced, so apply the same; see the comment in
|
||||
* get_partition_operator().
|
||||
*/
|
||||
if (!IsA(arg1, Const) &&
|
||||
(need_relabel ||
|
||||
key->partcollation[keynum] != key->parttypcoll[keynum]))
|
||||
arg1 = (Expr *) makeRelabelType(arg1,
|
||||
key->partopcintype[keynum],
|
||||
-1,
|
||||
key->partcollation[keynum],
|
||||
COERCE_EXPLICIT_CAST);
|
||||
|
||||
/* Generate the actual expression */
|
||||
switch (key->strategy)
|
||||
{
|
||||
case PARTITION_STRATEGY_LIST:
|
||||
{
|
||||
List *elems = (List *) arg2;
|
||||
int nelems = list_length(elems);
|
||||
|
||||
Assert(nelems >= 1);
|
||||
Assert(keynum == 0);
|
||||
|
||||
if (nelems > 1 &&
|
||||
!type_is_array(key->parttypid[keynum]))
|
||||
{
|
||||
ArrayExpr *arrexpr;
|
||||
ScalarArrayOpExpr *saopexpr;
|
||||
|
||||
/* Construct an ArrayExpr for the right-hand inputs */
|
||||
arrexpr = makeNode(ArrayExpr);
|
||||
arrexpr->array_typeid =
|
||||
get_array_type(key->parttypid[keynum]);
|
||||
arrexpr->array_collid = key->parttypcoll[keynum];
|
||||
arrexpr->element_typeid = key->parttypid[keynum];
|
||||
arrexpr->elements = elems;
|
||||
arrexpr->multidims = false;
|
||||
arrexpr->location = -1;
|
||||
|
||||
/* Build leftop = ANY (rightop) */
|
||||
saopexpr = makeNode(ScalarArrayOpExpr);
|
||||
saopexpr->opno = operoid;
|
||||
saopexpr->opfuncid = get_opcode(operoid);
|
||||
saopexpr->useOr = true;
|
||||
saopexpr->inputcollid = key->partcollation[keynum];
|
||||
saopexpr->args = list_make2(arg1, arrexpr);
|
||||
saopexpr->location = -1;
|
||||
|
||||
result = (Expr *) saopexpr;
|
||||
}
|
||||
else
|
||||
{
|
||||
List *elemops = NIL;
|
||||
ListCell *lc;
|
||||
|
||||
foreach (lc, elems)
|
||||
{
|
||||
Expr *elem = lfirst(lc),
|
||||
*elemop;
|
||||
|
||||
elemop = make_opclause(operoid,
|
||||
BOOLOID,
|
||||
false,
|
||||
arg1, elem,
|
||||
InvalidOid,
|
||||
key->partcollation[keynum]);
|
||||
elemops = lappend(elemops, elemop);
|
||||
}
|
||||
|
||||
result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PARTITION_STRATEGY_RANGE:
|
||||
result = make_opclause(operoid,
|
||||
BOOLOID,
|
||||
false,
|
||||
arg1, arg2,
|
||||
InvalidOid,
|
||||
key->partcollation[keynum]);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "invalid partitioning strategy");
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from src/backend/catalog/partition.c, not exported
|
||||
*
|
||||
* get_range_key_properties
|
||||
* Returns range partition key information for a given column
|
||||
*
|
||||
* This is a subroutine for get_qual_for_range, and its API is pretty
|
||||
* specialized to that caller.
|
||||
*
|
||||
* Constructs an Expr for the key column (returned in *keyCol) and Consts
|
||||
* for the lower and upper range limits (returned in *lower_val and
|
||||
* *upper_val). For MINVALUE/MAXVALUE limits, NULL is returned instead of
|
||||
* a Const. All of these structures are freshly palloc'd.
|
||||
*
|
||||
* *partexprs_item points to the cell containing the next expression in
|
||||
* the key->partexprs list, or NULL. It may be advanced upon return.
|
||||
*/
|
||||
static void
|
||||
get_range_key_properties(PartitionKey key, int keynum,
|
||||
PartitionRangeDatum *ldatum,
|
||||
PartitionRangeDatum *udatum,
|
||||
ListCell **partexprs_item,
|
||||
Expr **keyCol,
|
||||
Const **lower_val, Const **upper_val)
|
||||
{
|
||||
/* Get partition key expression for this column */
|
||||
if (key->partattrs[keynum] != 0)
|
||||
{
|
||||
*keyCol = (Expr *) makeVar(1,
|
||||
key->partattrs[keynum],
|
||||
key->parttypid[keynum],
|
||||
key->parttypmod[keynum],
|
||||
key->parttypcoll[keynum],
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*partexprs_item == NULL)
|
||||
elog(ERROR, "wrong number of partition key expressions");
|
||||
*keyCol = copyObject(lfirst(*partexprs_item));
|
||||
*partexprs_item = lnext(*partexprs_item);
|
||||
}
|
||||
|
||||
/* Get appropriate Const nodes for the bounds */
|
||||
if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
|
||||
*lower_val = castNode(Const, copyObject(ldatum->value));
|
||||
else
|
||||
*lower_val = NULL;
|
||||
|
||||
if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
|
||||
*upper_val = castNode(Const, copyObject(udatum->value));
|
||||
else
|
||||
*upper_val = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Copied from src/backend/catalog/partition.c, not exported
|
||||
*
|
||||
* get_range_nulltest
|
||||
*
|
||||
* A non-default range partition table does not currently allow partition
|
||||
* keys to be null, so emit an IS NOT NULL expression for each key column.
|
||||
*/
|
||||
static List *
|
||||
get_range_nulltest(PartitionKey key)
|
||||
{
|
||||
List *result = NIL;
|
||||
NullTest *nulltest;
|
||||
ListCell *partexprs_item;
|
||||
int i;
|
||||
|
||||
partexprs_item = list_head(key->partexprs);
|
||||
for (i = 0; i < key->partnatts; i++)
|
||||
{
|
||||
Expr *keyCol;
|
||||
|
||||
if (key->partattrs[i] != 0)
|
||||
{
|
||||
keyCol = (Expr *) makeVar(1,
|
||||
key->partattrs[i],
|
||||
key->parttypid[i],
|
||||
key->parttypmod[i],
|
||||
key->parttypcoll[i],
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (partexprs_item == NULL)
|
||||
elog(ERROR, "wrong number of partition key expressions");
|
||||
keyCol = copyObject(lfirst(partexprs_item));
|
||||
partexprs_item = lnext(partexprs_item);
|
||||
}
|
||||
|
||||
nulltest = makeNode(NullTest);
|
||||
nulltest->arg = keyCol;
|
||||
nulltest->nulltesttype = IS_NOT_NULL;
|
||||
nulltest->argisrow = false;
|
||||
nulltest->location = -1;
|
||||
result = lappend(result, nulltest);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Copied from src/backend/optimizer/prep/prepunion.c, not exported
|
||||
*
|
||||
* make_inh_translation_list
|
||||
* Build the list of translations from parent Vars to child Vars for
|
||||
* an inheritance child.
|
||||
*
|
||||
* For paranoia's sake, we match type/collation as well as attribute name.
|
||||
*/
|
||||
static void
|
||||
make_inh_translation_list(Relation oldrelation, Relation newrelation,
|
||||
Index newvarno,
|
||||
List **translated_vars)
|
||||
{
|
||||
List *vars = NIL;
|
||||
TupleDesc old_tupdesc = RelationGetDescr(oldrelation);
|
||||
TupleDesc new_tupdesc = RelationGetDescr(newrelation);
|
||||
int oldnatts = old_tupdesc->natts;
|
||||
int newnatts = new_tupdesc->natts;
|
||||
int old_attno;
|
||||
|
||||
for (old_attno = 0; old_attno < oldnatts; old_attno++)
|
||||
{
|
||||
Form_pg_attribute att;
|
||||
char *attname;
|
||||
Oid atttypid;
|
||||
int32 atttypmod;
|
||||
Oid attcollation;
|
||||
int new_attno;
|
||||
|
||||
att = TupleDescAttr(old_tupdesc, old_attno);
|
||||
if (att->attisdropped)
|
||||
{
|
||||
/* Just put NULL into this list entry */
|
||||
vars = lappend(vars, NULL);
|
||||
continue;
|
||||
}
|
||||
attname = NameStr(att->attname);
|
||||
atttypid = att->atttypid;
|
||||
atttypmod = att->atttypmod;
|
||||
attcollation = att->attcollation;
|
||||
|
||||
/*
|
||||
* When we are generating the "translation list" for the parent table
|
||||
* of an inheritance set, no need to search for matches.
|
||||
*/
|
||||
if (oldrelation == newrelation)
|
||||
{
|
||||
vars = lappend(vars, makeVar(newvarno,
|
||||
(AttrNumber) (old_attno + 1),
|
||||
atttypid,
|
||||
atttypmod,
|
||||
attcollation,
|
||||
0));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise we have to search for the matching column by name.
|
||||
* There's no guarantee it'll have the same column position, because
|
||||
* of cases like ALTER TABLE ADD COLUMN and multiple inheritance.
|
||||
* However, in simple cases it will be the same column number, so try
|
||||
* that before we go groveling through all the columns.
|
||||
*
|
||||
* Note: the test for (att = ...) != NULL cannot fail, it's just a
|
||||
* notational device to include the assignment into the if-clause.
|
||||
*/
|
||||
if (old_attno < newnatts &&
|
||||
(att = TupleDescAttr(new_tupdesc, old_attno)) != NULL &&
|
||||
!att->attisdropped && att->attinhcount != 0 &&
|
||||
strcmp(attname, NameStr(att->attname)) == 0)
|
||||
new_attno = old_attno;
|
||||
else
|
||||
{
|
||||
for (new_attno = 0; new_attno < newnatts; new_attno++)
|
||||
{
|
||||
att = TupleDescAttr(new_tupdesc, new_attno);
|
||||
if (!att->attisdropped && att->attinhcount != 0 &&
|
||||
strcmp(attname, NameStr(att->attname)) == 0)
|
||||
break;
|
||||
}
|
||||
if (new_attno >= newnatts)
|
||||
elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
|
||||
attname, RelationGetRelationName(newrelation));
|
||||
}
|
||||
|
||||
/* Found it, check type and collation match */
|
||||
if (atttypid != att->atttypid || atttypmod != att->atttypmod)
|
||||
elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
|
||||
attname, RelationGetRelationName(newrelation));
|
||||
if (attcollation != att->attcollation)
|
||||
elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's collation",
|
||||
attname, RelationGetRelationName(newrelation));
|
||||
|
||||
vars = lappend(vars, makeVar(newvarno,
|
||||
(AttrNumber) (new_attno + 1),
|
||||
atttypid,
|
||||
atttypmod,
|
||||
attcollation,
|
||||
0));
|
||||
}
|
||||
|
||||
*translated_vars = vars;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -118,5 +118,23 @@ void simple_quote_literal(StringInfo buf, const char *val);
|
|||
Const *transformPartitionBoundValue(ParseState *pstate, A_Const *con,
|
||||
const char *colName, Oid colType, int32 colTypmod);
|
||||
void validateInfiniteBounds(ParseState *pstate, List *blist);
|
||||
Oid get_partition_operator(PartitionKey key, int col, StrategyNumber strategy,
|
||||
bool *need_relabel);
|
||||
Expr *make_partition_op_expr(PartitionKey key, int keynum,
|
||||
uint16 strategy, Expr *arg1, Expr *arg2);
|
||||
void get_range_key_properties(PartitionKey key, int keynum,
|
||||
PartitionRangeDatum *ldatum,
|
||||
PartitionRangeDatum *udatum,
|
||||
ListCell **partexprs_item,
|
||||
Expr **keyCol,
|
||||
Const **lower_val, Const **upper_val);
|
||||
List *get_range_nulltest(PartitionKey key);
|
||||
void make_inh_translation_list(Relation oldrelation, Relation newrelation,
|
||||
Index newvarno,
|
||||
List **translated_vars);
|
||||
|
||||
/* Copied from src/backend/catalog/partition.c, not exported */
|
||||
#define partition_bound_accepts_nulls(bi) ((bi)->null_index != -1)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue