/*
_____       _    _    Corso   Italia,  178
(_|__   .  (_   |_|_  56125           Pisa
(_|_) |)|(()_)()| |   tel.  +39  050 46380
  |   |               picosoft@picosoft.it

 picoSqlNet - picoSQL client library

 Copyright (C) Picosoft s.r.l. 1994-2002

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
static char rcsid[] = "$Id: RESULTS.CPP 4.0 1998/10/27 16:20:46 picoSoft Exp $";
# ifdef WIN32
# include <windows.h>
# include <sql.h>
# include <sqlext.h>
# else
extern "C" {
# include "sqltype.h"
}
# endif
# include <stdio.h>
# include "sqlhndls.h"
# include "dberror.h"

# ifdef MEM_DEBUG
extern "C" {
extern void *myMalloc(size_t);
extern void myFree(void *);
}
# else
# define myMalloc(a) malloc(a)
# define myFree(a) free(a)
# endif

extern "C" {
# ifdef MSDOS
# define strcpy lstrcpy
# define strncpy lstrcpyn
# endif

//  -   -   -   -   -   -   -   -   -

//  Returns result column descriptor information for a result set.

RETCODE SQL_API SQLColAttributes(
    HSTMT   hstmt,
    UWORD   icol,
    UWORD       fDescType,
    PTR         rgbDesc,
    SWORD   cbDescMax,
    SWORD FAR   *pcbDesc,
    SDWORD FAR  *pfDesc)
{ 
   RETCODE Return = SQL_ERROR;
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   CORBA_Principal *desc = (CORBA_Principal *)CORBA_Object_new (&TCD_Principal, 0);
   void *argv[8];

   if (!myHstmt || !myHstmt->IsA(ClntHstmt::Class))
      return SQL_INVALID_HANDLE;
   DelError(0,0,myHstmt);

   argv[0] = &Return;
   argv[1] = &myHstmt->srvHstmt;
   argv[2] = &icol;
   argv[3] = &fDescType;
   argv[4] = desc;
   desc->data = (unsigned char *)rgbDesc;
   argv[5] = &cbDescMax;
   argv[6] = pcbDesc;
   argv[7] = pfDesc;
   
   Exception *ex = Exception_new();
   if (!Invoke_invoke (myHstmt->hdbc->call,ex,"SQLColAttributes",argv)) {
      char stat[6];
      sprintf (stat,"08%03d", ex->code);
      AddError (0, 0, myHstmt, stat, ex->code, ex->description);
      Exception_log(ex);
   }
   Exception_delete (ex);
   return Return;
}

//  This returns the number of columns associated with the database
//  attached to "hstmt".

RETCODE SQL_API SQLNumResultCols(
    HSTMT   hstmt,
    SWORD FAR *pccol)
{
   RETCODE Return = SQL_ERROR;
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   void *argv[3];
   if (!myHstmt || !myHstmt->IsA(ClntHstmt::Class))
      return SQL_INVALID_HANDLE;

   DelError (0,0,myHstmt);

   argv[0] = &Return;
   argv[1] = &myHstmt->srvHstmt;
   argv[2] = pccol;
   
   Exception *ex = Exception_new();
   if (!Invoke_invoke (myHstmt->hdbc->call,ex,"SQLNumResultCols",argv)) {
      char stat[6];
      sprintf (stat,"08%03d", ex->code);
      AddError (0, 0, myHstmt, stat, ex->code, ex->description);
      Exception_log(ex);
   }
   Exception_delete (ex);
   return Return;
}

//  -   -   -   -   -   -   -   -   -

//  Return information about the database column the user wants
//  information about.

RETCODE SQL_API SQLDescribeCol(
    HSTMT   hstmt,
    UWORD   icol,
    UCHAR FAR *szColName,
    SWORD   cbColNameMax,
    SWORD FAR *pcbColName,
    SWORD FAR *pfSqlType,
    UDWORD FAR *pcbColDef,
    SWORD FAR *pibScale,
    SWORD FAR *pfNullable)
{

   RETCODE Return = SQL_ERROR;
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   void *argv[10];
   if (!myHstmt || !myHstmt->IsA(ClntHstmt::Class))
      return SQL_INVALID_HANDLE;

   DelError (0,0,myHstmt);

   argv[0] = &Return;
   argv[1] = &myHstmt->srvHstmt;
   argv[2] = &icol;
   argv[3] = szColName;
   argv[4] = &cbColNameMax;
   argv[5] = pcbColName;
   argv[6] = pfSqlType;
   argv[7] = pcbColDef;
   argv[8] = pibScale;
   argv[9] = pfNullable;
   
   Exception *ex = Exception_new();
   if (!Invoke_invoke (myHstmt->hdbc->call,ex,"SQLDescribeCol",argv)) {
      char stat[6];
      sprintf (stat,"08%03d", ex->code);
      AddError (0, 0, myHstmt, stat, ex->code, ex->description);
      Exception_log(ex);
   }
   Exception_delete (ex);
   return Return;
}

//  -   -   -   -   -   -   -   -   -

//  Associate a user-supplied buffer with a database column.

RETCODE SQL_API SQLBindCol(
    HSTMT   hstmt,
    UWORD   icol,
    SWORD   fCType,
    PTR rgbValue,
    SDWORD  cbValueMax,
    SDWORD FAR *pcbValue)
{
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   BindCol *bc;

   if (!myHstmt || !myHstmt->IsA(ClntHstmt::Class))
      return SQL_INVALID_HANDLE;
   if (icol == 0) {
      AddError (0, 0, myHstmt, "S1C00", 0, "Driver not capable");
      return SQL_ERROR;
   }
   DelError (0,0,myHstmt);
   if ((bc = myHstmt->cols.getAt (icol)))
      delete bc;
   myHstmt->cols.setAt (icol, new BindCol (icol, fCType, rgbValue, cbValueMax, pcbValue));
   return SQL_SUCCESS;
}

//  -   -   -   -   -   -   -   -   -

RETCODE SQL_API
SQLFetchBindCol(ClntHstmt * myHstmt)
{
   RETCODE Return = SQL_ERROR;
   CORBA_Sequence colSeqIn, colSeqOut;
   BindCol *b;
   register int i;
   int numCols;
   void *argv[4];

   colSeqIn.data = new void*[myHstmt->cols.size()];
   colSeqOut.data = new void*[myHstmt->cols.size()];

   for (i = 1, numCols = 0; i < myHstmt->cols.size(); i++) {
      if ((b = myHstmt->cols.getAt(i))) {
         colSeqIn.data[numCols] = &b->dataIn;
         colSeqOut.data[numCols] = &b->dataOut;
         b->dataOut.pcbValue = *b->pcbValue;
         numCols++;
      }
   }

   colSeqIn.count = numCols;
   colSeqOut.count = numCols;

   argv[0] = &Return;
   argv[1] = &myHstmt->srvHstmt;
   argv[2] = &colSeqIn;
   argv[3] = &colSeqOut;
   
   Exception *ex = Exception_new();
   if (!Invoke_invoke (myHstmt->hdbc->call,ex,"SQLFetchBindCol",argv)) {
      char stat[6];
      sprintf (stat,"08%03d", ex->code);
      AddError (0, 0, myHstmt, stat, ex->code, ex->description);
      Exception_log(ex);
   } else if (Return == SQL_SUCCESS) {
      for (i = 1; i <= myHstmt->cols.size(); i++)
         if ((b = myHstmt->cols.getAt(i)))
            *b->pcbValue = b->dataOut.pcbValue;
   }

   Exception_delete (ex);
   delete colSeqIn.data;
   delete colSeqOut.data;
   return Return;
}

//  Returns data for bound columns in the current row ("hstmt->iCursor"),
//  advances the cursor.

RETCODE SQL_API SQLFetch(
    HSTMT   hstmt)
{
   RETCODE Return = SQL_ERROR;
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   void *argv[3];
   long numCols;

   if (!myHstmt || !myHstmt->IsA(ClntHstmt::Class))
      return SQL_INVALID_HANDLE;

   DelError (0,0,myHstmt);

   if (myHstmt->cols.size() > 1)
      return SQLFetchBindCol (myHstmt);

   argv[0] = &Return;
   argv[1] = &myHstmt->srvHstmt;
   argv[2] = &numCols;
   
   Exception *ex = Exception_new();
   if (!Invoke_invoke (myHstmt->hdbc->call,ex,"SQLFetch",argv)) {
      char stat[6];
      sprintf (stat,"08%03d", ex->code);
      AddError (0, 0, myHstmt, stat, ex->code, ex->description);
      Exception_log(ex);
   } else if (Return == SQL_SUCCESS) {
      BindCol *bc;
      register unsigned short i = myHstmt->cols.size() - 1; /* perche si salta l'elemento 0 */
      i =  i < numCols ? i : (unsigned short)numCols;
      for ( ; i > 0; i--)
         if (bc = myHstmt->cols.getAt(i))
            if ((Return = SQLGetData (hstmt, i, bc->dataIn.fCType, bc->dataOut.any->data,
                           bc->dataIn.cbValueMax, bc->pcbValue)) != SQL_SUCCESS)
               break;
   }
   Exception_delete (ex);
   return Return;
}

//  Returns result data for a single column in the current row.

RETCODE SQL_API SQLGetData(
    HSTMT   hstmt,
    UWORD   icol,
    SWORD   fCType,
    PTR rgbValue,
    SDWORD  cbValueMax,
    SDWORD FAR *pcbValue)
{
   CORBA_TCKindDesc * anyType (HSTMT, unsigned short, short *);
   RETCODE Return = SQL_ERROR;
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   CORBA_TCKindDesc *tcIn = anyType (hstmt, icol, &fCType);
   CORBA_Any *any = (CORBA_Any *)CORBA_Object_new (&TCD_any, 0);
   CORBA_Principal *intObject = 0;

   if (tcIn == &TCD_Principal) {
      intObject = (CORBA_Principal *) CORBA_Object_new (&TCD_Principal, 0);
      intObject->data = (unsigned char*) rgbValue;
      any->data = intObject;
   } else {
      any->data = rgbValue;
   }

   void *argv[7];
   
   if (!myHstmt || !myHstmt->IsA(ClntHstmt::Class))
      return SQL_INVALID_HANDLE;
   DelError (0,0,myHstmt);
   argv[0] = &Return;
   argv[1] = &myHstmt->srvHstmt;
   argv[2] = &icol;
   argv[3] = &fCType;
   argv[4] = any;
   argv[5] = &cbValueMax;
   argv[6] = pcbValue;
   
   Exception *ex = Exception_new();
   if (!Invoke_invoke (myHstmt->hdbc->call,ex,"SQLGetData",argv)) {
      char stat[6];
      sprintf (stat,"08%03d", ex->code);
      AddError (0, 0, myHstmt, stat, ex->code, ex->description);
      Exception_log(ex);
   } else {
      myFree (any->tcOut);
      if (any->tcIn == any->tcOut)
         any->tcIn = 0;
      any->tcOut = 0;
   }
   if (intObject)
      CORBA_Object_delete (intObject, &TCD_Principal);
   CORBA_Object_delete (any, &TCD_any);
   Exception_delete (ex);

   return Return;
}

//  This determines whether there are more results sets available for
//  the "hstmt".

RETCODE SQL_API SQLMoreResults(
    HSTMT   hstmt)
{
   RETCODE Return = SQL_ERROR;
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   void *argv[2];

   if (!myHstmt || !myHstmt->IsA(ClntHstmt::Class))
      return SQL_INVALID_HANDLE;

   DelError (0,0,myHstmt);

   argv[0] = &Return;
   argv[1] = &myHstmt->srvHstmt;

   Exception *ex = Exception_new();
   if (!Invoke_invoke (myHstmt->hdbc->call, ex, "SQLMoreResults", argv)) {
      char stat[6];
      sprintf (stat,"08%03d", ex->code);
      AddError (0, 0, myHstmt, stat, ex->code, ex->description);
      Exception_log(ex);
   }
   Exception_delete (ex);
   return Return;
}

//  -   -   -   -   -   -   -   -   -

//  This returns the number of rows associated with the database
//  attached to "hstmt".

RETCODE SQL_API SQLRowCount(
    HSTMT   hstmt,
    SDWORD FAR *pcrow)
{
   RETCODE Return = SQL_ERROR;
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   void *argv[3];
   if (!myHstmt || !myHstmt->IsA(ClntHstmt::Class))
      return SQL_INVALID_HANDLE;
   DelError (0,0,myHstmt);

   argv[0] = &Return;
   argv[1] = &myHstmt->srvHstmt;
   argv[2] = pcrow;
   
   Exception *ex = Exception_new();
   if (!Invoke_invoke (myHstmt->hdbc->call,ex,"SQLRowCount",argv)) {
      char stat[6];
      sprintf (stat,"08%03d", ex->code);
      AddError (0, 0, myHstmt, stat, ex->code, ex->description);
      Exception_log(ex);
   }
   Exception_delete (ex);
   return Return;
}
//  -   -   -   -   -   -   -   -   -

//  -   -   -   -   -   -   -   -   -

//  This fetchs a block of data (rowset).

RETCODE SQL_API SQLExtendedFetch(
    HSTMT   hstmt,
    UWORD   fFetchType,
    SDWORD  irow,
    UDWORD FAR *pcrow,
    UWORD FAR *rgfRowStatus)
{
   RETCODE Return = SQL_ERROR;
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   void *argv[7];
   long numCols;

   if (!myHstmt || !myHstmt->IsA(ClntHstmt::Class))
      return SQL_INVALID_HANDLE;

   DelError (0,0,myHstmt);
   argv[0] = &Return;
   argv[1] = &myHstmt->srvHstmt;
   argv[2] = &fFetchType;
   argv[3] = &irow;
   argv[4] = pcrow;
   argv[5] = rgfRowStatus;
   argv[6] = &numCols;
   
   Exception *ex = Exception_new();
   if (!Invoke_invoke (myHstmt->hdbc->call,ex,"SQLExtendedFetch",argv)) {
      char stat[6];
      sprintf (stat,"08%03d", ex->code);
      AddError (0, 0, myHstmt, stat, ex->code, ex->description);
      Exception_log(ex);
   } else if (Return == SQL_SUCCESS) {
      BindCol *bc;
      register unsigned short i = myHstmt->cols.size() - 1; /* perche si salta l'elemento 0 */
      i =  i < numCols ? i : (unsigned short)numCols;
      for ( ; i > 0; i--)
         if (bc = myHstmt->cols.getAt(i))
            if ((Return = SQLGetData (hstmt, i, bc->dataIn.fCType, bc->dataOut.any->data,
                           bc->dataIn.cbValueMax, bc->pcbValue)) != SQL_SUCCESS)
               break;
   }
   Exception_delete (ex);
   return Return;
}

//  Returns the next SQL error information.

RETCODE SQL_API SQLError(
    HENV    henv,
    HDBC    hdbc,
    HSTMT   hstmt,
    UCHAR FAR *outSqlState,
    SDWORD FAR *outNativeError,
    UCHAR FAR *outErrorMsg,
    SWORD   cbErrorMsgMax,
    SWORD FAR *pcbErrorMsg)
{

   RETCODE Return = SQL_ERROR;
   Invoke *call = 0;
   ClntHenv *myHenv = (ClntHenv *) henv;
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   ClntHdbc *myHdbc = (ClntHdbc *) hdbc;
   void *argv[9];

   if ((Return = GetError (myHenv, myHdbc, myHstmt, outSqlState, *outNativeError,
                          outErrorMsg, cbErrorMsgMax, *pcbErrorMsg)) != SQL_NO_DATA_FOUND)
      return Return;
   argv[0] = &Return;
   argv[1] = &henv;

   if (hdbc) {
      call = myHdbc->call;
      argv[2] = &myHdbc->srvHdbc;
   } else 
      argv[2] = &hdbc;

   if (hstmt) {
      call = myHstmt->hdbc->call;
      argv[3] = &myHstmt->srvHstmt;
   } else 
      argv[3] = &hstmt;
   argv[4] = outSqlState;
   argv[5] = outNativeError;
   argv[6] = outErrorMsg;
   argv[7] = &cbErrorMsgMax;
   argv[8] = pcbErrorMsg;
   
   Exception *ex = Exception_new();
   if (call) {
      if (!Invoke_invoke (call,ex,"SQLError",argv)) {
         char stat[6];
         sprintf (stat,"08%03d", ex->code);
         AddError (myHenv, myHdbc, myHstmt, stat, ex->code, ex->description);
         Exception_log(ex);
      }
   } else {
      Return = SQL_NO_DATA_FOUND;
   }
   Exception_delete (ex);
   return Return;
}
};
