/* --------------------------------
Sample database backend program function
This works for Sybase.

Jason Ng NCSA Dec 1993 likkai@ncsa.uiuc.edu

* ------------------------------------- */
#include <sybfront.h>
#include <sybdb.h>
#include <syberror.h>
#include <stdio.h>
#include <string.h>

static DBPROCESS  *dbproc;

/*
/ procedure:  msg_handler
/ desc:       This procedure handles any messages from sybase.  It stores
/             the messages in sbymsg so that the error handler
/             (err_handler) can check for certain errors.
*/

#define MAXMSG 500

static int nmsg = 0;
static char *mymsg[MAXMSG];
int msg_handler(dbproc,msgno,msgstate,severity,msgtext,srvname,procname,line)

DBPROCESS    *dbproc;
DBINT         msgno;
int           msgstate, severity;
char         *msgtext, *srvname, *procname;
DBUSMALLINT  line;

{
	  if (1)
	 {
		  /***
     	  printf("Message:\n%s\n",msgtext); fflush(stdout);
		  ***/
		  mymsg[nmsg] =  (char*) strdup(msgtext);
		  nmsg++; if(nmsg>=MAXMSG-1) nmsg=0; 
	     return(0);
	  }
}

dumpmessages()
{
  int i;
  for(i=0;i<nmsg;i++) printf(" Message: %s \n", mymsg[i]);
}

/*
/ procedure:  err_handler
/ returns:    INT_EXIT if Sybase process died or else INT_CANCEL
/ desc:       This procedure is called if Sybase returns an error
/             while processing data.  If an error occurs and Sybase
/             sends the message:"Unclosed quote before the
/             character string ')'." then assume a " was placed in
/             the data field.  In this case, call correct_error
/             to try and correct the error.
*/

int err_handler(dbproc, severity, dberr, oserr, dberrstr, oserrstr)

DBPROCESS *dbproc;
int        severity, dberr, oserr;
char      *dberrstr, *oserrstr;

{
	  if ((dbproc == NULL) || (DBDEAD(dbproc)))
          return(INT_EXIT);
     else
     {
          printf("DB-Library error:\n%s\n", dberrstr); fflush(stdout);

          if (oserr != DBNOERR)
               printf("Operating system error:\n%s\n", oserrstr);

			 dumpmessages();
          return(INT_CANCEL);
     } 
}

/*
/ procedure:  init_sybase
/ desc:       This procedure initializes the connection to Sybase
/             and sets up a db process.  If errors occur at this
/             point the program will exit.
*/

void init_sybase(char* login, char* passwd)

{
     LOGINREC   *glblogin;
	  if (dbinit() == FAIL)
     {
          printf("Error initializing db - aborting program\n");
          exit(ERREXIT);
      }

	dberrhandle(err_handler);
	dbmsghandle(msg_handler);

   if ((glblogin = dblogin()) == NULL)
   {
		  printf("Error allocating login struct - aborting program\n");
			exit(ERREXIT);
    }

	 DBSETLUSER(glblogin, login);
    DBSETLPWD(glblogin, passwd);
	 DBSETLAPP(glblogin, "import");


     if ((dbproc = dbopen(glblogin, NULL)) == NULL)
     {
          printf("Error getting a DBPROCESS struct - aborting program\n");
          exit(ERREXIT);
     }
}

/*================================================================== */

/* This is the program that you (the SQL programmer) get to write */

#define MAXITEMS 200
int execute_sql (char *sqlstring) /* sybase */

{
	char *bindvals[MAXITEMS];
	int width[MAXITEMS]; /* for output formatting */
	int ndisplayitems;
	int i,j,k,t,  return_code;
	char *ss;
	char * app_getdefine();


# define MARGIN 2
# define BUFSIZE 1000  /* malloc size - must be big, and >> STRSIZE */
# define STRSIZE 80   /* this is just for output to screen */
# define LONGSTRSIZE 300  /* threshold when it should be treated as long text */
	
	 putenv((char*) app_getdefine("SYBASE_ENV"));
    init_sybase((char*) app_getdefine("LOGIN"), (char*) app_getdefine("PASSWORD"));


	 dbcmd(dbproc, sqlstring); /* send the SQL query to sybase */

	 dbsqlexec(dbproc);

	 printf("<P><H2> OK.. RESULTS: </H2><P>" );
	 /* printf("<PLAINTEXT>");  */
	 printf("<PRE>"); 


	 /* --- now print out all the records --- */
	 while ((return_code = dbresults(dbproc)) != NO_MORE_RESULTS)
	 {
		if (return_code == SUCCEED)
		{
	      ndisplayitems = (int) dbnumcols(dbproc);
	      /*  printf("<li> found  %d cols <p>\n", ndisplayitems);  */
	      if(ndisplayitems > MAXITEMS) ndisplayitems = MAXITEMS;
	      for(i=0;i<ndisplayitems;i++) { width[i] = STRSIZE; }

			for(i=0;i<ndisplayitems;i++) {
			   t = dbcollen(dbproc,i+1); 
				if (t > BUFSIZE+5)
			      bindvals[i] = (char*) malloc(t);
			   else 
					bindvals[i] = (char*) malloc(BUFSIZE+5);
				}

			for(i=0;i<ndisplayitems;i++) 
			   dbbind(dbproc, i+1, STRINGBIND, (DBINT) 0, bindvals[i]);


			/* ================================== */

         /* buffer them up */
			initsaveoutput (ndisplayitems);
			while (dbnextrow(dbproc) != NO_MORE_ROWS) {
				saveoutput(bindvals);
				}
         displayoutput();

			/* ================================== */


			for(i=0;i<ndisplayitems;i++) free(bindvals[i]);
		}
	}
	dbclose(dbproc);

	 printf("</PRE>"); 

}

formatlongtext (text) char * text;
{

  printf("</PRE>"); 
  printf("\n%s\n", text);
  printf("<PRE>"); 

}

showimage() {
  int i = rand() %3;

  printf("<IMG SRC=http://www/SDG/People/jason/pub/color%d.gif>",i);
  fflush(stdout);
}

/* ------------------------------------------------------------------ */
struct o_store_struct { char **text;  struct o_store_struct *next; };
typedef struct o_store_struct O_STORE; 
static O_STORE *o_head  = NULL;
static O_STORE * o_tail = NULL;
static int o_nitems = 0;
static int o_nrows = 0;
static int * o_maxlen = NULL;
static int o_count = 0;

initsaveoutput (num_items) int num_items;
{
  int i;
  o_nitems =  num_items;
  o_maxlen = (int*) malloc(sizeof(int) * o_nitems);
  for(i=0;i<o_nitems;i++) o_maxlen[i] = 0;
}

saveoutput( bvals) char *bvals[];
{
  int i, slen;
  O_STORE * o;


  o = (O_STORE *) malloc(sizeof(O_STORE));
  o->next = NULL;
  o->text = (char**) malloc(sizeof(char *) * o_nitems);
  for(i=0;i<o_nitems;i++) {
	  /* trimblanks(bvals[i]); */
	  slen = strlen(bvals[i]);
	  if (slen > o_maxlen[i]) o_maxlen[i] = slen;
	  o->text[i] = strdup(bvals[i]);
	  }
   o_count++;

  if (o_tail) {
     o_tail->next  = o;  
     o_tail  = o;  
	  }
  else  {
	  o_head = o;
	  o_tail = o;
	  }

}
trimblanks(ss) char *ss;
{
   int i,n;
	n = strlen(ss);
   for(i=n-1;i>=0;i--)
      if(ss[i] != ' ') { ss[i+1] = '\0'; return; }
}

displayoutput() 
{
	 int i;
	 O_STORE *o = o_head ;

    /* --- first print the titles of fields */
	printf("</PRE>");
	 for(i=0;i<o_nitems; i++)
          printf("<b> %3d </b> %s    ", i+1, dbcolname(dbproc, i+1));
	printf("<PRE>\n\n\n");
			  
	 /* --- then print all the query results */
    while(o!= NULL) {
	    for(i=0;i<o_nitems;i++) {
			if (o_maxlen[i] >LONGSTRSIZE)   /* long text here */
				formatlongtext(o->text[i]);
			 else
            printf("%-*.*s", o_maxlen[i]+MARGIN, o_maxlen[i], o->text[i]); 
			 }
		 printf("\n");
       o = o->next;
		}
}

