diff --git a/pg_hypo--0.1.sql b/pg_hypo--0.1.sql index d9f2ff0..4a8440a 100644 --- a/pg_hypo--0.1.sql +++ b/pg_hypo--0.1.sql @@ -11,9 +11,51 @@ SET client_encoding = 'UTF8'; CREATE FUNCTION pg_hypo_reset() RETURNS void LANGUAGE c COST 1000 - AS '$libdir/pg_hypo', 'pg_hypo_reset'; +AS '$libdir/pg_hypo', 'pg_hypo_reset'; -CREATE FUNCTION pg_hypo_add_index_internal(IN indexid oid, relid oid, IN indexname text) +CREATE FUNCTION +pg_hypo_add_index_internal(IN indexid oid, + IN relid oid, + IN indexname text, + IN relam Oid, + IN ncolumns int, + IN indexkeys int, + IN indexcollations Oid, + IN opfamily Oid, + IN opcintype Oid) RETURNS bool LANGUAGE c COST 1000 - AS '$libdir/pg_hypo', 'pg_hypo_add_index_internal'; +AS '$libdir/pg_hypo', 'pg_hypo_add_index_internal'; + +CREATE FUNCTION +pg_hypo_add_index(IN _nspname name, IN _relname name, IN _attname name, IN _indtype text) + RETURNS bool +AS +$_$ + SELECT pg_hypo_add_index_internal( + id, + relid, + indexname, + amoid, + ncolumns, + attnum, + indexcollations, + opfoid, + atttypid) + FROM ( + SELECT DISTINCT 1 AS id, c.oid AS relid, 'index_name' AS indexname, am.oid AS amoid, 1 AS ncolumns, a.attnum, 0 AS indexcollations, opf.oid AS opfoid, a.atttypid + FROM pg_class c + JOIN pg_namespace n on n.oid = c.relnamespace + JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum > 0 + JOIN pg_type t ON t.oid = a.atttypid + JOIN pg_amop amop ON amop.amoplefttype = t.oid + JOIN pg_opfamily opf ON opf.oid = amop.amopfamily + JOIN pg_am am ON am.oid = amop.amopmethod + WHERE + n.nspname = _nspname + AND c.relname = _relname + AND a.attname = _attname + AND am.amname = _indtype + ) src; +$_$ +LANGUAGE sql; diff --git a/pg_hypo.c b/pg_hypo.c index 0d574dc..e8e2016 100644 --- a/pg_hypo.c +++ b/pg_hypo.c @@ -31,11 +31,11 @@ #include "utils/guc.h" #include "utils/rel.h" -static const uint32 PGHYPO_FILE_HEADER = 0x6879706f; - PG_MODULE_MAGIC; -#define HYPOTHETICAL_INDEX_OID 123; +static const uint32 PGHYPO_FILE_HEADER = 0x6879706f; + +#define HYPO_MAX_COL 1 #if PG_VERSION_NUM >= 90300 #define HYPO_DUMP_FILE "pg_stat/pg_hypo.stat" #else @@ -54,6 +54,12 @@ typedef struct hypoEntry Oid indexid; /* hypothetical index Oid */ Oid relid; /* related relation Oid */ char *indexname; /* hypothetical index name */ + Oid relam; + int ncolumns; /* number of columns, only 1 for now */ + int indexkeys; /* attnum */ + Oid indexcollations; + Oid opfamily; + Oid opcintype; slock_t mutex; /* protects fields */ } hypoEntry; @@ -83,7 +89,15 @@ PG_FUNCTION_INFO_V1(pg_hypo_add_index_internal); static Size hypo_memsize(void); static void entry_reset(void); -static bool entry_store(Oid indexid, Oid relid, char *indexname); +static bool entry_store(Oid indexid, + Oid relid, + char *indexname, + Oid relam, + int ncolumns, + int indexkeys, + int indexcollations, + Oid opfamily, + Oid opcintype); static void hypo_shmem_startup(void); static shmem_startup_hook_type prev_shmem_startup_hook = NULL; @@ -203,7 +217,6 @@ hypo_shmem_startup(void) if (!found) { entry_reset(); - entry_store(1, 1, "hypo_toto"); } @@ -316,12 +329,24 @@ entry_reset(void) } static bool -entry_store(Oid indexid, Oid relid, char *indexname) +entry_store(Oid indexid, + Oid relid, + char *indexname, + Oid relam, + int ncolumns, + int indexkeys, + int indexcollations, + Oid opfamily, + Oid opcintype) { int i = 0; hypoEntry *entry; bool found = false; + /* Make sure user didn't try to add too many columns */ + if (ncolumns > HYPO_MAX_COL) + return false; + entry = hypoEntries; LWLockAcquire(hypo->lock, LW_SHARED); @@ -333,6 +358,12 @@ entry_store(Oid indexid, Oid relid, char *indexname) entry->indexid = indexid; entry->relid = relid; entry->indexname = indexname; + entry->relam = relam; + entry->ncolumns = ncolumns; + entry->indexkeys = indexkeys; + entry->indexcollations = indexcollations; + entry->opfamily = opfamily; + entry->opcintype = opcintype; SpinLockRelease(&entry->mutex); found = true; break; @@ -419,19 +450,19 @@ addHypotheticalIndex(PlannerInfo *root, Oid relationObjectId, bool inhparent, Re /* create a node */ index = makeNode(IndexOptInfo); - index->relam = BTREE_AM_OID; // more to be added + index->relam = entry.relam; if (index->relam != BTREE_AM_OID) { - elog(WARNING, "pg_hypo: Only btree indexes are supported for now"); + elog(WARNING, "pg_hypo: Only btree indexes are supported for now!"); return; } // General stuff - index->indexoid = HYPOTHETICAL_INDEX_OID; + index->indexoid = entry.indexid; index->reltablespace = rel->reltablespace; // same as relation index->rel = rel; - index->ncolumns = ncolumns = 1; // only 1 col indexes for now + index->ncolumns = ncolumns = entry.ncolumns; index->indexkeys = (int *) palloc(sizeof(int) * ncolumns); index->indexcollations = (Oid *) palloc(sizeof(int) * ncolumns); @@ -446,23 +477,23 @@ addHypotheticalIndex(PlannerInfo *root, Oid relationObjectId, bool inhparent, Re case BTREE_AM_OID: // hardcode int4 cols, WIP index->indexcollations[i] = 0; //?? C_COLLATION_OID; - index->opfamily[i] = INTEGER_BTREE_FAM_OID; - index->opcintype[i] = INT4OID; // ??INT4_BTREE_OPS_OID; // btree integer opclass + index->opfamily[i] = entry.opfamily; //INTEGER_BTREE_FAM_OID; + index->opcintype[i] = entry.opcintype; //INT4OID; // ??INT4_BTREE_OPS_OID; // btree integer opclass break; } } - index->canreturn = true; - index->amcanorderbyop = false; - index->amoptionalkey = true; - index->amsearcharray = true; - index->amsearchnulls = true; - index->amhasgettuple = true; - index->amhasgetbitmap = true; - index->unique = false; - index->immediate = true; if (index->relam == BTREE_AM_OID) { + index->canreturn = true; + index->amcanorderbyop = false; + index->amoptionalkey = true; + index->amsearcharray = true; + index->amsearchnulls = true; + index->amhasgettuple = true; + index->amhasgetbitmap = true; + index->unique = false; + index->immediate = true; index->amcostestimate = (RegProcedure) 1268; // btcostestimate index->sortopfamily = index->opfamily; index->tree_height = 1; // WIP @@ -535,9 +566,17 @@ static void hypo_get_relation_info_hook(PlannerInfo *root, break; if (entry->relid == relationObjectId) { SpinLockAcquire(&entry->mutex); + current.indexid = entry->indexid; current.relid = entry->relid; current.indexname = entry->indexname; + current.relam = entry->relam; + current.ncolumns = entry->ncolumns; + current.indexkeys = entry->indexkeys; + current.indexcollations = entry->indexcollations; + current.opfamily = entry->opfamily; + current.opcintype = entry->opcintype; + SpinLockRelease(&entry->mutex); // Call the main function which will add hypothetical indexes if needed addHypotheticalIndex(root, relationObjectId, inhparent, rel, relation, current); @@ -618,7 +657,14 @@ pg_hypo_add_index_internal(PG_FUNCTION_ARGS) Oid indexid = PG_GETARG_OID(0); Oid relid = PG_GETARG_OID(1); char *indexname = TextDatumGetCString(PG_GETARG_TEXT_P(2)); - return entry_store(indexid, relid, indexname); + Oid relam = PG_GETARG_OID(3); + int ncolumns = PG_GETARG_INT32(4); + int indexkeys = PG_GETARG_INT32(5); + Oid indexcollations = PG_GETARG_OID(6); + Oid opfamily = PG_GETARG_OID(7); + Oid opcintype = PG_GETARG_OID(8); + + return entry_store(indexid, relid, indexname, relam, ncolumns, indexkeys, indexcollations, opfamily, opcintype); } // stolen from backend/optimisze/util/plancat.c, no export of this function :(