mirror of
https://github.com/HypoPG/hypopg
synced 2026-05-24 01:28:51 +00:00
Split imported code in multiple files in a dedicated directory
This commit is contained in:
parent
8424300cb9
commit
5d887319f3
10 changed files with 734 additions and 598 deletions
6
Makefile
6
Makefile
|
|
@ -12,7 +12,11 @@ REGRESS_OPTS = --inputdir=test
|
|||
PG_CONFIG ?= pg_config
|
||||
|
||||
MODULE_big = hypopg
|
||||
OBJS = hypopg.o hypopg_import.o hypopg_analyze.o hypopg_index.o hypopg_table.o
|
||||
|
||||
OBJS = hypopg.o \
|
||||
hypopg_analyze.o hypopg_index.o hypopg_table.o \
|
||||
import/hypopg_import.o import/hypopg_import_analyze.o \
|
||||
import/hypopg_import_index.o import/hypopg_import_table.o
|
||||
|
||||
all:
|
||||
|
||||
|
|
|
|||
|
|
@ -101,8 +101,10 @@ static void hypo_estimate_index_simple(hypoIndex *entry,
|
|||
static void hypo_estimate_index(hypoIndex *entry, RelOptInfo *rel,
|
||||
PlannerInfo *root);
|
||||
static int hypo_estimate_index_colsize(hypoIndex *entry, int col);
|
||||
#if PG_VERSION_NUM >= 110000
|
||||
static void hypo_index_check_uniqueness_compatibility(IndexStmt *stmt,
|
||||
Oid relid, hypoIndex *entry);
|
||||
#endif
|
||||
static void hypo_index_pfree(hypoIndex *entry);
|
||||
static bool hypo_index_remove(Oid indexid);
|
||||
static const hypoIndex *hypo_index_store_parsetree(IndexStmt *node,
|
||||
|
|
|
|||
68
import/hypopg_import.c
Normal file
68
import/hypopg_import.c
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* hypopg_import.c: Import of some PostgreSQL private fuctions.
|
||||
*
|
||||
* This program is open source, licensed under the PostgreSQL license.
|
||||
* For license terms, see the LICENSE file.
|
||||
*
|
||||
* Copyright (c) 2008-2018, PostgreSQL Global Development Group
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#include "postgres.h"
|
||||
#if PG_VERSION_NUM >= 90300
|
||||
#include "access/htup_details.h"
|
||||
#endif
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "commands/defrem.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
#include "include/hypopg_import.h"
|
||||
|
||||
/*
|
||||
* Copied from src/backend/utils/adt/ruleutils.c, not exported.
|
||||
*
|
||||
* get_opclass_name - fetch name of an index operator class
|
||||
*
|
||||
* The opclass name is appended (after a space) to buf.
|
||||
*
|
||||
* Output is suppressed if the opclass is the default for the given
|
||||
* actual_datatype. (If you don't want this behavior, just pass
|
||||
* InvalidOid for actual_datatype.)
|
||||
*/
|
||||
void
|
||||
get_opclass_name(Oid opclass, Oid actual_datatype,
|
||||
StringInfo buf)
|
||||
{
|
||||
HeapTuple ht_opc;
|
||||
Form_pg_opclass opcrec;
|
||||
char *opcname;
|
||||
char *nspname;
|
||||
|
||||
ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
|
||||
if (!HeapTupleIsValid(ht_opc))
|
||||
elog(ERROR, "cache lookup failed for opclass %u", opclass);
|
||||
opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
|
||||
|
||||
if (!OidIsValid(actual_datatype) ||
|
||||
GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
|
||||
{
|
||||
/* Okay, we need the opclass name. Do we need to qualify it? */
|
||||
opcname = NameStr(opcrec->opcname);
|
||||
if (OpclassIsVisible(opclass))
|
||||
appendStringInfo(buf, " %s", quote_identifier(opcname));
|
||||
else
|
||||
{
|
||||
nspname = get_namespace_name(opcrec->opcnamespace);
|
||||
appendStringInfo(buf, " %s.%s",
|
||||
quote_identifier(nspname),
|
||||
quote_identifier(opcname));
|
||||
}
|
||||
}
|
||||
ReleaseSysCache(ht_opc);
|
||||
}
|
||||
143
import/hypopg_import_analyze.c
Normal file
143
import/hypopg_import_analyze.c
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* hypopg_import_analyze.c: Import of some PostgreSQL private fuctions, used
|
||||
* for hypothetical analyze.
|
||||
*
|
||||
* This program is open source, licensed under the PostgreSQL license.
|
||||
* For license terms, see the LICENSE file.
|
||||
*
|
||||
* Copyright (c) 2008-2018, PostgreSQL Global Development Group
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#include "postgres.h"
|
||||
#if PG_VERSION_NUM >= 100000
|
||||
|
||||
#if PG_VERSION_NUM >= 90300
|
||||
#include "access/htup_details.h"
|
||||
#endif
|
||||
#include "nodes/nodeFuncs.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "include/hypopg_import.h"
|
||||
|
||||
|
||||
/*
|
||||
* Copied from src/backend/commands/analyze.c/, not exported
|
||||
*
|
||||
* examine_attribute -- pre-analysis of a single column
|
||||
*
|
||||
* Determine whether the column is analyzable; if so, create and initialize
|
||||
* a VacAttrStats struct for it. If not, return NULL.
|
||||
*
|
||||
* If index_expr isn't NULL, then we're trying to analyze an expression index,
|
||||
* and index_expr is the expression tree representing the column's data.
|
||||
*/
|
||||
VacAttrStats *
|
||||
examine_attribute(Relation onerel, int attnum, Node *index_expr)
|
||||
{
|
||||
Form_pg_attribute attr = TupleDescAttr(onerel->rd_att, attnum - 1);
|
||||
HeapTuple typtuple;
|
||||
VacAttrStats *stats;
|
||||
int i;
|
||||
bool ok;
|
||||
|
||||
/* Never analyze dropped columns */
|
||||
if (attr->attisdropped)
|
||||
return NULL;
|
||||
|
||||
/* Don't analyze column if user has specified not to */
|
||||
if (attr->attstattarget == 0)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Create the VacAttrStats struct. Note that we only have a copy of the
|
||||
* fixed fields of the pg_attribute tuple.
|
||||
*/
|
||||
stats = (VacAttrStats *) palloc0(sizeof(VacAttrStats));
|
||||
stats->attr = (Form_pg_attribute) palloc(ATTRIBUTE_FIXED_PART_SIZE);
|
||||
memcpy(stats->attr, attr, ATTRIBUTE_FIXED_PART_SIZE);
|
||||
|
||||
/*
|
||||
* When analyzing an expression index, believe the expression tree's type
|
||||
* not the column datatype --- the latter might be the opckeytype storage
|
||||
* type of the opclass, which is not interesting for our purposes. (Note:
|
||||
* if we did anything with non-expression index columns, we'd need to
|
||||
* figure out where to get the correct type info from, but for now that's
|
||||
* not a problem.) It's not clear whether anyone will care about the
|
||||
* typmod, but we store that too just in case.
|
||||
*/
|
||||
if (index_expr)
|
||||
{
|
||||
stats->attrtypid = exprType(index_expr);
|
||||
stats->attrtypmod = exprTypmod(index_expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
stats->attrtypid = attr->atttypid;
|
||||
stats->attrtypmod = attr->atttypmod;
|
||||
}
|
||||
|
||||
typtuple = SearchSysCacheCopy1(TYPEOID,
|
||||
ObjectIdGetDatum(stats->attrtypid));
|
||||
if (!HeapTupleIsValid(typtuple))
|
||||
elog(ERROR, "cache lookup failed for type %u", stats->attrtypid);
|
||||
stats->attrtype = (Form_pg_type) GETSTRUCT(typtuple);
|
||||
//FIXME
|
||||
stats->anl_context = CurrentMemoryContext;
|
||||
stats->tupattnum = attnum;
|
||||
|
||||
/*
|
||||
* The fields describing the stats->stavalues[n] element types default to
|
||||
* the type of the data being analyzed, but the type-specific typanalyze
|
||||
* function can change them if it wants to store something else.
|
||||
*/
|
||||
for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
|
||||
{
|
||||
stats->statypid[i] = stats->attrtypid;
|
||||
stats->statyplen[i] = stats->attrtype->typlen;
|
||||
stats->statypbyval[i] = stats->attrtype->typbyval;
|
||||
stats->statypalign[i] = stats->attrtype->typalign;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the type-specific typanalyze function. If none is specified, use
|
||||
* std_typanalyze().
|
||||
*/
|
||||
if (OidIsValid(stats->attrtype->typanalyze))
|
||||
ok = DatumGetBool(OidFunctionCall1(stats->attrtype->typanalyze,
|
||||
PointerGetDatum(stats)));
|
||||
else
|
||||
ok = std_typanalyze(stats);
|
||||
|
||||
if (!ok || stats->compute_stats == NULL || stats->minrows <= 0)
|
||||
{
|
||||
heap_freetuple(typtuple);
|
||||
pfree(stats->attr);
|
||||
pfree(stats);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from src/backend/commands/analyze.c, not exported
|
||||
*
|
||||
* Standard fetch function for use by compute_stats subroutines.
|
||||
*
|
||||
* This exists to provide some insulation between compute_stats routines
|
||||
* and the actual storage of the sample data.
|
||||
*/
|
||||
Datum
|
||||
std_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull)
|
||||
{
|
||||
int attnum = stats->tupattnum;
|
||||
HeapTuple tuple = stats->rows[rownum];
|
||||
TupleDesc tupDesc = stats->tupDesc;
|
||||
|
||||
return heap_getattr(tuple, attnum, tupDesc, isNull);
|
||||
}
|
||||
|
||||
#endif /* pg10+ */
|
||||
297
import/hypopg_import_index.c
Normal file
297
import/hypopg_import_index.c
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* hypopg_import_index.c: Import of some PostgreSQL private fuctions, used for
|
||||
* hypothetical index.
|
||||
*
|
||||
* This program is open source, licensed under the PostgreSQL license.
|
||||
* For license terms, see the LICENSE file.
|
||||
*
|
||||
* Copyright (c) 2008-2018, PostgreSQL Global Development Group
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
#if PG_VERSION_NUM >= 90300
|
||||
#include "access/htup_details.h"
|
||||
#endif
|
||||
#include "catalog/heap.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "commands/defrem.h"
|
||||
#include "commands/vacuum.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "nodes/pg_list.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/planner.h"
|
||||
#include "optimizer/pathnode.h"
|
||||
#if PG_VERSION_NUM >= 110000
|
||||
#include "partitioning/partbounds.h"
|
||||
#endif
|
||||
#include "parser/parse_coerce.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "include/hypopg.h"
|
||||
|
||||
/* Copied from src/backend/optimizer/util/plancat.c, not exported.
|
||||
*
|
||||
* Build a targetlist representing the columns of the specified index.
|
||||
* Each column is represented by a Var for the corresponding base-relation
|
||||
* column, or an expression in base-relation Vars, as appropriate.
|
||||
*
|
||||
* There are never any dropped columns in indexes, so unlike
|
||||
* build_physical_tlist, we need no failure case.
|
||||
*/
|
||||
List *
|
||||
build_index_tlist(PlannerInfo *root, IndexOptInfo *index,
|
||||
Relation heapRelation)
|
||||
{
|
||||
List *tlist = NIL;
|
||||
Index varno = index->rel->relid;
|
||||
ListCell *indexpr_item;
|
||||
int i;
|
||||
|
||||
indexpr_item = list_head(index->indexprs);
|
||||
for (i = 0; i < index->ncolumns; i++)
|
||||
{
|
||||
int indexkey = index->indexkeys[i];
|
||||
Expr *indexvar;
|
||||
|
||||
if (indexkey != 0)
|
||||
{
|
||||
/* simple column */
|
||||
const FormData_pg_attribute *att_tup;
|
||||
|
||||
if (indexkey < 0)
|
||||
att_tup = SystemAttributeDefinition(indexkey,
|
||||
heapRelation->rd_rel->relhasoids);
|
||||
else
|
||||
#if PG_VERSION_NUM >= 110000
|
||||
att_tup = TupleDescAttr(heapRelation->rd_att, indexkey - 1);
|
||||
#else
|
||||
att_tup = heapRelation->rd_att->attrs[indexkey - 1];
|
||||
#endif
|
||||
|
||||
indexvar = (Expr *) makeVar(varno,
|
||||
indexkey,
|
||||
att_tup->atttypid,
|
||||
att_tup->atttypmod,
|
||||
att_tup->attcollation,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* expression column */
|
||||
if (indexpr_item == NULL)
|
||||
elog(ERROR, "wrong number of index expressions");
|
||||
indexvar = (Expr *) lfirst(indexpr_item);
|
||||
indexpr_item = lnext(indexpr_item);
|
||||
}
|
||||
|
||||
tlist = lappend(tlist,
|
||||
makeTargetEntry(indexvar,
|
||||
i + 1,
|
||||
NULL,
|
||||
false));
|
||||
}
|
||||
if (indexpr_item != NULL)
|
||||
elog(ERROR, "wrong number of index expressions");
|
||||
|
||||
return tlist;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from src/backend/commands/indexcmds.c, not exported.
|
||||
* Resolve possibly-defaulted operator class specification
|
||||
*/
|
||||
Oid
|
||||
GetIndexOpClass(List *opclass, Oid attrType,
|
||||
char *accessMethodName, Oid accessMethodId)
|
||||
{
|
||||
char *schemaname;
|
||||
char *opcname;
|
||||
HeapTuple tuple;
|
||||
Oid opClassId,
|
||||
opInputType;
|
||||
|
||||
/*
|
||||
* Release 7.0 removed network_ops, timespan_ops, and datetime_ops, so we
|
||||
* ignore those opclass names so the default *_ops is used. This can be
|
||||
* removed in some later release. bjm 2000/02/07
|
||||
*
|
||||
* Release 7.1 removes lztext_ops, so suppress that too for a while. tgl
|
||||
* 2000/07/30
|
||||
*
|
||||
* Release 7.2 renames timestamp_ops to timestamptz_ops, so suppress that
|
||||
* too for awhile. I'm starting to think we need a better approach. tgl
|
||||
* 2000/10/01
|
||||
*
|
||||
* Release 8.0 removes bigbox_ops (which was dead code for a long while
|
||||
* anyway). tgl 2003/11/11
|
||||
*/
|
||||
if (list_length(opclass) == 1)
|
||||
{
|
||||
char *claname = strVal(linitial(opclass));
|
||||
|
||||
if (strcmp(claname, "network_ops") == 0 ||
|
||||
strcmp(claname, "timespan_ops") == 0 ||
|
||||
strcmp(claname, "datetime_ops") == 0 ||
|
||||
strcmp(claname, "lztext_ops") == 0 ||
|
||||
strcmp(claname, "timestamp_ops") == 0 ||
|
||||
strcmp(claname, "bigbox_ops") == 0)
|
||||
opclass = NIL;
|
||||
}
|
||||
|
||||
if (opclass == NIL)
|
||||
{
|
||||
/* no operator class specified, so find the default */
|
||||
opClassId = GetDefaultOpClass(attrType, accessMethodId);
|
||||
if (!OidIsValid(opClassId))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("data type %s has no default operator class for access method \"%s\"",
|
||||
format_type_be(attrType), accessMethodName),
|
||||
errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
|
||||
return opClassId;
|
||||
}
|
||||
|
||||
/*
|
||||
* Specific opclass name given, so look up the opclass.
|
||||
*/
|
||||
|
||||
/* deconstruct the name list */
|
||||
DeconstructQualifiedName(opclass, &schemaname, &opcname);
|
||||
|
||||
if (schemaname)
|
||||
{
|
||||
/* Look in specific schema only */
|
||||
Oid namespaceId;
|
||||
|
||||
#if PG_VERSION_NUM >= 90300
|
||||
namespaceId = LookupExplicitNamespace(schemaname, false);
|
||||
#else
|
||||
namespaceId = LookupExplicitNamespace(schemaname);
|
||||
#endif
|
||||
tuple = SearchSysCache3(CLAAMNAMENSP,
|
||||
ObjectIdGetDatum(accessMethodId),
|
||||
PointerGetDatum(opcname),
|
||||
ObjectIdGetDatum(namespaceId));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unqualified opclass name, so search the search path */
|
||||
opClassId = OpclassnameGetOpcid(accessMethodId, opcname);
|
||||
if (!OidIsValid(opClassId))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("operator class \"%s\" does not exist for access method \"%s\"",
|
||||
opcname, accessMethodName)));
|
||||
tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opClassId));
|
||||
}
|
||||
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("operator class \"%s\" does not exist for access method \"%s\"",
|
||||
NameListToString(opclass), accessMethodName)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that the index operator class accepts this datatype. Note we
|
||||
* will accept binary compatibility.
|
||||
*/
|
||||
opClassId = HeapTupleGetOid(tuple);
|
||||
opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype;
|
||||
|
||||
if (!IsBinaryCoercible(attrType, opInputType))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("operator class \"%s\" does not accept data type %s",
|
||||
NameListToString(opclass), format_type_be(attrType))));
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
return opClassId;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from src/backend/commands/indexcmds.c, not exported.
|
||||
* CheckPredicate
|
||||
* Checks that the given partial-index predicate is valid.
|
||||
*
|
||||
* This used to also constrain the form of the predicate to forms that
|
||||
* indxpath.c could do something with. However, that seems overly
|
||||
* restrictive. One useful application of partial indexes is to apply
|
||||
* a UNIQUE constraint across a subset of a table, and in that scenario
|
||||
* any evaluatable predicate will work. So accept any predicate here
|
||||
* (except ones requiring a plan), and let indxpath.c fend for itself.
|
||||
*/
|
||||
void
|
||||
CheckPredicate(Expr *predicate)
|
||||
{
|
||||
/*
|
||||
* transformExpr() should have already rejected subqueries, aggregates,
|
||||
* and window functions, based on the EXPR_KIND_ for a predicate.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A predicate using mutable functions is probably wrong, for the same
|
||||
* reasons that we don't allow an index expression to use one.
|
||||
*/
|
||||
if (CheckMutability(predicate))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||
errmsg("functions in index predicate must be marked IMMUTABLE")));
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from src/backend/commands/indexcmds.c, not exported.
|
||||
* CheckMutability
|
||||
* Test whether given expression is mutable
|
||||
*/
|
||||
bool
|
||||
CheckMutability(Expr *expr)
|
||||
{
|
||||
/*
|
||||
* First run the expression through the planner. This has a couple of
|
||||
* important consequences. First, function default arguments will get
|
||||
* inserted, which may affect volatility (consider "default now()").
|
||||
* Second, inline-able functions will get inlined, which may allow us to
|
||||
* conclude that the function is really less volatile than it's marked. As
|
||||
* an example, polymorphic functions must be marked with the most volatile
|
||||
* behavior that they have for any input type, but once we inline the
|
||||
* function we may be able to conclude that it's not so volatile for the
|
||||
* particular input type we're dealing with.
|
||||
*
|
||||
* We assume here that expression_planner() won't scribble on its input.
|
||||
*/
|
||||
expr = expression_planner(expr);
|
||||
|
||||
/* Now we can search for non-immutable functions */
|
||||
return contain_mutable_functions((Node *) expr);
|
||||
}
|
||||
|
||||
#if PG_VERSION_NUM < 90500
|
||||
/*
|
||||
* Copied from src/backend/commands/amcmds.c
|
||||
*
|
||||
* get_am_name - given an access method OID name and type, look up its name.
|
||||
*/
|
||||
char *
|
||||
get_am_name(Oid amOid)
|
||||
{
|
||||
HeapTuple tup;
|
||||
char *result = NULL;
|
||||
|
||||
tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
|
||||
if (HeapTupleIsValid(tup))
|
||||
{
|
||||
Form_pg_am amform = (Form_pg_am) GETSTRUCT(tup);
|
||||
|
||||
result = pstrdup(NameStr(amform->amname));
|
||||
ReleaseSysCache(tup);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* hypopg_import.c: Import of some PostgreSQL private fuctions.
|
||||
* hypopg_import_table.c: Import of some PostgreSQL private fuctions, used
|
||||
* for hypothetical partitioning.
|
||||
*
|
||||
* This program is open source, licensed under the PostgreSQL license.
|
||||
* For license terms, see the LICENSE file.
|
||||
|
|
@ -10,44 +11,22 @@
|
|||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#if PG_VERSION_NUM >= 90300
|
||||
#include "access/htup_details.h"
|
||||
#endif
|
||||
#if PG_VERSION_NUM >= 100000
|
||||
|
||||
#include "access/htup_details.h"
|
||||
#include "access/sysattr.h"
|
||||
#include "access/stratnum.h"
|
||||
#endif
|
||||
#include "catalog/heap.h"
|
||||
#include "catalog/namespace.h"
|
||||
#if PG_VERSION_NUM >= 100000
|
||||
#include "catalog/partition.h"
|
||||
#include "catalog/pg_am.h"
|
||||
#endif
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "commands/defrem.h"
|
||||
#if PG_VERSION_NUM < 90500
|
||||
#include "lib/stringinfo.h"
|
||||
#endif
|
||||
#include "nodes/makefuncs.h"
|
||||
#if PG_VERSION_NUM >= 100000
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/defrem.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "nodes/nodeFuncs.h"
|
||||
#include "utils/ruleutils.h"
|
||||
#endif
|
||||
#include "optimizer/clauses.h"
|
||||
#if PG_VERSION_NUM >= 100000
|
||||
#include "catalog/partition.h"
|
||||
#endif
|
||||
#if PG_VERSION_NUM >= 110000
|
||||
#include "catalog/partition.h"
|
||||
#include "optimizer/cost.h"
|
||||
#include "optimizer/paths.h"
|
||||
#include "partitioning/partbounds.h"
|
||||
#include "utils/partcache.h"
|
||||
#include "partitioning/partdefs.h"
|
||||
#endif
|
||||
#include "optimizer/planner.h"
|
||||
#include "optimizer/var.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
|
|
@ -57,15 +36,21 @@
|
|||
#include "parser/parser.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#if PG_VERSION_NUM >= 110000
|
||||
#include "utils/rel.h"
|
||||
#endif
|
||||
#include "utils/ruleutils.h"
|
||||
#include "utils/syscache.h"
|
||||
#if PG_VERSION_NUM >= 110000
|
||||
#include "partitioning/partbounds.h"
|
||||
#include "partitioning/partdefs.h"
|
||||
#include "utils/partcache.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "include/hypopg_import.h"
|
||||
|
||||
#include "include/hypopg_import_table.h"
|
||||
|
||||
/* pg10 only imports */
|
||||
#if PG_VERSION_NUM >= 100000 && PG_VERSION_NUM < 110000
|
||||
#if PG_VERSION_NUM < 110000
|
||||
static int32 partition_rbound_datum_cmp(PartitionKey key,
|
||||
Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
|
||||
Datum *tuple_datums);
|
||||
|
|
@ -321,314 +306,6 @@ partition_rbound_datum_cmp(PartitionKey key,
|
|||
}
|
||||
#endif /* pg10 only imports */
|
||||
|
||||
/* Copied from src/backend/optimizer/util/plancat.c, not exported.
|
||||
*
|
||||
* Build a targetlist representing the columns of the specified index.
|
||||
* Each column is represented by a Var for the corresponding base-relation
|
||||
* column, or an expression in base-relation Vars, as appropriate.
|
||||
*
|
||||
* There are never any dropped columns in indexes, so unlike
|
||||
* build_physical_tlist, we need no failure case.
|
||||
*/
|
||||
List *
|
||||
build_index_tlist(PlannerInfo *root, IndexOptInfo *index,
|
||||
Relation heapRelation)
|
||||
{
|
||||
List *tlist = NIL;
|
||||
Index varno = index->rel->relid;
|
||||
ListCell *indexpr_item;
|
||||
int i;
|
||||
|
||||
indexpr_item = list_head(index->indexprs);
|
||||
for (i = 0; i < index->ncolumns; i++)
|
||||
{
|
||||
int indexkey = index->indexkeys[i];
|
||||
Expr *indexvar;
|
||||
|
||||
if (indexkey != 0)
|
||||
{
|
||||
/* simple column */
|
||||
const FormData_pg_attribute *att_tup;
|
||||
|
||||
if (indexkey < 0)
|
||||
att_tup = SystemAttributeDefinition(indexkey,
|
||||
heapRelation->rd_rel->relhasoids);
|
||||
else
|
||||
#if PG_VERSION_NUM >= 110000
|
||||
att_tup = TupleDescAttr(heapRelation->rd_att, indexkey - 1);
|
||||
#else
|
||||
att_tup = heapRelation->rd_att->attrs[indexkey - 1];
|
||||
#endif
|
||||
|
||||
indexvar = (Expr *) makeVar(varno,
|
||||
indexkey,
|
||||
att_tup->atttypid,
|
||||
att_tup->atttypmod,
|
||||
att_tup->attcollation,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* expression column */
|
||||
if (indexpr_item == NULL)
|
||||
elog(ERROR, "wrong number of index expressions");
|
||||
indexvar = (Expr *) lfirst(indexpr_item);
|
||||
indexpr_item = lnext(indexpr_item);
|
||||
}
|
||||
|
||||
tlist = lappend(tlist,
|
||||
makeTargetEntry(indexvar,
|
||||
i + 1,
|
||||
NULL,
|
||||
false));
|
||||
}
|
||||
if (indexpr_item != NULL)
|
||||
elog(ERROR, "wrong number of index expressions");
|
||||
|
||||
return tlist;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from src/backend/commands/indexcmds.c, not exported.
|
||||
* Resolve possibly-defaulted operator class specification
|
||||
*/
|
||||
Oid
|
||||
GetIndexOpClass(List *opclass, Oid attrType,
|
||||
char *accessMethodName, Oid accessMethodId)
|
||||
{
|
||||
char *schemaname;
|
||||
char *opcname;
|
||||
HeapTuple tuple;
|
||||
Oid opClassId,
|
||||
opInputType;
|
||||
|
||||
/*
|
||||
* Release 7.0 removed network_ops, timespan_ops, and datetime_ops, so we
|
||||
* ignore those opclass names so the default *_ops is used. This can be
|
||||
* removed in some later release. bjm 2000/02/07
|
||||
*
|
||||
* Release 7.1 removes lztext_ops, so suppress that too for a while. tgl
|
||||
* 2000/07/30
|
||||
*
|
||||
* Release 7.2 renames timestamp_ops to timestamptz_ops, so suppress that
|
||||
* too for awhile. I'm starting to think we need a better approach. tgl
|
||||
* 2000/10/01
|
||||
*
|
||||
* Release 8.0 removes bigbox_ops (which was dead code for a long while
|
||||
* anyway). tgl 2003/11/11
|
||||
*/
|
||||
if (list_length(opclass) == 1)
|
||||
{
|
||||
char *claname = strVal(linitial(opclass));
|
||||
|
||||
if (strcmp(claname, "network_ops") == 0 ||
|
||||
strcmp(claname, "timespan_ops") == 0 ||
|
||||
strcmp(claname, "datetime_ops") == 0 ||
|
||||
strcmp(claname, "lztext_ops") == 0 ||
|
||||
strcmp(claname, "timestamp_ops") == 0 ||
|
||||
strcmp(claname, "bigbox_ops") == 0)
|
||||
opclass = NIL;
|
||||
}
|
||||
|
||||
if (opclass == NIL)
|
||||
{
|
||||
/* no operator class specified, so find the default */
|
||||
opClassId = GetDefaultOpClass(attrType, accessMethodId);
|
||||
if (!OidIsValid(opClassId))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("data type %s has no default operator class for access method \"%s\"",
|
||||
format_type_be(attrType), accessMethodName),
|
||||
errhint("You must specify an operator class for the index or define a default operator class for the data type.")));
|
||||
return opClassId;
|
||||
}
|
||||
|
||||
/*
|
||||
* Specific opclass name given, so look up the opclass.
|
||||
*/
|
||||
|
||||
/* deconstruct the name list */
|
||||
DeconstructQualifiedName(opclass, &schemaname, &opcname);
|
||||
|
||||
if (schemaname)
|
||||
{
|
||||
/* Look in specific schema only */
|
||||
Oid namespaceId;
|
||||
|
||||
#if PG_VERSION_NUM >= 90300
|
||||
namespaceId = LookupExplicitNamespace(schemaname, false);
|
||||
#else
|
||||
namespaceId = LookupExplicitNamespace(schemaname);
|
||||
#endif
|
||||
tuple = SearchSysCache3(CLAAMNAMENSP,
|
||||
ObjectIdGetDatum(accessMethodId),
|
||||
PointerGetDatum(opcname),
|
||||
ObjectIdGetDatum(namespaceId));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unqualified opclass name, so search the search path */
|
||||
opClassId = OpclassnameGetOpcid(accessMethodId, opcname);
|
||||
if (!OidIsValid(opClassId))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("operator class \"%s\" does not exist for access method \"%s\"",
|
||||
opcname, accessMethodName)));
|
||||
tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opClassId));
|
||||
}
|
||||
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("operator class \"%s\" does not exist for access method \"%s\"",
|
||||
NameListToString(opclass), accessMethodName)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that the index operator class accepts this datatype. Note we
|
||||
* will accept binary compatibility.
|
||||
*/
|
||||
opClassId = HeapTupleGetOid(tuple);
|
||||
opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype;
|
||||
|
||||
if (!IsBinaryCoercible(attrType, opInputType))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("operator class \"%s\" does not accept data type %s",
|
||||
NameListToString(opclass), format_type_be(attrType))));
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
return opClassId;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from src/backend/commands/indexcmds.c, not exported.
|
||||
* CheckPredicate
|
||||
* Checks that the given partial-index predicate is valid.
|
||||
*
|
||||
* This used to also constrain the form of the predicate to forms that
|
||||
* indxpath.c could do something with. However, that seems overly
|
||||
* restrictive. One useful application of partial indexes is to apply
|
||||
* a UNIQUE constraint across a subset of a table, and in that scenario
|
||||
* any evaluatable predicate will work. So accept any predicate here
|
||||
* (except ones requiring a plan), and let indxpath.c fend for itself.
|
||||
*/
|
||||
void
|
||||
CheckPredicate(Expr *predicate)
|
||||
{
|
||||
/*
|
||||
* transformExpr() should have already rejected subqueries, aggregates,
|
||||
* and window functions, based on the EXPR_KIND_ for a predicate.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A predicate using mutable functions is probably wrong, for the same
|
||||
* reasons that we don't allow an index expression to use one.
|
||||
*/
|
||||
if (CheckMutability(predicate))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||
errmsg("functions in index predicate must be marked IMMUTABLE")));
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from src/backend/commands/indexcmds.c, not exported.
|
||||
* CheckMutability
|
||||
* Test whether given expression is mutable
|
||||
*/
|
||||
bool
|
||||
CheckMutability(Expr *expr)
|
||||
{
|
||||
/*
|
||||
* First run the expression through the planner. This has a couple of
|
||||
* important consequences. First, function default arguments will get
|
||||
* inserted, which may affect volatility (consider "default now()").
|
||||
* Second, inline-able functions will get inlined, which may allow us to
|
||||
* conclude that the function is really less volatile than it's marked. As
|
||||
* an example, polymorphic functions must be marked with the most volatile
|
||||
* behavior that they have for any input type, but once we inline the
|
||||
* function we may be able to conclude that it's not so volatile for the
|
||||
* particular input type we're dealing with.
|
||||
*
|
||||
* We assume here that expression_planner() won't scribble on its input.
|
||||
*/
|
||||
expr = expression_planner(expr);
|
||||
|
||||
/* Now we can search for non-immutable functions */
|
||||
return contain_mutable_functions((Node *) expr);
|
||||
}
|
||||
|
||||
#if PG_VERSION_NUM < 90500
|
||||
/*
|
||||
* Copied from src/backend/commands/amcmds.c
|
||||
*
|
||||
* get_am_name - given an access method OID name and type, look up its name.
|
||||
*/
|
||||
char *
|
||||
get_am_name(Oid amOid)
|
||||
{
|
||||
HeapTuple tup;
|
||||
char *result = NULL;
|
||||
|
||||
tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
|
||||
if (HeapTupleIsValid(tup))
|
||||
{
|
||||
Form_pg_am amform = (Form_pg_am) GETSTRUCT(tup);
|
||||
|
||||
result = pstrdup(NameStr(amform->amname));
|
||||
ReleaseSysCache(tup);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Copied from src/backend/utils/adt/ruleutils.c, not exported.
|
||||
*
|
||||
* get_opclass_name - fetch name of an index operator class
|
||||
*
|
||||
* The opclass name is appended (after a space) to buf.
|
||||
*
|
||||
* Output is suppressed if the opclass is the default for the given
|
||||
* actual_datatype. (If you don't want this behavior, just pass
|
||||
* InvalidOid for actual_datatype.)
|
||||
*/
|
||||
void
|
||||
get_opclass_name(Oid opclass, Oid actual_datatype,
|
||||
StringInfo buf)
|
||||
{
|
||||
HeapTuple ht_opc;
|
||||
Form_pg_opclass opcrec;
|
||||
char *opcname;
|
||||
char *nspname;
|
||||
|
||||
ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
|
||||
if (!HeapTupleIsValid(ht_opc))
|
||||
elog(ERROR, "cache lookup failed for opclass %u", opclass);
|
||||
opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
|
||||
|
||||
if (!OidIsValid(actual_datatype) ||
|
||||
GetDefaultOpClass(actual_datatype, opcrec->opcmethod) != opclass)
|
||||
{
|
||||
/* Okay, we need the opclass name. Do we need to qualify it? */
|
||||
opcname = NameStr(opcrec->opcname);
|
||||
if (OpclassIsVisible(opclass))
|
||||
appendStringInfo(buf, " %s", quote_identifier(opcname));
|
||||
else
|
||||
{
|
||||
nspname = get_namespace_name(opcrec->opcnamespace);
|
||||
appendStringInfo(buf, " %s.%s",
|
||||
quote_identifier(nspname),
|
||||
quote_identifier(opcname));
|
||||
}
|
||||
}
|
||||
ReleaseSysCache(ht_opc);
|
||||
}
|
||||
|
||||
#if PG_VERSION_NUM >= 100000
|
||||
/*
|
||||
* Copied from src/backend/commands/tablecmds.c, not exported.
|
||||
*
|
||||
|
|
@ -1712,123 +1389,4 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
|
|||
*translated_vars = vars;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Copied from src/backend/commands/analyze.c/, not exported
|
||||
*
|
||||
* examine_attribute -- pre-analysis of a single column
|
||||
*
|
||||
* Determine whether the column is analyzable; if so, create and initialize
|
||||
* a VacAttrStats struct for it. If not, return NULL.
|
||||
*
|
||||
* If index_expr isn't NULL, then we're trying to analyze an expression index,
|
||||
* and index_expr is the expression tree representing the column's data.
|
||||
*/
|
||||
VacAttrStats *
|
||||
examine_attribute(Relation onerel, int attnum, Node *index_expr)
|
||||
{
|
||||
Form_pg_attribute attr = TupleDescAttr(onerel->rd_att, attnum - 1);
|
||||
HeapTuple typtuple;
|
||||
VacAttrStats *stats;
|
||||
int i;
|
||||
bool ok;
|
||||
|
||||
/* Never analyze dropped columns */
|
||||
if (attr->attisdropped)
|
||||
return NULL;
|
||||
|
||||
/* Don't analyze column if user has specified not to */
|
||||
if (attr->attstattarget == 0)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Create the VacAttrStats struct. Note that we only have a copy of the
|
||||
* fixed fields of the pg_attribute tuple.
|
||||
*/
|
||||
stats = (VacAttrStats *) palloc0(sizeof(VacAttrStats));
|
||||
stats->attr = (Form_pg_attribute) palloc(ATTRIBUTE_FIXED_PART_SIZE);
|
||||
memcpy(stats->attr, attr, ATTRIBUTE_FIXED_PART_SIZE);
|
||||
|
||||
/*
|
||||
* When analyzing an expression index, believe the expression tree's type
|
||||
* not the column datatype --- the latter might be the opckeytype storage
|
||||
* type of the opclass, which is not interesting for our purposes. (Note:
|
||||
* if we did anything with non-expression index columns, we'd need to
|
||||
* figure out where to get the correct type info from, but for now that's
|
||||
* not a problem.) It's not clear whether anyone will care about the
|
||||
* typmod, but we store that too just in case.
|
||||
*/
|
||||
if (index_expr)
|
||||
{
|
||||
stats->attrtypid = exprType(index_expr);
|
||||
stats->attrtypmod = exprTypmod(index_expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
stats->attrtypid = attr->atttypid;
|
||||
stats->attrtypmod = attr->atttypmod;
|
||||
}
|
||||
|
||||
typtuple = SearchSysCacheCopy1(TYPEOID,
|
||||
ObjectIdGetDatum(stats->attrtypid));
|
||||
if (!HeapTupleIsValid(typtuple))
|
||||
elog(ERROR, "cache lookup failed for type %u", stats->attrtypid);
|
||||
stats->attrtype = (Form_pg_type) GETSTRUCT(typtuple);
|
||||
//FIXME
|
||||
stats->anl_context = CurrentMemoryContext;
|
||||
stats->tupattnum = attnum;
|
||||
|
||||
/*
|
||||
* The fields describing the stats->stavalues[n] element types default to
|
||||
* the type of the data being analyzed, but the type-specific typanalyze
|
||||
* function can change them if it wants to store something else.
|
||||
*/
|
||||
for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
|
||||
{
|
||||
stats->statypid[i] = stats->attrtypid;
|
||||
stats->statyplen[i] = stats->attrtype->typlen;
|
||||
stats->statypbyval[i] = stats->attrtype->typbyval;
|
||||
stats->statypalign[i] = stats->attrtype->typalign;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the type-specific typanalyze function. If none is specified, use
|
||||
* std_typanalyze().
|
||||
*/
|
||||
if (OidIsValid(stats->attrtype->typanalyze))
|
||||
ok = DatumGetBool(OidFunctionCall1(stats->attrtype->typanalyze,
|
||||
PointerGetDatum(stats)));
|
||||
else
|
||||
ok = std_typanalyze(stats);
|
||||
|
||||
if (!ok || stats->compute_stats == NULL || stats->minrows <= 0)
|
||||
{
|
||||
heap_freetuple(typtuple);
|
||||
pfree(stats->attr);
|
||||
pfree(stats);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from src/backend/commands/analyze.c, not exported
|
||||
*
|
||||
* Standard fetch function for use by compute_stats subroutines.
|
||||
*
|
||||
* This exists to provide some insulation between compute_stats routines
|
||||
* and the actual storage of the sample data.
|
||||
*/
|
||||
Datum
|
||||
std_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull)
|
||||
{
|
||||
int attnum = stats->tupattnum;
|
||||
HeapTuple tuple = stats->rows[rownum];
|
||||
TupleDesc tupDesc = stats->tupDesc;
|
||||
|
||||
return heap_getattr(tuple, attnum, tupDesc, isNull);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* pg10+ */
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#define _HYPOPG_IMPORT_H_
|
||||
|
||||
#include "commands/vacuum.h"
|
||||
#include "lib/stringinfo.h"
|
||||
#include "nodes/pg_list.h"
|
||||
#include "optimizer/planner.h"
|
||||
#include "optimizer/pathnode.h"
|
||||
|
|
@ -20,143 +21,12 @@
|
|||
#include "partitioning/partbounds.h"
|
||||
#endif
|
||||
#include "utils/rel.h"
|
||||
|
||||
|
||||
/* adapted from nbtinsert.h */
|
||||
#define HYPO_BTMaxItemSize \
|
||||
MAXALIGN_DOWN((BLCKSZ - \
|
||||
MAXALIGN(SizeOfPageHeaderData + 3*sizeof(ItemIdData)) - \
|
||||
MAXALIGN(sizeof(BTPageOpaqueData))) / 3)
|
||||
|
||||
extern List *build_index_tlist(PlannerInfo *root, IndexOptInfo *index,
|
||||
Relation heapRelation);
|
||||
extern Oid GetIndexOpClass(List *opclass, Oid attrType,
|
||||
char *accessMethodName, Oid accessMethodId);
|
||||
|
||||
extern void CheckPredicate(Expr *predicate);
|
||||
extern bool CheckMutability(Expr *expr);
|
||||
#if PG_VERSION_NUM < 90500
|
||||
extern char *get_am_name(Oid amOid);
|
||||
#include "include/hypopg_import_index.h"
|
||||
#if PG_VERSION_NUM >= 100000
|
||||
#include "include/hypopg_import_analyze.h"
|
||||
#include "include/hypopg_import_table.h"
|
||||
#endif
|
||||
|
||||
extern void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf);
|
||||
|
||||
#if PG_VERSION_NUM >= 100000
|
||||
|
||||
/* pg10 only imports */
|
||||
#if PG_VERSION_NUM < 110000
|
||||
/*
|
||||
* Imported from src/backend/catalog/partition.c, not exported
|
||||
*/
|
||||
typedef struct PartitionBoundInfoData
|
||||
{
|
||||
char strategy; /* hash, list or range? */
|
||||
int ndatums; /* Length of the datums following array */
|
||||
Datum **datums;
|
||||
PartitionRangeDatumKind **kind; /* The kind of each range bound datum;
|
||||
* NULL for hash and list partitioned
|
||||
* tables */
|
||||
int *indexes; /* Partition indexes */
|
||||
int null_index; /* Index of the null-accepting partition; -1
|
||||
* if there isn't one */
|
||||
} PartitionBoundInfoData;
|
||||
|
||||
/* One bound of a hash partition */
|
||||
typedef struct PartitionHashBound
|
||||
{
|
||||
int modulus;
|
||||
int remainder;
|
||||
int index;
|
||||
} PartitionHashBound;
|
||||
|
||||
/* One value coming from some (index'th) list partition */
|
||||
typedef struct PartitionListValue
|
||||
{
|
||||
int index;
|
||||
Datum value;
|
||||
} PartitionListValue;
|
||||
|
||||
/* One bound of a range partition */
|
||||
typedef struct PartitionRangeBound
|
||||
{
|
||||
int index;
|
||||
Datum *datums; /* range bound datums */
|
||||
PartitionRangeDatumKind *kind; /* the kind of each datum */
|
||||
bool lower; /* this is the lower (vs upper) bound */
|
||||
} PartitionRangeBound;
|
||||
|
||||
/*
|
||||
* Entry of a hash table used in find_all_inheritors. See below.
|
||||
*/
|
||||
typedef struct SeenRelsEntry
|
||||
{
|
||||
Oid rel_id; /* relation oid */
|
||||
ListCell *numparents_cell; /* corresponding list cell */
|
||||
} SeenRelsEntry;
|
||||
|
||||
PartitionRangeBound *make_one_range_bound(PartitionKey key, int index,
|
||||
List *datums, bool lower);
|
||||
int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo,
|
||||
void *probe, bool probe_is_bound, bool *is_equal);
|
||||
int32 partition_bound_cmp(PartitionKey key,
|
||||
PartitionBoundInfo boundinfo,
|
||||
int offset, void *probe, bool probe_is_bound);
|
||||
|
||||
int32 partition_rbound_cmp(PartitionKey key,
|
||||
Datum *datums1, PartitionRangeDatumKind *kind1,
|
||||
bool lower1, PartitionRangeBound *b2);
|
||||
#endif /* pg10 only imports */
|
||||
|
||||
/* Context info needed for invoking a recursive querytree display routine */
|
||||
typedef struct
|
||||
{
|
||||
StringInfo buf; /* output buffer to append to */
|
||||
// List *namespaces; /* List of deparse_namespace nodes */
|
||||
// List *windowClause; /* Current query level's WINDOW clause */
|
||||
// List *windowTList; /* targetlist for resolving WINDOW clause */
|
||||
// int prettyFlags; /* enabling of pretty-print functions */
|
||||
// int wrapColumn; /* max line length, or -1 for no limit */
|
||||
// int indentLevel; /* current indent level for prettyprint */
|
||||
// bool varprefix; /* true to print prefixes on Vars */
|
||||
// ParseExprKind special_exprkind; /* set only for exprkinds needing special
|
||||
// * handling */
|
||||
} deparse_context;
|
||||
|
||||
|
||||
PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec,
|
||||
char *strategy);
|
||||
void ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber
|
||||
*partattrs, List **partexprs, Oid *partopclass, Oid *partcollation,
|
||||
char strategy);
|
||||
char *get_relation_name(Oid relid);
|
||||
bool looks_like_function(Node *node);
|
||||
int32 qsort_partition_hbound_cmp(const void *a, const void *b);
|
||||
int32 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg);
|
||||
int32 qsort_partition_rbound_cmp(const void *a, const void *b, void *arg);
|
||||
void get_const_expr(Const *constval, deparse_context *context, int
|
||||
showtype);
|
||||
void get_const_collation(Const *constval, deparse_context *context);
|
||||
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);
|
||||
VacAttrStats *examine_attribute(Relation onerel, int attnum, Node *index_expr);
|
||||
Datum std_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
|
||||
/* Copied from src/backend/catalog/partition.c, not exported */
|
||||
#define partition_bound_accepts_nulls(bi) ((bi)->null_index != -1)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif /* _HYPOPG_IMPORT_H_ */
|
||||
|
|
|
|||
24
include/hypopg_import_analyze.h
Normal file
24
include/hypopg_import_analyze.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* hypopg_import_analyze.h: Import of some PostgreSQL private fuctions, used
|
||||
* for hypothetical analyze.
|
||||
*
|
||||
* This program is open source, licensed under the PostgreSQL license.
|
||||
* For license terms, see the LICENSE file.
|
||||
*
|
||||
* Copyright (c) 2008-2018, PostgreSQL Global Development Group
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef _HYPOPG_IMPORT_ANALYZE_H_
|
||||
#define _HYPOPG_IMPORT_ANALYZE_H_
|
||||
|
||||
#if PG_VERSION_NUM < 100000
|
||||
#error "This could should only be included on pg10+ code"
|
||||
#endif
|
||||
|
||||
|
||||
VacAttrStats *examine_attribute(Relation onerel, int attnum, Node *index_expr);
|
||||
Datum std_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
|
||||
|
||||
#endif /* _HYPOPG_IMPORT_ANALYZE_H_ */
|
||||
33
include/hypopg_import_index.h
Normal file
33
include/hypopg_import_index.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* hypopg_import_index.h: Import of some PostgreSQL private fuctions, used for
|
||||
* hypothetical index.
|
||||
*
|
||||
* This program is open source, licensed under the PostgreSQL license.
|
||||
* For license terms, see the LICENSE file.
|
||||
*
|
||||
* Copyright (c) 2008-2018, PostgreSQL Global Development Group
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef _HYPOPG_IMPORT_INDEX_H_
|
||||
#define _HYPOPG_IMPORT_INDEX_H_
|
||||
|
||||
/* adapted from nbtinsert.h */
|
||||
#define HYPO_BTMaxItemSize \
|
||||
MAXALIGN_DOWN((BLCKSZ - \
|
||||
MAXALIGN(SizeOfPageHeaderData + 3*sizeof(ItemIdData)) - \
|
||||
MAXALIGN(sizeof(BTPageOpaqueData))) / 3)
|
||||
|
||||
extern List *build_index_tlist(PlannerInfo *root, IndexOptInfo *index,
|
||||
Relation heapRelation);
|
||||
extern Oid GetIndexOpClass(List *opclass, Oid attrType,
|
||||
char *accessMethodName, Oid accessMethodId);
|
||||
|
||||
extern void CheckPredicate(Expr *predicate);
|
||||
extern bool CheckMutability(Expr *expr);
|
||||
#if PG_VERSION_NUM < 90500
|
||||
extern char *get_am_name(Oid amOid);
|
||||
#endif
|
||||
|
||||
#endif /* _HYPOPG_IMPORT_INDEX_H_ */
|
||||
137
include/hypopg_import_table.h
Normal file
137
include/hypopg_import_table.h
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* hypopg_import_table.h: Import of some PostgreSQL private fuctions, used
|
||||
* for hypothetical partitioning.
|
||||
*
|
||||
* This program is open source, licensed under the PostgreSQL license.
|
||||
* For license terms, see the LICENSE file.
|
||||
*
|
||||
* Copyright (c) 2008-2018, PostgreSQL Global Development Group
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef _HYPOPG_IMPORT_TABLE_H_
|
||||
#define _HYPOPG_IMPORT_TABLE_H_
|
||||
|
||||
#include "catalog/partition.h"
|
||||
|
||||
#if PG_VERSION_NUM < 100000
|
||||
#error "This could should only be included on pg10+ code"
|
||||
#endif
|
||||
|
||||
|
||||
/* pg10 only imports */
|
||||
#if PG_VERSION_NUM < 110000
|
||||
/*
|
||||
* Imported from src/backend/catalog/partition.c, not exported
|
||||
*/
|
||||
typedef struct PartitionBoundInfoData
|
||||
{
|
||||
char strategy; /* hash, list or range? */
|
||||
int ndatums; /* Length of the datums following array */
|
||||
Datum **datums;
|
||||
PartitionRangeDatumKind **kind; /* The kind of each range bound datum;
|
||||
* NULL for hash and list partitioned
|
||||
* tables */
|
||||
int *indexes; /* Partition indexes */
|
||||
int null_index; /* Index of the null-accepting partition; -1
|
||||
* if there isn't one */
|
||||
} PartitionBoundInfoData;
|
||||
|
||||
/* One bound of a hash partition */
|
||||
typedef struct PartitionHashBound
|
||||
{
|
||||
int modulus;
|
||||
int remainder;
|
||||
int index;
|
||||
} PartitionHashBound;
|
||||
|
||||
/* One value coming from some (index'th) list partition */
|
||||
typedef struct PartitionListValue
|
||||
{
|
||||
int index;
|
||||
Datum value;
|
||||
} PartitionListValue;
|
||||
|
||||
/* One bound of a range partition */
|
||||
typedef struct PartitionRangeBound
|
||||
{
|
||||
int index;
|
||||
Datum *datums; /* range bound datums */
|
||||
PartitionRangeDatumKind *kind; /* the kind of each datum */
|
||||
bool lower; /* this is the lower (vs upper) bound */
|
||||
} PartitionRangeBound;
|
||||
|
||||
/*
|
||||
* Entry of a hash table used in find_all_inheritors. See below.
|
||||
*/
|
||||
typedef struct SeenRelsEntry
|
||||
{
|
||||
Oid rel_id; /* relation oid */
|
||||
ListCell *numparents_cell; /* corresponding list cell */
|
||||
} SeenRelsEntry;
|
||||
|
||||
PartitionRangeBound *make_one_range_bound(PartitionKey key, int index,
|
||||
List *datums, bool lower);
|
||||
int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo,
|
||||
void *probe, bool probe_is_bound, bool *is_equal);
|
||||
int32 partition_bound_cmp(PartitionKey key,
|
||||
PartitionBoundInfo boundinfo,
|
||||
int offset, void *probe, bool probe_is_bound);
|
||||
|
||||
int32 partition_rbound_cmp(PartitionKey key,
|
||||
Datum *datums1, PartitionRangeDatumKind *kind1,
|
||||
bool lower1, PartitionRangeBound *b2);
|
||||
#endif /* pg10 only imports */
|
||||
|
||||
/* Context info needed for invoking a recursive querytree display routine */
|
||||
typedef struct
|
||||
{
|
||||
StringInfo buf; /* output buffer to append to */
|
||||
// List *namespaces; /* List of deparse_namespace nodes */
|
||||
// List *windowClause; /* Current query level's WINDOW clause */
|
||||
// List *windowTList; /* targetlist for resolving WINDOW clause */
|
||||
// int prettyFlags; /* enabling of pretty-print functions */
|
||||
// int wrapColumn; /* max line length, or -1 for no limit */
|
||||
// int indentLevel; /* current indent level for prettyprint */
|
||||
// bool varprefix; /* true to print prefixes on Vars */
|
||||
// ParseExprKind special_exprkind; /* set only for exprkinds needing special
|
||||
// * handling */
|
||||
} deparse_context;
|
||||
|
||||
|
||||
PartitionSpec *transformPartitionSpec(Relation rel, PartitionSpec *partspec,
|
||||
char *strategy);
|
||||
void ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber
|
||||
*partattrs, List **partexprs, Oid *partopclass, Oid *partcollation,
|
||||
char strategy);
|
||||
char *get_relation_name(Oid relid);
|
||||
bool looks_like_function(Node *node);
|
||||
int32 qsort_partition_hbound_cmp(const void *a, const void *b);
|
||||
int32 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg);
|
||||
int32 qsort_partition_rbound_cmp(const void *a, const void *b, void *arg);
|
||||
void get_const_expr(Const *constval, deparse_context *context, int
|
||||
showtype);
|
||||
void get_const_collation(Const *constval, deparse_context *context);
|
||||
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 /* _HYPOPG_IMPORT_TABLE_H_ */
|
||||
Loading…
Reference in a new issue