aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ruleutils.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2001-10-01 20:15:26 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2001-10-01 20:15:26 +0000
commite5bbf19659b0e30fde177539b6f8fd81f4274b47 (patch)
treec277f59050ea6a86b6236ddb017b47d9acfb69d3 /src/backend/utils/adt/ruleutils.c
parent0648d78ac4ae3d3945348392795a401ddd4b2839 (diff)
downloadpostgresql-e5bbf19659b0e30fde177539b6f8fd81f4274b47.tar.gz
postgresql-e5bbf19659b0e30fde177539b6f8fd81f4274b47.zip
Extend pg_get_indexdef() to know about index predicates. Also, tweak
it to suppress index opclass output for opclasses that are the default for their datatype; only non-default opclasses are shown explicitly. This is expected to improve portability of the CREATE INDEX command across future versions of Postgres --- we've changed index opclasses too often in the past to think we won't do so again.
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r--src/backend/utils/adt/ruleutils.c188
1 files changed, 84 insertions, 104 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index a5f9d2ace1a..6d4d926078d 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.82 2001/08/12 21:35:19 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.83 2001/10/01 20:15:26 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -41,7 +41,9 @@
#include <fcntl.h>
#include "catalog/heap.h"
+#include "catalog/index.h"
#include "catalog/pg_index.h"
+#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_shadow.h"
#include "executor/spi.h"
@@ -94,10 +96,6 @@ static void *plan_getrule = NULL;
static char *query_getrule = "SELECT * FROM pg_rewrite WHERE rulename = $1";
static void *plan_getview = NULL;
static char *query_getview = "SELECT * FROM pg_rewrite WHERE rulename = $1";
-static void *plan_getam = NULL;
-static char *query_getam = "SELECT * FROM pg_am WHERE oid = $1";
-static void *plan_getopclass = NULL;
-static char *query_getopclass = "SELECT * FROM pg_opclass WHERE oid = $1";
/* ----------
@@ -138,6 +136,8 @@ static void get_sublink_expr(Node *node, deparse_context *context);
static void get_from_clause(Query *query, deparse_context *context);
static void get_from_clause_item(Node *jtnode, Query *query,
deparse_context *context);
+static void get_opclass_name(Oid opclass, bool only_nondefault,
+ StringInfo buf);
static bool tleIsArrayAssign(TargetEntry *tle);
static char *quote_identifier(char *ident);
static char *get_relation_name(Oid relid);
@@ -341,15 +341,10 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
HeapTuple ht_idx;
HeapTuple ht_idxrel;
HeapTuple ht_indrel;
- HeapTuple spi_tup;
- TupleDesc spi_ttc;
- int spi_fno;
Form_pg_index idxrec;
Form_pg_class idxrelrec;
Form_pg_class indrelrec;
- Datum spi_args[1];
- char spi_nulls[2];
- int spirc;
+ Form_pg_am amrec;
int len;
int keyno;
StringInfoData buf;
@@ -357,33 +352,6 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
char *sep;
/*
- * Connect to SPI manager
- */
- if (SPI_connect() != SPI_OK_CONNECT)
- elog(ERROR, "get_indexdef: cannot connect to SPI manager");
-
- /*
- * On the first call prepare the plans to lookup pg_am and pg_opclass.
- */
- if (plan_getam == NULL)
- {
- Oid argtypes[1];
- void *plan;
-
- argtypes[0] = OIDOID;
- plan = SPI_prepare(query_getam, 1, argtypes);
- if (plan == NULL)
- elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getam);
- plan_getam = SPI_saveplan(plan);
-
- argtypes[0] = OIDOID;
- plan = SPI_prepare(query_getopclass, 1, argtypes);
- if (plan == NULL)
- elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getopclass);
- plan_getopclass = SPI_saveplan(plan);
- }
-
- /*
* Fetch the pg_index tuple by the Oid of the index
*/
ht_idx = SearchSysCache(INDEXRELID,
@@ -414,21 +382,14 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
indrelrec = (Form_pg_class) GETSTRUCT(ht_indrel);
/*
- * Get the am name for the index relation
+ * Fetch the pg_am tuple of the index' access method
+ *
+ * There is no syscache for this, so use index.c subroutine.
*/
- spi_args[0] = ObjectIdGetDatum(idxrelrec->relam);
- spi_nulls[0] = ' ';
- spi_nulls[1] = '\0';
- spirc = SPI_execp(plan_getam, spi_args, spi_nulls, 1);
- if (spirc != SPI_OK_SELECT)
- elog(ERROR, "failed to get pg_am tuple for index %s",
- NameStr(idxrelrec->relname));
- if (SPI_processed != 1)
- elog(ERROR, "failed to get pg_am tuple for index %s",
- NameStr(idxrelrec->relname));
- spi_tup = SPI_tuptable->vals[0];
- spi_ttc = SPI_tuptable->tupdesc;
- spi_fno = SPI_fnumber(spi_ttc, "amname");
+ amrec = AccessMethodObjectIdGetForm(idxrelrec->relam,
+ CurrentMemoryContext);
+ if (!amrec)
+ elog(ERROR, "lookup for AM %u failed", idxrelrec->relam);
/*
* Start the index definition
@@ -436,13 +397,12 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
initStringInfo(&buf);
appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
idxrec->indisunique ? "UNIQUE " : "",
- quote_identifier(pstrdup(NameStr(idxrelrec->relname))),
- quote_identifier(pstrdup(NameStr(indrelrec->relname))),
- quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
- spi_fno)));
+ quote_identifier(NameStr(idxrelrec->relname)),
+ quote_identifier(NameStr(indrelrec->relname)),
+ quote_identifier(NameStr(amrec->amname)));
/*
- * Collect the indexed attributes
+ * Collect the indexed attributes in keybuf
*/
initStringInfo(&keybuf);
sep = "";
@@ -465,29 +425,14 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
* If not a functional index, add the operator class name
*/
if (idxrec->indproc == InvalidOid)
- {
- spi_args[0] = ObjectIdGetDatum(idxrec->indclass[keyno]);
- spi_nulls[0] = ' ';
- spi_nulls[1] = '\0';
- spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
- if (spirc != SPI_OK_SELECT)
- elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[keyno]);
- if (SPI_processed != 1)
- elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[keyno]);
- spi_tup = SPI_tuptable->vals[0];
- spi_ttc = SPI_tuptable->tupdesc;
- spi_fno = SPI_fnumber(spi_ttc, "opcname");
- appendStringInfo(&keybuf, " %s",
- quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
- spi_fno)));
- }
+ get_opclass_name(idxrec->indclass[keyno], true, &keybuf);
}
- /*
- * For functional index say 'func (attrs) opclass'
- */
if (idxrec->indproc != InvalidOid)
{
+ /*
+ * For functional index say 'func (attrs) opclass'
+ */
HeapTuple proctup;
Form_pg_proc procStruct;
@@ -498,58 +443,67 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc);
procStruct = (Form_pg_proc) GETSTRUCT(proctup);
- appendStringInfo(&buf, "%s(%s) ",
- quote_identifier(pstrdup(NameStr(procStruct->proname))),
+ appendStringInfo(&buf, "%s(%s)",
+ quote_identifier(NameStr(procStruct->proname)),
keybuf.data);
+ get_opclass_name(idxrec->indclass[0], true, &buf);
- spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]);
- spi_nulls[0] = ' ';
- spi_nulls[1] = '\0';
- spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
- if (spirc != SPI_OK_SELECT)
- elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[0]);
- if (SPI_processed != 1)
- elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[0]);
- spi_tup = SPI_tuptable->vals[0];
- spi_ttc = SPI_tuptable->tupdesc;
- spi_fno = SPI_fnumber(spi_ttc, "opcname");
- appendStringInfo(&buf, "%s",
- quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
- spi_fno)));
ReleaseSysCache(proctup);
}
else
-
+ {
/*
- * For the others say 'attr opclass [, ...]'
+ * Otherwise say 'attr opclass [, ...]'
*/
appendStringInfo(&buf, "%s", keybuf.data);
+ }
+
+ appendStringInfo(&buf, ")");
/*
- * Finish
+ * If it's a partial index, decompile and append the predicate
*/
- appendStringInfo(&buf, ")");
+ if (VARSIZE(&idxrec->indpred) > VARHDRSZ)
+ {
+ Node *node;
+ List *context;
+ char *exprstr;
+ char *str;
+
+ /* Convert TEXT object to C string */
+ exprstr = DatumGetCString(DirectFunctionCall1(textout,
+ PointerGetDatum(&idxrec->indpred)));
+ /* Convert expression to node tree */
+ node = (Node *) stringToNode(exprstr);
+ /*
+ * If top level is a List, assume it is an implicit-AND structure,
+ * and convert to explicit AND. This is needed for partial index
+ * predicates.
+ */
+ if (node && IsA(node, List))
+ node = (Node *) make_ands_explicit((List *) node);
+ /* Deparse */
+ context = deparse_context_for(NameStr(indrelrec->relname),
+ idxrec->indrelid);
+ str = deparse_expression(node, context, false);
+ appendStringInfo(&buf, " WHERE %s", str);
+ }
/*
- * Create the result in upper executor memory, and free objects
+ * Create the result as a TEXT datum, and free working data
*/
len = buf.len + VARHDRSZ;
- indexdef = SPI_palloc(len);
+ indexdef = (text *) palloc(len);
VARATT_SIZEP(indexdef) = len;
memcpy(VARDATA(indexdef), buf.data, buf.len);
pfree(buf.data);
pfree(keybuf.data);
+ pfree(amrec);
ReleaseSysCache(ht_idx);
ReleaseSysCache(ht_idxrel);
ReleaseSysCache(ht_indrel);
- /*
- * Disconnect from SPI manager
- */
- if (SPI_finish() != SPI_OK_FINISH)
- elog(ERROR, "get_viewdef: SPI_finish() failed");
-
PG_RETURN_TEXT_P(indexdef);
}
@@ -2546,6 +2500,32 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
dpns->namespace = sv_namespace;
}
+/* ----------
+ * get_opclass_name - fetch name of an index operator class
+ *
+ * The opclass name is appended (after a space) to buf.
+ * If "only_nondefault" is true, the opclass name is appended only if
+ * it isn't the default for its datatype.
+ * ----------
+ */
+static void
+get_opclass_name(Oid opclass, bool only_nondefault,
+ StringInfo buf)
+{
+ HeapTuple ht_opc;
+ Form_pg_opclass opcrec;
+
+ ht_opc = SearchSysCache(CLAOID,
+ ObjectIdGetDatum(opclass),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(ht_opc))
+ elog(ERROR, "cache lookup failed for opclass %u", opclass);
+ opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
+ if (!only_nondefault || !opcrec->opcdefault)
+ appendStringInfo(buf, " %s",
+ quote_identifier(NameStr(opcrec->opcname)));
+ ReleaseSysCache(ht_opc);
+}
/* ----------
* tleIsArrayAssign - check for array assignment