/*
_____       _    _    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: execute.cpp 4.0 1998/10/27 16:20:29 picoSoft Exp picoSoft $";
# 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"
extern "C" {

extern CORBA_TCKindDesc Param_struct;
extern CORBA_TCKindDesc Param_seq;

RETCODE
executeParams(ClntHstmt *myHstmt)
{
   RETCODE Return = SQL_ERROR;
   void *argv[3];
   register unsigned int i;
   CORBA_Sequence parSeq;
   Parameter *p;

   for (i = 1; i < (unsigned int) myHstmt->param.size(); i++)
      if ((p = myHstmt->param.getAt(i)) == 0)
         break;
      else if (p->isDataAtExec())
         return (RETCODE) SQL_NEED_DATA;
   i--;

   parSeq.count = i;
   parSeq.data = new void*[i];
   for (i = 0; i < parSeq.count; i++) {
      p = myHstmt->param.getAt(i + 1);
      p->data.pcbValue = *p->pcbValue;
      parSeq.data[i] = &p->data;
   }

   argv[0] = &Return;
   argv[1] = &myHstmt->srvHstmt;
   argv[2] = &parSeq;
   
   Exception *ex = Exception_new();
   if (!Invoke_invoke (myHstmt->hdbc->call,ex,"SQLExecuteParams",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);
   delete parSeq.data;
   return Return;
}

RETCODE
execDirectParams(HSTMT hstmt, UCHAR FAR *szSqlStr, SDWORD  cbSqlStr)
{
   RETCODE Return = SQL_ERROR;
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   void *argv[5];
   register unsigned int i;
   CORBA_Sequence parSeq;
   Parameter *p;

   for (i = 1; i < (unsigned int) myHstmt->param.size(); i++)
      if ((p = myHstmt->param.getAt(i)) == 0)
         break;
      else if (p->isDataAtExec()) {
         if ((Return = SQLPrepare (hstmt, szSqlStr, cbSqlStr))==SQL_SUCCESS)
            return (RETCODE) SQL_NEED_DATA;
         else
            return Return;
      }

   i--;

   parSeq.count = i;
   parSeq.data = new void*[i];
   for (i = 0; i < parSeq.count; i++) {
      p = myHstmt->param.getAt(i + 1);
      if (p->pcbValue)
         p->data.pcbValue = *p->pcbValue;
      else
         p->data.pcbValue = strlen ((char *)p->data.any->data);
      parSeq.data[i] = &p->data;
   }

   argv[0] = &Return;
   argv[1] = &myHstmt->srvHstmt;
   argv[2] = toCorbaString (szSqlStr, cbSqlStr);
   argv[3] = &cbSqlStr;
   argv[4] = &parSeq;

   Exception *ex = Exception_new();
   if (!Invoke_invoke (myHstmt->hdbc->call, ex, "SQLExecDirectParams", 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);
   if (argv[2] != szSqlStr)
      delete (char *) argv[2];
   delete parSeq.data;
   return Return;
}

//  Execute a prepared SQL statement

RETCODE SQL_API SQLExecute(
    HSTMT   hstmt)          // statement to execute.
{

   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);
   if (myHstmt->param.size() > 0)
      Return = executeParams (myHstmt);
   else {

      argv[0] = &Return;
      argv[1] = &myHstmt->srvHstmt;
   
      Exception *ex = Exception_new();
      if (!Invoke_invoke (myHstmt->hdbc->call,ex,"SQLExecute",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;
}

//  -   -   -   -   -   -   -   -   -

//  Performs the equivalent of SQLPrepare, followed by SQLExecute.

RETCODE SQL_API SQLExecDirect(
    HSTMT   hstmt,
    UCHAR FAR *szSqlStr,
    SDWORD  cbSqlStr)
{

   RETCODE Return = SQL_ERROR;
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   void *argv[4];

   if (!myHstmt || !myHstmt->IsA(ClntHstmt::Class))
      return SQL_INVALID_HANDLE;
   else if (notOk (szSqlStr, cbSqlStr)) {
      AddError (0, 0, myHstmt, "S1090", 0, "Invalid string or buffer length");
      return SQL_ERROR;
   }
   DelError (0,0,myHstmt);
   if (myHstmt->param.size() > 0)
      Return = execDirectParams (hstmt, szSqlStr, cbSqlStr);
   else {
      argv[0] = &Return;
      argv[1] = &myHstmt->srvHstmt;
      argv[2] = toCorbaString (szSqlStr, cbSqlStr);
      argv[3] = &cbSqlStr;

      Exception *ex = Exception_new();
      if (!Invoke_invoke (myHstmt->hdbc->call, ex, "SQLExecDirect", 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);
      if (argv[2] != szSqlStr)
         delete (char *) argv[2];
   }
   return Return;
}

//  Returns the SQL string as modified by the driver.
/*
RETCODE SQL_API SQLNativeSql(
    HSTMT   hstmt,
    UCHAR FAR *szSqlStrIn,
    SDWORD  cbSqlStrIn,
    UCHAR FAR *szSqlStr,
    SDWORD  cbSqlStrMax,
    SDWORD FAR *pcbSqlStr)
{
    RETCODE Return = SQL_SUCCESS;
   if (Trace.isSet)
      Trace.Write ( "SQLNative Sql(0x%lx,'%s',%ld,'%s',%ld,%ld)=%d\n",
                      hstmt,
                      szSqlStrIn,cbSqlStrIn,
                      szSqlStr,cbSqlStrMax,*pcbSqlStr,Return);
    return Return;
}
*/
//  -   -   -   -   -   -   -   -   -

//  Supplies parameter data at execution time.  Used in conjuction with
//  SQLPutData.

RETCODE SQL_API SQLParamData(
    HSTMT   hstmt,
    PTR FAR *prgbValue)
{ 
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   Parameter *p;
   CORBA_TCKindDesc *kdesc = 0;
   int i;

   if (!myHstmt || !myHstmt->IsA(ClntHstmt::Class))
      return SQL_INVALID_HANDLE;
   DelError (0,0,myHstmt);
   for (i = 1; p = myHstmt->param.getAt(i); i++)
      if (p->isDataAtExec()) {
         *prgbValue = p->getData();
         break;
      }
   if (p == 0)
      return SQLExecute (hstmt);
   else
      return (RETCODE) SQL_NEED_DATA;
}

//  -   -   -   -   -   -   -   -   -

//  Supplies parameter data at execution time.  Used in conjunction with
//  SQLParamData.

RETCODE SQL_API SQLPutData(
    HSTMT   hstmt,
    PTR rgbValue,
    SDWORD  cbValue)
{   
   RETCODE Return = SQL_SUCCESS;
   ClntHstmt *myHstmt = (ClntHstmt *) hstmt;
   Parameter *p;

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

   DelError(0, 0, myHstmt);

   for (int i = 1; p = myHstmt->param.getAt(i); i++)
      if (p->isDataAtExec()) {
         p->putData ((char *) rgbValue, cbValue);
         break;
      }
/*
   CORBA_Principal rgb;
   void *argv[4];
   if (p) {
      rgb.size = cbValue;
      rgb.data = (unsigned char *) rgbValue;
      argv[0] = &Return;
      argv[1] = &myHstmt->srvHstmt;
      argv[2] = &rgb;
      argv[3] = &cbValue;

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

//  -   -   -   -   -   -   -   -   -

RETCODE SQL_API SQLCancel(
    HSTMT   hstmt)      // Statement to cancel.
{
   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,"SQLCancel",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;
}

//  -   -   -   -   -   -   -   -   -

RETCODE SQL_API SQLTransact(HENV henv, HDBC hdbc, UWORD fType)
{
   RETCODE Return = SQL_SUCCESS;
   ClntHdbc *myHdbc = (ClntHdbc *) hdbc;
   void *argv[4];

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

   argv[0] = &Return;
   argv[1] = &henv;
   argv[2] = &myHdbc->srvHdbc;
   argv[3] = &fType;

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

   return Return;      
}

};
