]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Extend pg_get_indexdef() to know about index predicates. Also, tweak
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 1 Oct 2001 20:15:26 +0000 (20:15 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 1 Oct 2001 20:15:26 +0000 (20:15 +0000)
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.

src/backend/utils/adt/ruleutils.c

index a5f9d2ace1a0c319137d339c343e945381079f9d..6d4d926078d4385131b14580f9d44f83174741da 100644 (file)
@@ -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,48 +341,16 @@ 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;
        StringInfoData keybuf;
        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
         */
@@ -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