/*
 * Copyright 1990 by Baylor College of Medicine ALL RIGHTS RESERVED. 
 *
 * This program is subject to a license agreement between 
 * Baylor College of Medicine and MIT. Any use inconsistent with
 * said license and any use by persons other than the faculty, 
 * students and staff at MIT or any use on a computer not operated 
 * as part of the Athena Computing Environment (ACE) is expressly 
 * prohibited.
 */
/*
 *		This file contains the code for communicating with the
 *		SQL server.
 */
#include <stdio.h>
char *sprintf() ;
#include <varargs.h>
#include "sy_io.h"

static char left_overs[512] ;
static int nleft = 0 ;
static int current_column = 1 ;

/*
 *		Flushes any characters out to the SQL server.
 *		Does nothing if none are there.
 */
static
flush_chrs()
{
	if (nleft > 0)
	{
		left_overs[nleft] = 0 ;
		nleft = 0 ;
		if (debug_sy_io)
		{
			(void)fprintf(stderr,"%s",left_overs) ;
			(void)fflush(stderr) ;
		}
		if (db_process != NULL)
		{
			dbcmd(db_process,left_overs) ;
		}
	}
}

/*
 *		Adds a character to the current SQL command buffer.
 */
static
add_db_char(c)
	char c ;
{
	if (nleft >= (sizeof left_overs) - 1)
	{
		flush_chrs() ;
	}
	left_overs[nleft++] = c ;
}

/*
 *		Adds a string to the current SQL command buffer.
 */
sy_puts(s)
	char *s ;
{
	while(*s)
	{
		add_db_char(*s++) ;
	}
}

#define QUOTE '\''

/*
 *		Adds a quoted string to the current SQL command buffer.
 */
static
add_db_qu_str(s)
	char *s ;
{
	if (s != NULL)
	{
		add_db_char(QUOTE) ;
		while(*s)
		{
			if (*s == QUOTE)
				add_db_char(QUOTE) ;
			add_db_char(*s++) ;
		}
		add_db_char(QUOTE) ;
	}
	else
	{
		sy_puts("NULL") ;
	}
}

/*
 *		Adds an unsigned int to the current SQL command buffer.
 */
static
add_db_unsigned_int(i)
	unsigned int i ;
{
	char buf[80] ;
	(void)sprintf(buf,"%u",i) ;
	sy_puts(buf) ;
}

/*
 *		Adds an unsigned int to the current SQL command buffer.
 */
static
add_db_unsigned_long(i)
	unsigned long i ;
{
	char buf[80] ;
	(void)sprintf(buf,"%lu",i) ;
	sy_puts(buf) ;
}

/*
 *		Adds a float number
 */
static
add_db_float(ctrl,i)
	char ctrl ;
	float i ;
{
	char buf[80] ;
	char ctrl_str[20] ;
	(void)sprintf(ctrl_str,"%%%c",ctrl) ;
	(void)sprintf(buf,ctrl_str,i) ;
	sy_puts(buf) ;
}

/*
 *		Adds an integer number
 */
static
add_db_num(ctrl,i)
	char ctrl ;
	int i ;
{
	char buf[80] ;
	char ctrl_str[20] ;
	(void)sprintf(ctrl_str,"%%%c",ctrl) ;
	(void)sprintf(buf,ctrl_str,i) ;
	sy_puts(buf) ;
}

/*
 *		Adds a long number
 */
static
add_db_long_num(ctrl,i)
	char ctrl ;
	long i ;
{
	char buf[80] ;
	char ctrl_str[20] ;
	(void)sprintf(ctrl_str,"%%l%c",ctrl) ;
	(void)sprintf(buf,ctrl_str,i) ;
	sy_puts(buf) ;
}

/*
 *		Adds a double number
 */
static
add_db_double(ctrl,i)
	char ctrl ;
	double i ;
{
	char buf[80] ;
	char ctrl_str[20] ;
	(void)sprintf(ctrl_str,"%%l%c",ctrl) ;
	(void)sprintf(buf,ctrl_str,i) ;
	sy_puts(buf) ;
}

/*
 *		Converts to lowercase.
 */
static
tolow(c)
	char c ;
{
	return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c ;
}

static
sy_vprintf(ctrl,pvar)
	char *ctrl ;
	va_list pvar ;
{
	while(*ctrl)
	{
		int c = *ctrl++ ;
		if (c == '%')
		{
			char ctl ;
			int lng = 0 ;
			if (*ctrl == 'l' || *ctrl == 'L')
			{
				lng = 1 ;
				ctrl++ ;
			}
			switch(ctl = tolow(*ctrl++))
			{
				case 'u' :
					if (lng)
					{
						unsigned long i = va_arg(pvar,unsigned long) ;
						add_db_unsigned_long(i) ;
					}
					else
					{
						unsigned int i = va_arg(pvar,unsigned int) ;
						add_db_unsigned_int(i) ;
					}
					break ;
				case 'i' :
				case 'd' :
				case 'o' :
				case 'x' :
				case 'c' :
					if (lng)
					{
						long i = va_arg(pvar,long) ;
						add_db_long_num(ctl,i) ;
					}
					else
					{
						int i = va_arg(pvar,int) ;
						add_db_num(ctl,i) ;
					}
					break ;
				case 'f' :
				case 'g' :
					if (lng)
					{
						double i = va_arg(pvar,double) ;
						add_db_double(ctl,i) ;
					}
					else
					{
						float i = va_arg(pvar,double) ;
						add_db_float(ctl,i) ;
					}
					break ;
				case 's' :
				{
					char *p = va_arg(pvar,char *) ;
					if (p != NULL)
						sy_puts(p) ;
					else
						sy_puts("NULL") ;
					break ;
				}
				case 'q' :
				{
					char *p = va_arg(pvar,char *) ;
					add_db_qu_str(p) ;
					break ;
				}
				default :
					add_db_char(ctl) ;
					break ;
			}
		}
		else
		{
			add_db_char(c) ;
		}
	}
}

/*VARARGS*/
sy_printf(ctrl,va_alist)
	char *ctrl ;
	va_dcl
{
	va_list pvar ;
	va_start(pvar) ;
	sy_vprintf(ctrl,pvar) ;
	va_end(pvar) ;
}

/*VARARGS*/
sy_printf_exec(ctrl,va_alist)
	char *ctrl ;
	va_dcl
{
	va_list pvar ;
	va_start(pvar) ;
	sy_vprintf(ctrl,pvar) ;
	va_end(pvar) ;
	return sy_exec_res() ;
}

/*
 *		Executes sybase command and gets results.  Returns -1 if error.
 */
sy_exec_res()
{
	return
		(sy_exec() != SUCCEED) ?
			-1 :
		(sy_results() != SUCCEED) ?
			-1 :
			0 ;
}

/*
 *		Executes sql command.
 */
sy_exec()
{
	flush_chrs() ;
	if (debug_sy_io)
	{
		(void)fprintf(stderr,"\n") ;
		(void)fflush(stderr) ;
	}
	if (db_process != NULL)
	{
		int rc ;
		dbcancel(db_process) ;
		rc = dbsqlexec(db_process) ;
		if (debug_sy_io)
		{
			if (rc == SUCCEED)
			{
				(void)fprintf(stderr,"sy_exec = SUCCEED\n") ;
			}
			else
			{
				(void)fprintf(stderr,"sy_exec = %d\n",rc) ;
			}
		}
		return rc ;
	}
	return FAIL ;
}

static
get_field(i,type,ptr)
	BYTE *ptr ;
{
	current_column = i + 1 ;
	if (db_process != NULL && i >= 1 && i <= dbnumcols(db_process))
	{
		BYTE *data = dbdata(db_process,i) ;
		int len = dbdatlen(db_process,i) ;
		int dtype = dbcoltype(db_process,i) ;
		if (len)
		{
			dbconvert(db_process,dtype,data,len,type,ptr,-1) ;
			return 0 ;
		}
	}
	return -1 ;
}

get_int_field(i)
{
	DBINT ival ;
	int res =
		get_field(i,SYBINT4,(BYTE *)&ival) < 0 ?
			0 :
			ival ;
	if (debug_sy_io)
	{
		(void)fprintf(stderr,"get_int_field(%d) = %d\n",i,res) ;
		(void)fflush(stderr) ;
	}
	return res ;
}

get_int_result()
{
	return get_int_field(current_column) ;
}

get_str_field(i,s)
	char *s ;
{
	if (get_field(i,SYBCHAR,(BYTE *)s) < 0)
	{
		s[0] = 0 ;
	}
	if (debug_sy_io)
	{
		(void)fprintf(stderr,"get_str_field(%d) = %s\n",i,s) ;
		(void)fflush(stderr) ;
	}
}

get_str_result(s)
	char *s ;
{
	get_str_field(current_column,s) ;
}

ignore_result()
{
	current_column++ ;
}

sy_results()
{
	int rc = (db_process == NULL) ? FAIL : dbresults(db_process) ;
	if (debug_sy_io)
	{
		if (rc == SUCCEED)
		{
			(void)fprintf(stderr,"sy_results = SUCCEED\n") ;
		}
		else
		{
			(void)fprintf(stderr,"sy_results = %d\n",rc) ;
		}
		(void)fflush(stderr) ;
	}
	return rc ;
}

sy_get_row()
{
	int rc = (db_process == NULL) ? NO_MORE_ROWS : dbnextrow(db_process) ;
	if (debug_sy_io)
	{
		if (rc == MORE_ROWS)
		{
			(void)fprintf(stderr,"sy_get_row = MORE_ROWS\n") ;
		}
		else if (rc == NO_MORE_ROWS)
		{
			(void)fprintf(stderr,"sy_get_row = NO_MORE_ROWS\n") ;
		}
		else
		{
			(void)fprintf(stderr,"sy_get_row = %d\n",rc) ;
		}
		(void)fflush(stderr) ;
	}
	current_column = 1 ;
	return rc ;
}

sy_ret_code()
{
	int rc = (db_process == NULL) ? -1 : dbretstatus(db_process) ;
	if (debug_sy_io)
	{
		(void)fprintf(stderr,"sy_ret_code = %d\n",rc) ;
		(void)fflush(stderr) ;
	}
	return rc ;
}

sy_open(log_name,passwd,server,application)
	char *log_name ;
	char *passwd ;
	char *server ;
	char *application ;
{
	LOGINREC *login = dblogin() ;
	if (login == NULL)
	{
		return -1 ;
	}
	if (log_name != NULL)
	{
		DBSETLUSER(login,log_name) ;
	}
	if (passwd != NULL)
	{
		DBSETLPWD(login, passwd) ;
	}
	if (server != NULL)
	{
		DBSETLHOST(login, server) ;
	}
	if (application != NULL)
	{
		DBSETLAPP(login,application) ;
	}
	if ((db_process = dbopen(login, server)) == NULL)
	{
		return -1 ;
	}
	return 0 ;
}

sy_close()
{
	if (db_process != NULL)
	{
		dbclose(db_process) ;
		db_process = NULL ;
	}
}

/*
 *      Message routines for sybase.
 */
static
err_handler(db_process, severity, errno, oserr)
    DBPROCESS *db_process ;
{
    if (oserr != DBNOERR)
    {
        (void) fprintf(stderr, "Operating System Error:\n\t%s\n",
                dboserrstr(errno)) ;
		fflush(stderr) ;
    }
    return
        ((db_process == NULL) || (DBDEAD(db_process))) ?
            INT_EXIT : INT_CANCEL ;
}

static
msg_handler(db_process, msgno, msgstate, severity, msgtext)
    DBPROCESS *db_process ;
    char *msgtext ;
{
	if (severity)
	{
		(void) fprintf(stderr,
			"DataServer message %d, state %d, severity %d:\n\t%s\n",
			msgno, msgstate, severity, msgtext) ;
		fflush(stderr) ;
	}
    return DBNOSAVE ;
}

set_default_handlers()
{
    dberrhandle(err_handler) ;
    dbmsghandle(msg_handler) ;
}

sy_use(db)
	char *db ;
{
	return (dbuse(db_process,db) == SUCCEED) ? 0 : -1 ;
}

sy_get_one_row()
{
	return (sy_get_row() == MORE_ROWS) ? 0 : -1 ;
}
