/*
 * NAME
 *
 * Public:
 *     pg_classes()   - get class definitions
 *
 * Private:
 *     pg_describe()   - gets attribute information
 *     pg_inherits()   - does the class inherit any other class?
 *
 * FILES
 *     pg_classes.c
 *
 * AUTHOR
 *     J.T. Anderson, jean@gso.saic.com
 */
#ifndef lint
static char SccsId[] = "@(#)pg_classes.c	5.7 8/12/93";
#endif

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

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

extern dbConstr     *constr;

Proto (static dbStatus, pg_describe, 
          (dbConn *dbconn, int coid, char *class_name, FILE *fp));
Proto (static dbStatus, pg_inherits,     
          (dbConn *dbconn, int class_oid, dbObj **results));

char     query_class[300];

dbStatus
pg_class(dbconn, obj_name, fp)
dbConn  *dbconn;
char    *obj_name;
FILE    *fp;
{
     char     *pg_type="CLASSES";
     char     *tmp_class, *comment;
     int      *class_oid;
     int      status, i, tuples, str_length, arr_length, is_null;
     dbObj    *result_obj=NULL;
     void     *tuple = NULL;
     
     bzero(query_class, sizeof(query_class));

     if( (strlen(obj_name) == 0) || !strcmp(obj_name, "user") )
          sprintf(query_class, "%s %s", ALL_CLASSES, USER_CLASSES);
     else if(!strcmp(obj_name, "sys"))
          sprintf(query_class, "%s %s", ALL_CLASSES, SYS_CLASSES);
     else
          sprintf(query_class, 
               "%s and p.relname =\"%s\"", ALL_CLASSES, obj_name);

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

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

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

     if (GDI_OBJ_NUM_COLUMNS(result_obj) != 3)
     {    fprintf(fp, "pg_classes: expected 3 columns but got %d\n",
               GDI_OBJ_NUM_COLUMNS(result_obj));
          fprintf(fp, "pg_classes: did somebody change the query?\n");
          result_obj = gdi_obj_destroy(result_obj);
          return(GDI_FAILURE);
     }

     print_header(fp, pg_type); 

     for(i=0; i < tuples; i++)
     {
          /* step through each class name */
          if ((tuple = gdi_obj_tuple_retrieve (result_obj, i)) == NULL)
          {    fprintf(fp, "gdi_obj_tuple_retrieve failed\n");
               return(GDI_FAILURE);
          }

          /* Column 0: oid           */
          if( (class_oid = (int *) gdi_obj_get_data (result_obj, 0, tuple,
               &is_null, &str_length, &arr_length)) == NULL)
          {    fprintf(stderr, "pg_class: could not get oid\n");
               return(GDI_FAILURE);
          }

          /* Column 1: class name    */
          if( (tmp_class = (char *) gdi_obj_get_data (result_obj, 1, tuple,
               &is_null, &str_length, &arr_length)) == NULL)
          {    fprintf(stderr, "pg_class: could not get class name\n");
               return(GDI_FAILURE);
          }

          /* Column 2: comment    */
          if( (comment = (char *) gdi_obj_get_data (result_obj, 2, tuple,
               &is_null, &str_length, &arr_length)) == NULL)
          {    fprintf(stderr, "pg_class: could not get class name\n");
               return(GDI_FAILURE);
          }


          fprintf(fp, "create %s ( ", tmp_class);

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

          fprintf(fp, "\n");

          status=pg_describe(dbconn, *class_oid, tmp_class, fp);
     }

     result_obj = gdi_obj_destroy(result_obj);
     return(status);
}

static
dbStatus
pg_describe (dbconn, coid, cname, fp)
dbConn   *dbconn;
int      coid;
char     *cname;
FILE     *fp;
{
     char     *att_name, *comment, type_name[PG_CLASS_SIZE + 1]; 
     dbObj    *result = NULL;
     int      i, *is_inherited, ntup, *array_size, str_length, arr_length, is_null;
     void     *tuple = NULL;
     char     tmp_buf[30];

     dbObj    *inherits_obj = NULL;
     void     *inherits_tuple = NULL;
     int       inherits_ntup;

     bzero(query_class, sizeof(query_class));

     /* =========== Does this class inherit any others? ============ */

     if (pg_inherits(dbconn, coid, &inherits_obj) == GDI_FAILURE)
          return(GDI_FAILURE);

     inherits_ntup = GDI_OBJ_NUM_TUPLES(inherits_obj);

     /* =========== Get the attributes ============================ */
     if(inherits_ntup)
          sprintf(query_class, "%s %s and p.attrelid = %d::oid sort by attnum", 
               INHERITS_ATTRIBUTES, USER_ATTRIBUTES, coid);
     else
          sprintf(query_class, "%s %s and p.attrelid = %d::oid sort by attnum", 
               ALL_ATTRIBUTES, USER_ATTRIBUTES, coid);
     
#ifndef DEC
     assert( strlen(query_class) < sizeof(query_class) );
#endif

     if(gdi_submit(dbconn, query_class, GDI_FETCH_ALL, constr, &result) 
          != GDI_SUCCESS)
     {    fprintf(fp, "pg_describe: gdi_submit failed\n");
          result = gdi_obj_destroy (result);
          return(GDI_FAILURE);
     }

     ntup=GDI_OBJ_NUM_TUPLES(result);

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


     for (i = 0; i < ntup ; i++)
     {
          if ((tuple = gdi_obj_tuple_retrieve (result, i)) == NULL) 
          {    fprintf(fp, "pg_describe: pg_obj_tuple_retrieve failed\n");
               result = gdi_obj_destroy (result);
               return(GDI_FAILURE);
          }


          /* Column 5: is_inherited */
          if( (is_inherited = (int *) gdi_obj_get_data (result, 5, tuple,
               &is_null, &str_length, &arr_length)) == NULL)
          {    fprintf(stderr, "pg_describe: could not get is_inherited\n");
               return(GDI_FAILURE);
          }

             /* Output attribute only if it isn't inherited from another class */

          if ( *is_inherited == 0 )
          {
               /* Column 0: attname */
               if( (att_name = (char *) gdi_obj_get_data (result, 0, tuple,
                    &is_null, &str_length, &arr_length)) == NULL)
               {    fprintf(stderr, "pg_describe: could not get attname\n");
                    return(GDI_FAILURE);
               }
               /* Column 1: attnelems */
               if( (array_size = (int *) gdi_obj_get_data (result, 1, tuple,
                    &is_null, &str_length, &arr_length)) == NULL)
               {    fprintf(stderr, "pg_describe: could not get attname\n");
                    return(GDI_FAILURE);
               }

               /* Column 2: typname -- Make a copy so we can stomp on it */
               strncpy(type_name, 
                    (char *) gdi_obj_get_data (result, 2, tuple, &is_null, 
                         &str_length, &arr_length),
                    PG_CLASS_SIZE);
               type_name[PG_CLASS_SIZE] = '\0';

               /* =============================
                * Output attribute information 
                * =============================
                */
               (void) sprintf(tmp_buf, "\t%s =", att_name);

               if(*array_size == 0)
                    sprintf(tmp_buf, "%s %s", tmp_buf, type_name);
               else 
               {    
                    if(type_name[0] == '_') /* some array types begin with _ */
                         type_name[0] = ' ';  
                    if(*array_size == -1)
                         sprintf(tmp_buf, "%s %s[]", tmp_buf, type_name);
                    else
                         sprintf(tmp_buf, 
                              "%s %s[%d]", tmp_buf, type_name, *array_size);
               }

               fprintf(fp, "%s", tmp_buf);
               if (i < (ntup - 1))
                    fprintf(fp, ",");

               /* Column 3: sequoia comment */
               if( (comment = (char *) gdi_obj_get_data (result, 3, tuple,
                    &is_null, &str_length, &arr_length)) == NULL)
               {    fprintf(stderr, "pg_describe: could not get comment\n");
                    return(GDI_FAILURE);
               }
               if (is_null == 0)
               {
                    if(strlen(tmp_buf) <= 15)
                         fprintf(fp, "\t");
                    fprintf(fp, "\t/* %.*s */", COMMENT_SIZE, comment);
               }
               fprintf(fp, "\n");

               /* Column 4: attnum (skip) */
          } /* END (is_inherited == 0) */
     }

     fprintf(fp, ") ");

     result = gdi_obj_destroy (result);   /* free results */

     if(inherits_ntup == 0) 
     {    fprintf(fp, "\n\\g \n\n");
          inherits_obj = gdi_obj_destroy(inherits_obj);
          return(GDI_SUCCESS);
     }
     if (GDI_OBJ_NUM_COLUMNS(inherits_obj) != 2)
     {    fprintf(fp,
               "pg_describe: expected 2 columns from pg_inherits but got %d\n",
               GDI_OBJ_NUM_COLUMNS(result));
          fprintf(fp, "pg_describe: did somebody change the query?\n");
          inherits_obj = gdi_obj_destroy(inherits_obj);
          return(GDI_FAILURE);
     }

     for (i = 0; i < inherits_ntup ; i++)
     {
          if((inherits_tuple = gdi_obj_tuple_retrieve(inherits_obj, i)) == NULL)
          {    fprintf(stderr, "pg_describe: gdi_obj_tuple_retrieve failed\n");
               inherits_obj = gdi_obj_destroy(inherits_obj);
               return(GDI_FAILURE);
          }

          /* Column 0: inhseqno (skip it) */
          /* Column 1: relname */
          if((att_name = (char *) gdi_obj_get_data(inherits_obj,1,inherits_tuple
,
               &is_null, &str_length, &arr_length)) == NULL)
          {    fprintf(stderr, "pg_describe: could not get relname\n");
               inherits_obj = gdi_obj_destroy(inherits_obj);
               return(GDI_FAILURE);
          }

          if(i==0)
               fprintf(fp, " inherits (");

          fprintf(fp, "%s", att_name);
          if (i < inherits_ntup - 1)
               fprintf(fp, ", ");
     }
     fprintf(fp, ")");

     inherits_obj = gdi_obj_destroy(inherits_obj);

     fprintf(fp, "\n\\g \n\n");
     return(GDI_SUCCESS);
}

static
dbStatus
pg_inherits(dbconn, class_oid, results)
dbConn    *dbconn;
int       class_oid;
dbObj     **results;
{
     if ( results )
          *results = NULL;

     sprintf(query_class, "%s and p.inhrel = %d::oid sort by inhseqno", 
          INHERITS, class_oid);
     
#ifndef DEC
     assert( strlen(query_class) < sizeof(query_class) );
#endif

     if(gdi_submit(dbconn, query_class, GDI_FETCH_ALL, constr, results) 
          != GDI_SUCCESS)
     {    gdi_obj_destroy (*results);
          *results = NULL;
          return(GDI_FAILURE);
     }
     return(GDI_SUCCESS);
}
