Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e5bbf19

Browse files
committed
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.
1 parent 0648d78 commit e5bbf19

File tree

1 file changed

+84
-104
lines changed

1 file changed

+84
-104
lines changed

src/backend/utils/adt/ruleutils.c

Lines changed: 84 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* back to source text
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.82 2001/08/12 21:35:19 tgl Exp $
6+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.83 2001/10/01 20:15:26 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -41,7 +41,9 @@
4141
#include <fcntl.h>
4242

4343
#include "catalog/heap.h"
44+
#include "catalog/index.h"
4445
#include "catalog/pg_index.h"
46+
#include "catalog/pg_opclass.h"
4547
#include "catalog/pg_operator.h"
4648
#include "catalog/pg_shadow.h"
4749
#include "executor/spi.h"
@@ -94,10 +96,6 @@ static void *plan_getrule = NULL;
9496
static char *query_getrule = "SELECT * FROM pg_rewrite WHERE rulename = $1";
9597
static void *plan_getview = NULL;
9698
static char *query_getview = "SELECT * FROM pg_rewrite WHERE rulename = $1";
97-
static void *plan_getam = NULL;
98-
static char *query_getam = "SELECT * FROM pg_am WHERE oid = $1";
99-
static void *plan_getopclass = NULL;
100-
static char *query_getopclass = "SELECT * FROM pg_opclass WHERE oid = $1";
10199

102100

103101
/* ----------
@@ -138,6 +136,8 @@ static void get_sublink_expr(Node *node, deparse_context *context);
138136
static void get_from_clause(Query *query, deparse_context *context);
139137
static void get_from_clause_item(Node *jtnode, Query *query,
140138
deparse_context *context);
139+
static void get_opclass_name(Oid opclass, bool only_nondefault,
140+
StringInfo buf);
141141
static bool tleIsArrayAssign(TargetEntry *tle);
142142
static char *quote_identifier(char *ident);
143143
static char *get_relation_name(Oid relid);
@@ -341,48 +341,16 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
341341
HeapTuple ht_idx;
342342
HeapTuple ht_idxrel;
343343
HeapTuple ht_indrel;
344-
HeapTuple spi_tup;
345-
TupleDesc spi_ttc;
346-
int spi_fno;
347344
Form_pg_index idxrec;
348345
Form_pg_class idxrelrec;
349346
Form_pg_class indrelrec;
350-
Datum spi_args[1];
351-
char spi_nulls[2];
352-
int spirc;
347+
Form_pg_am amrec;
353348
int len;
354349
int keyno;
355350
StringInfoData buf;
356351
StringInfoData keybuf;
357352
char *sep;
358353

359-
/*
360-
* Connect to SPI manager
361-
*/
362-
if (SPI_connect() != SPI_OK_CONNECT)
363-
elog(ERROR, "get_indexdef: cannot connect to SPI manager");
364-
365-
/*
366-
* On the first call prepare the plans to lookup pg_am and pg_opclass.
367-
*/
368-
if (plan_getam == NULL)
369-
{
370-
Oid argtypes[1];
371-
void *plan;
372-
373-
argtypes[0] = OIDOID;
374-
plan = SPI_prepare(query_getam, 1, argtypes);
375-
if (plan == NULL)
376-
elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getam);
377-
plan_getam = SPI_saveplan(plan);
378-
379-
argtypes[0] = OIDOID;
380-
plan = SPI_prepare(query_getopclass, 1, argtypes);
381-
if (plan == NULL)
382-
elog(ERROR, "SPI_prepare() failed for \"%s\"", query_getopclass);
383-
plan_getopclass = SPI_saveplan(plan);
384-
}
385-
386354
/*
387355
* Fetch the pg_index tuple by the Oid of the index
388356
*/
@@ -414,35 +382,27 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
414382
indrelrec = (Form_pg_class) GETSTRUCT(ht_indrel);
415383

416384
/*
417-
* Get the am name for the index relation
385+
* Fetch the pg_am tuple of the index' access method
386+
*
387+
* There is no syscache for this, so use index.c subroutine.
418388
*/
419-
spi_args[0] = ObjectIdGetDatum(idxrelrec->relam);
420-
spi_nulls[0] = ' ';
421-
spi_nulls[1] = '\0';
422-
spirc = SPI_execp(plan_getam, spi_args, spi_nulls, 1);
423-
if (spirc != SPI_OK_SELECT)
424-
elog(ERROR, "failed to get pg_am tuple for index %s",
425-
NameStr(idxrelrec->relname));
426-
if (SPI_processed != 1)
427-
elog(ERROR, "failed to get pg_am tuple for index %s",
428-
NameStr(idxrelrec->relname));
429-
spi_tup = SPI_tuptable->vals[0];
430-
spi_ttc = SPI_tuptable->tupdesc;
431-
spi_fno = SPI_fnumber(spi_ttc, "amname");
389+
amrec = AccessMethodObjectIdGetForm(idxrelrec->relam,
390+
CurrentMemoryContext);
391+
if (!amrec)
392+
elog(ERROR, "lookup for AM %u failed", idxrelrec->relam);
432393

433394
/*
434395
* Start the index definition
435396
*/
436397
initStringInfo(&buf);
437398
appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",
438399
idxrec->indisunique ? "UNIQUE " : "",
439-
quote_identifier(pstrdup(NameStr(idxrelrec->relname))),
440-
quote_identifier(pstrdup(NameStr(indrelrec->relname))),
441-
quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
442-
spi_fno)));
400+
quote_identifier(NameStr(idxrelrec->relname)),
401+
quote_identifier(NameStr(indrelrec->relname)),
402+
quote_identifier(NameStr(amrec->amname)));
443403

444404
/*
445-
* Collect the indexed attributes
405+
* Collect the indexed attributes in keybuf
446406
*/
447407
initStringInfo(&keybuf);
448408
sep = "";
@@ -465,29 +425,14 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
465425
* If not a functional index, add the operator class name
466426
*/
467427
if (idxrec->indproc == InvalidOid)
468-
{
469-
spi_args[0] = ObjectIdGetDatum(idxrec->indclass[keyno]);
470-
spi_nulls[0] = ' ';
471-
spi_nulls[1] = '\0';
472-
spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
473-
if (spirc != SPI_OK_SELECT)
474-
elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[keyno]);
475-
if (SPI_processed != 1)
476-
elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[keyno]);
477-
spi_tup = SPI_tuptable->vals[0];
478-
spi_ttc = SPI_tuptable->tupdesc;
479-
spi_fno = SPI_fnumber(spi_ttc, "opcname");
480-
appendStringInfo(&keybuf, " %s",
481-
quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
482-
spi_fno)));
483-
}
428+
get_opclass_name(idxrec->indclass[keyno], true, &keybuf);
484429
}
485430

486-
/*
487-
* For functional index say 'func (attrs) opclass'
488-
*/
489431
if (idxrec->indproc != InvalidOid)
490432
{
433+
/*
434+
* For functional index say 'func (attrs) opclass'
435+
*/
491436
HeapTuple proctup;
492437
Form_pg_proc procStruct;
493438

@@ -498,58 +443,67 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
498443
elog(ERROR, "cache lookup for proc %u failed", idxrec->indproc);
499444
procStruct = (Form_pg_proc) GETSTRUCT(proctup);
500445

501-
appendStringInfo(&buf, "%s(%s) ",
502-
quote_identifier(pstrdup(NameStr(procStruct->proname))),
446+
appendStringInfo(&buf, "%s(%s)",
447+
quote_identifier(NameStr(procStruct->proname)),
503448
keybuf.data);
449+
get_opclass_name(idxrec->indclass[0], true, &buf);
504450

505-
spi_args[0] = ObjectIdGetDatum(idxrec->indclass[0]);
506-
spi_nulls[0] = ' ';
507-
spi_nulls[1] = '\0';
508-
spirc = SPI_execp(plan_getopclass, spi_args, spi_nulls, 1);
509-
if (spirc != SPI_OK_SELECT)
510-
elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[0]);
511-
if (SPI_processed != 1)
512-
elog(ERROR, "failed to get pg_opclass tuple %u", idxrec->indclass[0]);
513-
spi_tup = SPI_tuptable->vals[0];
514-
spi_ttc = SPI_tuptable->tupdesc;
515-
spi_fno = SPI_fnumber(spi_ttc, "opcname");
516-
appendStringInfo(&buf, "%s",
517-
quote_identifier(SPI_getvalue(spi_tup, spi_ttc,
518-
spi_fno)));
519451
ReleaseSysCache(proctup);
520452
}
521453
else
522-
454+
{
523455
/*
524-
* For the others say 'attr opclass [, ...]'
456+
* Otherwise say 'attr opclass [, ...]'
525457
*/
526458
appendStringInfo(&buf, "%s", keybuf.data);
459+
}
460+
461+
appendStringInfo(&buf, ")");
527462

528463
/*
529-
* Finish
464+
* If it's a partial index, decompile and append the predicate
530465
*/
531-
appendStringInfo(&buf, ")");
466+
if (VARSIZE(&idxrec->indpred) > VARHDRSZ)
467+
{
468+
Node *node;
469+
List *context;
470+
char *exprstr;
471+
char *str;
472+
473+
/* Convert TEXT object to C string */
474+
exprstr = DatumGetCString(DirectFunctionCall1(textout,
475+
PointerGetDatum(&idxrec->indpred)));
476+
/* Convert expression to node tree */
477+
node = (Node *) stringToNode(exprstr);
478+
/*
479+
* If top level is a List, assume it is an implicit-AND structure,
480+
* and convert to explicit AND. This is needed for partial index
481+
* predicates.
482+
*/
483+
if (node && IsA(node, List))
484+
node = (Node *) make_ands_explicit((List *) node);
485+
/* Deparse */
486+
context = deparse_context_for(NameStr(indrelrec->relname),
487+
idxrec->indrelid);
488+
str = deparse_expression(node, context, false);
489+
appendStringInfo(&buf, " WHERE %s", str);
490+
}
532491

533492
/*
534-
* Create the result in upper executor memory, and free objects
493+
* Create the result as a TEXT datum, and free working data
535494
*/
536495
len = buf.len + VARHDRSZ;
537-
indexdef = SPI_palloc(len);
496+
indexdef = (text *) palloc(len);
538497
VARATT_SIZEP(indexdef) = len;
539498
memcpy(VARDATA(indexdef), buf.data, buf.len);
540499

541500
pfree(buf.data);
542501
pfree(keybuf.data);
502+
pfree(amrec);
543503
ReleaseSysCache(ht_idx);
544504
ReleaseSysCache(ht_idxrel);
545505
ReleaseSysCache(ht_indrel);
546506

547-
/*
548-
* Disconnect from SPI manager
549-
*/
550-
if (SPI_finish() != SPI_OK_FINISH)
551-
elog(ERROR, "get_viewdef: SPI_finish() failed");
552-
553507
PG_RETURN_TEXT_P(indexdef);
554508
}
555509

@@ -2546,6 +2500,32 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
25462500
dpns->namespace = sv_namespace;
25472501
}
25482502

2503+
/* ----------
2504+
* get_opclass_name - fetch name of an index operator class
2505+
*
2506+
* The opclass name is appended (after a space) to buf.
2507+
* If "only_nondefault" is true, the opclass name is appended only if
2508+
* it isn't the default for its datatype.
2509+
* ----------
2510+
*/
2511+
static void
2512+
get_opclass_name(Oid opclass, bool only_nondefault,
2513+
StringInfo buf)
2514+
{
2515+
HeapTuple ht_opc;
2516+
Form_pg_opclass opcrec;
2517+
2518+
ht_opc = SearchSysCache(CLAOID,
2519+
ObjectIdGetDatum(opclass),
2520+
0, 0, 0);
2521+
if (!HeapTupleIsValid(ht_opc))
2522+
elog(ERROR, "cache lookup failed for opclass %u", opclass);
2523+
opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
2524+
if (!only_nondefault || !opcrec->opcdefault)
2525+
appendStringInfo(buf, " %s",
2526+
quote_identifier(NameStr(opcrec->opcname)));
2527+
ReleaseSysCache(ht_opc);
2528+
}
25492529

25502530
/* ----------
25512531
* tleIsArrayAssign - check for array assignment

0 commit comments

Comments
 (0)