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

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

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

 This program 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
static char rcsid[] = "$Id: prepare.cpp 5.0 1999/10/08 10:17:43 picoSoft Exp Marco $";
# include "database.h"
# include "sqlpars.h"
# include "trace.h"
# include "sqltype.h"
# ifdef MSDOS
# define strlen lstrlen
# define strncpy lstrcpyn
# endif
extern "C" {
//  Allocate a SQL statement

RETCODE SQL_API SQLAllocStmt(
    HDBC       hdbc,
    HSTMT FAR *phstmt)
{
   RETCODE Return = SQL_SUCCESS;
   if (hdbc == 0 ||
       !((PObject *) hdbc)->IsA (DataBase::Class))
      Return = SQL_INVALID_HANDLE;
   else
      *phstmt = (SqlParser *) new SqlParser(((DataBase *) hdbc));

   if (Trace.isSet)
      Trace.Write ("SQLAllocStmt(0x%lx,0x%lx)=%d\n",
                  hdbc,*phstmt,Return);
   return Return;
}

RETCODE SQL_API SQLFreeStmt(
    HSTMT   hstmt,
        UWORD   fOption)
{
   RETCODE Return = SQL_SUCCESS;

   if (hstmt == 0 ||
       !((PObject *) hstmt)->IsA (SqlParser::Class))
      Return = SQL_INVALID_HANDLE;
   else {
      ((SqlParser *) hstmt)->DelError();
      switch (fOption) {
      case SQL_CLOSE:
         ((SqlParser *) (hstmt))->ClearExec();
         break;
      case SQL_DROP:
         delete (SqlParser *) (hstmt);
         break;
      case SQL_UNBIND:
         ((SqlParser *) (hstmt))->Unbind ();
         break;
      case SQL_RESET_PARAMS:
         ((SqlParser *) (hstmt))->ResetParams ();
         break;
      default:
         PrintError (0, 0, (SqlParser *) (hstmt), E_GENERAL_ERROR_092, "");
         Return = SQL_ERROR;
         break;
      }
   }
   if (Trace.isSet)
      Trace.Write ("SQLFreeStmt(0x%lx,%d)=%d\n",
                  hstmt,fOption,Return);
   return Return;
}

//  Perform a Prepare on the SQL statement

RETCODE SQL_API SQLPrepare(
    HSTMT      hstmt,
    UCHAR FAR *szSqlStr,
    SDWORD     cbSqlStr)
{
   RETCODE Return = SQL_SUCCESS;
   if (hstmt == 0 ||
       !((PObject *) hstmt)->IsA (SqlParser::Class))
      Return = SQL_INVALID_HANDLE;
   else {
      if (cbSqlStr < 0 && cbSqlStr != SQL_NTS) {
         PrintError (0, 0, (SqlParser *) (hstmt), E_GENERAL_ERROR_090, "");
         Return = SQL_ERROR;
      } else {
         ((SqlParser *) hstmt)->DelError();
         Return = ((SqlParser *) hstmt)->Parse ((char *)szSqlStr,
                                                cbSqlStr);
      }
   }
   if (Trace.isSet) {
      Trace.Write ("SQLPrepare(0x%lx,'", hstmt );
      Trace.WriteNoFmt ((char *)szSqlStr);
      Trace.Write ("',%ld)=%d\n", cbSqlStr, Return); 
   }
   return Return;
}

//  Return the cursor name for a statement handle

RETCODE SQL_API SQLGetCursorName(
    HSTMT      hstmt,
    UCHAR FAR *szCursor,
    SWORD      cbCursorMax,
    SWORD FAR *pcbCursor)
{
   RETCODE Return = SQL_SUCCESS;
   PString cursorName;

   if (hstmt == 0 ||
       !((PObject *) hstmt)->IsA (SqlParser::Class))
      Return = SQL_INVALID_HANDLE;
   else {
      ((SqlParser *) hstmt)->DelError();
      cursorName = ((SqlParser *) hstmt)->getCursorName ();
   }
   if (Return == SQL_SUCCESS && cursorName.size() > 0) {
      if (cursorName.size() < cbCursorMax) {
         *pcbCursor = (SWORD) cursorName.size();
         strcpy(((char*)szCursor), cursorName.gets());
      } else {
         *pcbCursor = cbCursorMax - 1;
         strncpy(((char*)szCursor), cursorName.gets(), cbCursorMax);
         ((char*)szCursor)[cbCursorMax] = 0;
         PrintError ( 0, 0, (SqlParser *) hstmt, E_WARNING_004, "");
         Return = SQL_SUCCESS_WITH_INFO;
      }
   }
   if (Trace.isSet)
      Trace.Write ("SQLGetCursorName(0x%lx,'%s',%d,%d)=%d\n",
                  hstmt, szCursor,cbCursorMax,*pcbCursor,Return); 
   return Return;
}

//  Set the cursor name on a statement handle

RETCODE SQL_API SQLSetCursorName(
    HSTMT       hstmt,
    UCHAR FAR  *szCursor,
    SWORD       cbCursor)
{
   RETCODE Return = SQL_SUCCESS;
   if (hstmt == 0 ||
       !((PObject *) hstmt)->IsA (SqlParser::Class))
      Return = SQL_INVALID_HANDLE;
   else {
      if (cbCursor < 0 && cbCursor != SQL_NTS) {
         PrintError (0, 0, (SqlParser *) (hstmt), E_GENERAL_ERROR_090, "");
         Return = SQL_ERROR;
      } else {
         ((SqlParser *) hstmt)->DelError();
         ((SqlParser *) hstmt)->setCursorName ((char *)szCursor, cbCursor);
      }
   }
   if (Trace.isSet)
      Trace.Write ("SQLSetCursorName(0x%lx,'%s',%d)=%d\n",
                  hstmt, szCursor,cbCursor,Return);
   return Return;
}

//  Set parameters on a statement handle

RETCODE SQL_API SQLBindParameter(
    HSTMT       hstmt,
    UWORD       ipar,
    SWORD       fParamType,
    SWORD       fCType,
    SWORD       fSqlType,
    UDWORD      cbColDef,
    SWORD       ibScale,
    PTR         rgbValue,
    SDWORD      cbValueMax,
    SDWORD FAR *pcbValue)
{
   RETCODE Return = SQL_SUCCESS;
 
   if (cbValueMax == SQL_SETPARAM_VALUE_MAX ||
       cbValueMax == 0) // not documented Access behaviour
      cbValueMax = cbColDef;

   if (hstmt == 0 ||
       !((PObject *) hstmt)->IsA (SqlParser::Class))
      Return = SQL_INVALID_HANDLE;
   else {
      ((SqlParser *) hstmt)->DelError();
      if (fCType == SQL_C_DEFAULT) 
         switch (fSqlType) {
         case SQL_CHAR:
         case SQL_VARCHAR:
         case SQL_LONGVARCHAR:
            fCType = SQL_C_CHAR;
            break;
         case SQL_BINARY:
         case SQL_VARBINARY:
         case SQL_LONGVARBINARY:
            fCType = SQL_C_BINARY;
            break;
         case SQL_NUMERIC:
         case SQL_DECIMAL:
            fCType = SQL_C_CHAR;
            break;
         case SQL_REAL:
            fCType = SQL_C_FLOAT;
            break;
         case SQL_FLOAT:
         case SQL_DOUBLE:
            fCType = SQL_C_DOUBLE;
            break;
         case SQL_INTEGER:
            fCType = SQL_C_LONG;
            break;
         case SQL_SMALLINT:
            fCType = SQL_C_SHORT;
            break;
         case SQL_TIMESTAMP:
            fCType = SQL_C_TIMESTAMP;
            break;
         default:
            PrintError (0, 0, (SqlParser *)hstmt, E_GENERAL_ERROR_C00, "");
            return Return = SQL_ERROR;
            break;
         }
      Return = ((SqlParser *) hstmt)->SetParam (ipar, (AttrCType) fCType,
                                                fSqlType, cbValueMax,
                                                (char *)rgbValue, pcbValue);
   }
   if (Trace.isSet)
      if (pcbValue)
         Trace.Write ("SQLBindParameter(0x%lx,%d,%d,%d,%ld,%d,'...',%ld,%ld)=%d\n",
                       hstmt,ipar,fCType,fSqlType,cbColDef,ibScale,
                       /* rgbValue,*/ cbValueMax, *pcbValue, Return);
      else
         Trace.Write ("SQLBindParam(0x%lx,%d,%d,%d,%ld,%d,'...',%ld,(null))=%d\n",
                       hstmt,ipar,fCType,fSqlType,cbColDef,ibScale,
                       /* rgbValue,*/ cbValueMax,/**pcbValue,*/Return); 
   return Return;
}

//  Returns the number of parameter markers.

RETCODE SQL_API SQLNumParams(
    HSTMT   hstmt,
    SWORD FAR *pcpar)
{
   RETCODE Return = SQL_SUCCESS;

   if (hstmt == 0 || !((PObject *) hstmt)->IsA (SqlParser::Class))
      Return = SQL_INVALID_HANDLE;
   else
      Return = ((SqlParser *) hstmt)->GetNumParams(*pcpar);
   if (Trace.isSet)
      if (pcpar)
         Trace.Write ("SQLNumParams(0x%lx,%d)=%d\n", *pcpar, hstmt, Return);
      else
         Trace.Write ("SQLNumParams(0x%lx,NULL)=%d\n", hstmt, Return);
    return Return;
}

//  Returns the description of a parameter marker.

RETCODE SQL_API SQLDescribeParam(
    HSTMT   hstmt,
    UWORD   ipar,
    SWORD FAR *pfSqlType,
    UDWORD FAR *pcbColDef,
    SWORD FAR *pibScale,
    SWORD FAR *pfNullable)
{    
   
   RETCODE Return = SQL_SUCCESS;

   if (hstmt == 0 || !((PObject *) hstmt)->IsA (SqlParser::Class))
      Return = SQL_INVALID_HANDLE;
   else
      Return = ((SqlParser *) hstmt)->DescribeParam(ipar, pfSqlType, pcbColDef,
                                                    pibScale, pfNullable);
   if (Trace.isSet)
      Trace.Write ("SQLDescribeParam (0x%lx,%d,%d,%d,%d)=%d\n",
                                      hstmt, *pfSqlType, *pcbColDef,
                                      *pibScale, *pfNullable, Return);
   return Return;
}
/*
//  Sets multiple values (arrays) for the set of parameter markers.

RETCODE SQL_API SQLParamOptions(
    HSTMT   hstmt,
    UDWORD  crow,
    UDWORD FAR *pirow)
{
       
   if (Trace.isSet)
      Trace.Write ("SQLParamOptions\n"); 
    return SQL_SUCCESS;
}

//  -   -   -   -   -   -   -   -   -

//  Sets options that control the behavior of cursors.

RETCODE SQL_API SQLSetScrollOptions(
    HSTMT   hstmt,
    UWORD   fConcurrency,
    SDWORD  crowKeyset,
    UWORD   crowRowset)
{
       
   if (Trace.isSet)
      Trace.Write ("SQLSetScrollOptions\n");
    return SQL_SUCCESS;
}
*/
};
