/* NAME
 *      pg_indexes()   - get indexes
 *
 * FILES
 *      pg_indexes.c
 *
 * BUGS & HACKS
 *      indproc:  I'm not sure about decoding. Down below, if it is 0, it 
 *                outputs btree, otherwise it outputs ??? followed by the 
                  actual indproc code. 
 *      indkey:   This joins to pg_attribute.attnum. If you do a lookup on a 
 *                negative attnum, the backend exits. So down below, a check
 *                for -3 (oid) is hard coded.
 *      indclass: Operators are hard coded.
 *
 * AUTHOR
 *      J.T. Anderson, jean@gso.saic.com
 */

#ifndef lint
static char SccsId[] = "@(#)pg_indexes.c	5.5 8/5/93";
#endif

#include "pg_schema.h"
#include "dd_queries.h"

#ifndef DEC
#include "assert.h"
#endif

extern char       *strtok();
extern dbConstr   *constr;

dbStatus
pg_indexes(dbconn, obj_name, fp)
dbConn  *dbconn;
char    *obj_name;
FILE    *fp;
{
     char     *pg_type = "INDEXES";
     char     *routine = "pg_indexes";
     char     query[350];
     int      i, j, tuples1, tuples2;

     dbObj    *result = NULL, *result2 = NULL;
     void     *tuple1 = NULL, *tuple2 = NULL;

     char     *index_name, *class_name, *col_name, *comment;
     int      *indproc;

     short    indkey, **key_array;
     long     *indrelid, indclass, **class_array;

     int      str_length, arr_length, arr_length2, is_null;

     if( (strlen(obj_name) == 0) || !strcmp(obj_name, "user") )
          sprintf(query, "%s %s", ALL_INDEXES, USER_INDEXES);
     else if(!strcmp(obj_name, "sys"))
          sprintf(query, "%s %s", ALL_INDEXES, SYS_INDEXES);
     else
          sprintf(query, "%s and r1.relname =\"%s\"", ALL_INDEXES, obj_name);

#ifndef DEC
     assert( strlen(query) < sizeof(query) );
#endif

     if(gdi_submit(dbconn, query, GDI_FETCH_ALL, constr, &result)
          != GDI_SUCCESS)
     {    result = gdi_obj_destroy (result);
          return(GDI_FAILURE);
     }

     tuples1=GDI_OBJ_NUM_TUPLES(result);
     if(tuples1 == 0 )
     {    if( (strlen(obj_name) == 0) || !strcmp(obj_name, "user") )
               fprintf(fp, "No user indexes found.\n");
          else
               fprintf(fp, "Could not find index '%s' in database '%s'.\n",
                    obj_name, GDI_DATABASE(dbconn));
          result = gdi_obj_destroy(result);
          return(GDI_SUCCESS);
     }

     if (GDI_OBJ_NUM_COLUMNS(result) != 8)
     {    fprintf(fp, "%s: expected 8 columns but got %d.",
               routine, GDI_OBJ_NUM_COLUMNS(result));
          fprintf(fp, " Did somebody change the query?\n");
          result = gdi_obj_destroy(result);
          return(GDI_FAILURE);
     }

     print_header(fp, pg_type); 

     for(i=0; i < tuples1; i++)  /* process each index */
     {
          if ((tuple1 = gdi_obj_tuple_retrieve (result, i)) == NULL) 
          {    fprintf(fp, "\n%s: gdi_obj_tuple_retrieve failed on tuple1 row %d\n",
                    routine, i+1);
               result = gdi_obj_destroy(result);
               return(GDI_FAILURE);
          }

          /* Column 0: index_name           */
          if( (index_name = (char *) gdi_obj_get_data (result, 0, tuple1,
               &is_null, &str_length, &arr_length)) == NULL)
          {    fprintf(stderr, "%s: could not get index name\n", routine);
               result = gdi_obj_destroy(result);
               return(GDI_FAILURE);
          }

          /* Column 1: class_name           */
          if( (class_name = (char *) gdi_obj_get_data (result, 1, tuple1,
               &is_null, &str_length, &arr_length)) == NULL)
          {    fprintf(stderr, "%s: could not get class name\n", routine);
               result = gdi_obj_destroy(result);
               return(GDI_FAILURE);
          }

          /* Column 7: comment    */
          if( (comment = (char *) gdi_obj_get_data (result, 7, tuple1,
               &is_null, &str_length, &arr_length)) == NULL)
          {    fprintf(stderr, "%s: could not get comment\n", routine);
               result = gdi_obj_destroy(result);
               return(GDI_FAILURE);
          }


          fprintf(fp, "define index %s on %s ", index_name, class_name );

          if (is_null == 0)
               fprintf(fp, "/* %.*s */\n", COMMENT_SIZE, comment);

          /* Column 2: indexrelid  (skip)  */

          /* Column 3: indrelid     */
          if( (indrelid = (long *) gdi_obj_get_data (result, 3, tuple1,
               &is_null, &str_length, &arr_length)) == NULL)
          {    fprintf(stderr, "%s: could not get indrelid\n", routine);
               result = gdi_obj_destroy(result);
               return(GDI_FAILURE);
          }

          /* Column 6: indproc      */
          if( (indproc = (int *) gdi_obj_get_data (result, 6, tuple1,
               &is_null, &str_length, &arr_length)) == NULL)
          {    fprintf(stderr, "%s: could not get indproc\n", routine);
               result = gdi_obj_destroy(result);
               return(GDI_FAILURE);
          }

          if (*indproc == 0)
               fprintf(fp, "\tusing btree (");
          else
               fprintf(fp, "\tusing ??? (indproc=%d) (", *indproc);

          /* Column 4: indkey -- What columns are indexed?   */
          if( (key_array = (short **) gdi_obj_get_data (result, 4, tuple1,
               &is_null, &str_length, &arr_length)) == NULL)
          {    fprintf(stderr, "%s: could not get key_array\n", routine);
               result = gdi_obj_destroy(result);
               return(GDI_FAILURE);
          }

          /* Column 5: indclass      */
          if ( (class_array = (long **) gdi_obj_get_data (result, 5, tuple1,
               &is_null, &str_length, &arr_length)) == NULL)
          {    fprintf(stderr, "%s: could not get class_array\n", routine);
               result = gdi_obj_destroy(result);
               return(GDI_FAILURE);
          }

          /* What columns are indexed? how are they indexed? */

          for (j=0; j < arr_length; j++)
          {
               indkey =   (* key_array)[j];
               indclass = (* class_array)[j];

               if(indkey == 0) /* pop out of loop as soon as indkey becomes 0 */
                    break;

               if (indkey == -3)  /* querying a negative attnum exits backend */
               {
                    if ( (j > 0) && (j < (arr_length - 1) ) )
                         fprintf(fp, ", ");
                    fprintf(fp, "oid");
               }
               else 
               {
                    /* Get the attribute name */
                    sprintf(query,
                         "retrieve (a.attname) from a in pg_attribute \
                         where a.attrelid = %d::oid and a.attnum = %d",
                         *indrelid, indkey);

#ifndef DEC
                    assert( strlen(query) < sizeof(query) );
#endif

                    if(gdi_submit(dbconn, query, GDI_FETCH_ALL, constr, 
                         &result2) != GDI_SUCCESS)
                    {    result = gdi_obj_destroy (result);
                         result2 = gdi_obj_destroy (result2);
                         return(GDI_FAILURE);
                    }

                    tuples2=GDI_OBJ_NUM_TUPLES(result);
                    if(tuples2 == 0 )               /* Bizarre */
                    {    fprintf(fp, 
                           "\n%s: No column name found for attrelid %d column %d\n",
                           routine, *indrelid, indkey);
                         result = gdi_obj_destroy(result);
                         result2 = gdi_obj_destroy(result);
                         return(GDI_FAILURE);
                    }

                    /* Only one row should be there */
                    if ((tuple2 = gdi_obj_tuple_retrieve (result2, 0)) == NULL) 
                    {    fprintf(fp,
                           "\n%s: gdi_obj_tuple_retrieve failed on tuple2 row %d\n",
                           routine, j+1);
                         result = gdi_obj_destroy (result);
                         result2 = gdi_obj_destroy (result2);
                         return(GDI_FAILURE);
                    }

                    /* Column 0: col_name           */
                    if((col_name = (char *) gdi_obj_get_data (result, 0, tuple2,
                         &is_null, &str_length, &arr_length2)) == NULL)
                    {    fprintf(stderr,"%s: could not get col_name\n", routine);
                         result = gdi_obj_destroy (result);
                         result2 = gdi_obj_destroy (result2);
                         return(GDI_FAILURE);
                    }

                    if ( (j > 0) && ( j < ( arr_length - 1) ) )
                         fprintf(fp, ", ");
                    fprintf(fp, "%s", col_name);
                    result2 = gdi_obj_destroy (result2);

               } /* end get attribute name */


               switch (indclass)
               {
                    case INT2_OPS:      fprintf(fp," int2_ops");      break;
                    case BOX_OPS:       fprintf(fp," box_ops");       break;
                    case FLOAT8_OPS:    fprintf(fp," float8_ops");    break;
                    case INT24_OPS:     fprintf(fp," int24_ops");     break;
                    case INT42_OPS:     fprintf(fp," int42_ops");     break;
                    case INT4_OPS:      fprintf(fp," int4_ops");      break;
                    case OID_OPS:       fprintf(fp," oid_ops");       break;
                    case FLOAT4_OPS:    fprintf(fp," float4_ops");    break;
                    case CHAR_OPS:      fprintf(fp," char_ops");      break;
                    case CHAR16_OPS:    fprintf(fp," char16_ops");    break;
                    case TEXT_OPS:      fprintf(fp," text_ops");      break;
                    case ABSTIME_OPS:   fprintf(fp," abstime_ops");   break;
                    case BIGBOX_OPS:    fprintf(fp," bigbox_ops");    break;
                    case POLY_OPS:      fprintf(fp," poly_ops");      break;
                    case OIDINT4_OPS:   fprintf(fp," oidint4_ops");   break;
                    case OIDCHAR16_OPS: fprintf(fp," oidchar16_ops"); break;
                    default: fprintf(fp," ??? (indclass=%d)", indclass); break;
               }
          } /* end process indclass */

          fprintf(fp, ")\n\\g\n\n");

     } /* end process each index */

     result = gdi_obj_destroy(result);
     return(GDI_SUCCESS);
}
