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 *
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;
9496static char * query_getrule = "SELECT * FROM pg_rewrite WHERE rulename = $1" ;
9597static void * plan_getview = NULL ;
9698static 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);
138136static void get_from_clause (Query * query ,deparse_context * context );
139137static void get_from_clause_item (Node * jtnode ,Query * query ,
140138deparse_context * context );
139+ static void get_opclass_name (Oid opclass ,bool only_nondefault ,
140+ StringInfo buf );
141141static bool tleIsArrayAssign (TargetEntry * tle );
142142static char * quote_identifier (char * ident );
143143static char * get_relation_name (Oid relid );
@@ -341,48 +341,16 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
341341HeapTuple ht_idx ;
342342HeapTuple ht_idxrel ;
343343HeapTuple ht_indrel ;
344- HeapTuple spi_tup ;
345- TupleDesc spi_ttc ;
346- int spi_fno ;
347344Form_pg_index idxrec ;
348345Form_pg_class idxrelrec ;
349346Form_pg_class indrelrec ;
350- Datum spi_args [1 ];
351- char spi_nulls [2 ];
352- int spirc ;
347+ Form_pg_am amrec ;
353348int len ;
354349int keyno ;
355350StringInfoData buf ;
356351StringInfoData keybuf ;
357352char * 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)
414382indrelrec = (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 */
436397initStringInfo (& buf );
437398appendStringInfo (& buf ,"CREATE %sINDEX %s ON %s USING %s (" ,
438399idxrec -> 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 */
447407initStringInfo (& keybuf );
448408sep = "" ;
@@ -465,29 +425,14 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
465425 * If not a functional index, add the operator class name
466426 */
467427if (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- */
489431if (idxrec -> indproc != InvalidOid )
490432{
433+ /*
434+ * For functional index say 'func (attrs) opclass'
435+ */
491436HeapTuple proctup ;
492437Form_pg_proc procStruct ;
493438
@@ -498,58 +443,67 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
498443elog (ERROR ,"cache lookup for proc %u failed" ,idxrec -> indproc );
499444procStruct = (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 )),
503448keybuf .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 )));
519451ReleaseSysCache (proctup );
520452}
521453else
522-
454+ {
523455/*
524- *For the others say 'attr opclass [, ...]'
456+ *Otherwise say 'attr opclass [, ...]'
525457 */
526458appendStringInfo (& 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 resultin upper executor memory , and freeobjects
493+ * Create the resultas a TEXT datum , and freeworking data
535494 */
536495len = buf .len + VARHDRSZ ;
537- indexdef = SPI_palloc (len );
496+ indexdef = ( text * ) palloc (len );
538497VARATT_SIZEP (indexdef )= len ;
539498memcpy (VARDATA (indexdef ),buf .data ,buf .len );
540499
541500pfree (buf .data );
542501pfree (keybuf .data );
502+ pfree (amrec );
543503ReleaseSysCache (ht_idx );
544504ReleaseSysCache (ht_idxrel );
545505ReleaseSysCache (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-
553507PG_RETURN_TEXT_P (indexdef );
554508}
555509
@@ -2546,6 +2500,32 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
25462500dpns -> 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