/*
 * NAME
 *     tst_arrays
 *
 * USAGE
 *      pg_dd [-d database] [-o output_file] [-g 0|1|2] [-t] 
 *
 * ARGUMENTS
 *     -d   POSTGRES database name
 *
 *     -o   Output filename. If not set, output is sent to the screen.
 *
 *     -g   gdi degub level: 0 (off) by default
 *          1 = GDI_DEBUG_ON
 *          2 = GDI_DEBUG_VERBOSE
 *
 *     -t   turns PQtrace on
 *
 * DESCRIPTION
 *      Retrieves array data from test_strings2. One attribute is a fixed size 
 *      array, the other is an undimensioned array of text.
 *
 * NOTES
 *      This is a misbehaved example on how to access GDI_TURBO data.  It's a 
 *      no-no to access turboTup data directly like the code does down below.
 *      It makes this code completely specific to GDI_TURBO. However, it's 
 *      much easier to debug and make sure that the arrays work the way they 
 *      are supposed to.
 *
 *      tst_num_arrays is an example of the "correct" way to access data in 
 *      turboTup.
 *
 * AUTHOR
 *     Jean T. Anderson, jean@gso.saic.com
 */
#ifndef lint
static char     SccsId[] = "%W% %G%";
#endif

#include <stdio.h>
#include <stddef.h>
#include "gdi_postgres.h"
#include "gdi_turbo.h"
#include "errno.h"
#include "proto.h"

FILE      *fp, *fopen();
extern    void perror();
extern    int getopt();

Proto     (static void,     pg_cleanup, (dbConn *dbconn));
Proto     (static dbStatus, pg_arrays,  (dbconn *dbconn));

dbConstr  *constr;

char      filename[256];

#define USAGE\
"Usage:\ttst_arrays\t[-d database] [-o output_filename] [-g 0|1|2] [-t]"

extern char     *optarg;

/****************************************************************************/
/*  main                                                                    */
/****************************************************************************/
void
main(argc, argv)
int        argc;
char      **argv;
{
     char    *vendor="postgres";
     char    database[GDI_DBNAME_SIZE +1];

     int     c;

     dbConn  *dbconn = NULL;      /* GDI database connector */
     int     debug=0, trace=0;    /* GDI debug and trace */

     /* GDI_TURBO is the only constructor that does POSTGRES array types */
     constr = &GDI_TURBO;

     /*=====================================================*
      *========= Get command line arguments ================*
      *=====================================================*/

     database[0] = '\0';
     filename[0] = '\0';

     while ((c = getopt(argc, argv, "d:g:ho:t")) != EOF)
     {
          switch(c)
          {
          case 'd':
               (void) strncpy (database, optarg, sizeof(database) - 1);
               database[sizeof(database) - 1] = '\0';
               break;
          case 'o':
               (void) strncpy (filename, optarg, sizeof(filename) - 1);
               filename[sizeof(filename) - 1] = '\0';
               break;
          case 'g':
               debug = atoi (optarg);
               break;
          case 'h':
               fprintf(stderr, "%s\n", USAGE);
               exit(0);
          case 't':
               trace++;
               break;
          default:
               fprintf(stderr, "%s\n", USAGE);
               exit(1);
          }
     }

     /* ==============
      * Initialize GDI
      * ==============
      */

     gdi_init(argv[0]);

     /* ====================
      * Connect to Database
      * ====================
      */
     if ((dbconn = gdi_open(vendor, NULL, NULL, database, NULL, NULL))
          == (dbConn *)NULL )
     {
          fprintf (stderr, "Connect failed: %s\n", 
                    GDI_ERROR_MSG( (dbConn *)NULL) );
          exit (GDI_FAILURE);
     }

     /* ====================
      * Set Debug & Trace
      * ====================
      */
     (void) gdi_error_init(dbconn, (dbDebug) debug, GDI_WARNING, 
          GDI_NOT_USED, GDI_NOT_USED);

     if(trace)
          gdi_trace(dbconn, TRUE, "");

     /* ====================
      * Open output file
      * ====================
      */
     if(filename[0] == '\0')
          fp=stdout;
     else 
     {    fp=fopen(filename, "w");
          if(fp == NULL)
          {    perror (argv[0]);
               (void) gdi_close(dbconn);
               exit(GDI_FAILURE);
          }
     }

     if( (pg_arrays(dbconn)) != GDI_SUCCESS)
     {
          fprintf (stderr, "pg_class failed: %s\n", 
               GDI_ERROR_MSG(dbconn));
          pg_cleanup(dbconn);
          exit(GDI_FAILURE);
     }
     pg_cleanup(dbconn);
     exit(GDI_SUCCESS);
}

static
dbStatus
pg_arrays(dbconn)
dbConn  *dbconn;
{
     char     query[80];
     int      i, j, k, tuples1, col_num;

     dbObj    *result = NULL;
     turboTup *tuple1 = NULL;

     char     array_name [PG_CLASS_SIZE + 1];
     int      array_size, str_size;
  
     sprintf(query, "retrieve (test_strings2.all)");

     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 )
     {    
          fprintf(fp, "No data found.\n");
          result = gdi_obj_destroy(result);
          return(GDI_SUCCESS);
     }
     col_num = GDI_OBJ_NUM_COLUMNS(result);

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

          for(j=0; j < col_num; j++)
          {
               array_size = ((tuple1)->col[j].arr_length);
               str_size = ((tuple1)->col[j].str_length);

               fprintf(fp, 
                    "\nTuple %d Column %d has %d elements.", 
                    i, j, array_size);
               fprintf(fp, 
               " The max string length is %d, including the NULL terminator.",
                    str_size);
               fprintf(fp, " Values are:\n");

               for(k=0; k < array_size; k++)
                    fprintf(fp, "<%s>\t", 
                         ((char **)((tuple1)->col[j].value.ptr))[k]);
               fprintf(fp, "\n");
          }

     } 

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

static
void
pg_cleanup(dbconn)
dbConn     *dbconn;
{
     if(gdi_close(dbconn) != GDI_SUCCESS)
     {
          fprintf (stderr, "gdi_close failed: %s\n", 
               GDI_ERROR_MSG(dbconn));
          exit(GDI_FAILURE);
     }

     if(strlen(filename) > 0)
          fclose(filename);
     return;
}
