Logo Search packages:      
Sourcecode: unixodbc version File versions  Download package

options.c

/* Module:          options.c
 *
 * Description:     This module contains routines for getting/setting
 *                  connection and statement options.
 *
 * Classes:         n/a
 *
 * API functions:   SQLSetConnectOption, SQLSetStmtOption, SQLGetConnectOption,
 *                  SQLGetStmtOption
 *
 * Comments:        See "notice.txt" for copyright and license information.
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "psqlodbc.h"

#ifndef WIN32

#ifdef UNIXODBC
#include <sql.h>
#include <sqlext.h>
#else
#include "iodbc.h"
#include "isql.h"
#include "isqlext.h"
#endif

#else
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#endif

#include "environ.h"
#include "connection.h"
#include "statement.h"
#include "qresult.h"


extern GLOBAL_VALUES globals;

RETCODE set_statement_option(ConnectionClass *conn,
                                           StatementClass *stmt,
                                           UWORD   fOption,
                                           UDWORD  vParam);



RETCODE set_statement_option(ConnectionClass *conn,
                                           StatementClass *stmt,
                                           UWORD   fOption,
                                           UDWORD  vParam)
{
static char *func="set_statement_option";
char changed = FALSE;


      switch(fOption) {
      case SQL_ASYNC_ENABLE:/* ignored */
            break;

      case SQL_BIND_TYPE:           
            /* now support multi-column and multi-row binding */
            if (conn) conn->stmtOptions.bind_size = vParam;
            if (stmt) stmt->options.bind_size = vParam;
            break;

      case SQL_CONCURRENCY:
            /*    positioned update isn't supported so cursor concurrency is read-only */

            if (conn) conn->stmtOptions.scroll_concurrency = vParam;
            if (stmt) stmt->options.scroll_concurrency = vParam;
            break;

            /*
            if (globals.lie) {
                  if (conn) conn->stmtOptions.scroll_concurrency = vParam;
                  if (stmt) stmt->options.scroll_concurrency = vParam;
            }
            else {

                  if (conn) conn->stmtOptions.scroll_concurrency = SQL_CONCUR_READ_ONLY;
                  if (stmt) stmt->options.scroll_concurrency = SQL_CONCUR_READ_ONLY;

                  if (vParam != SQL_CONCUR_READ_ONLY)
                        changed = TRUE;
            }
            break;
            */
            
      case SQL_CURSOR_TYPE:
            /*    if declare/fetch, then type can only be forward.
                  otherwise, it can only be forward or static.
            */
            mylog("SetStmtOption(): SQL_CURSOR_TYPE = %d\n", vParam);

            if (globals.lie) {

                  if (conn) conn->stmtOptions.cursor_type = vParam;
                  if (stmt) stmt->options.cursor_type = vParam;

            }
            else {
                  if (globals.use_declarefetch) {

                        if (conn) conn->stmtOptions.cursor_type = SQL_CURSOR_FORWARD_ONLY;
                        if (stmt) stmt->options.cursor_type = SQL_CURSOR_FORWARD_ONLY;

                        if (vParam != SQL_CURSOR_FORWARD_ONLY)
                              changed = TRUE;
                  }
                  else {
                        if (vParam == SQL_CURSOR_FORWARD_ONLY || vParam == SQL_CURSOR_STATIC) {

                              if (conn) conn->stmtOptions.cursor_type = vParam;           /*// valid type */
                              if (stmt) stmt->options.cursor_type = vParam;         /*// valid type */
                        }
                        else {

                              if (conn) conn->stmtOptions.cursor_type = SQL_CURSOR_STATIC;
                              if (stmt) stmt->options.cursor_type = SQL_CURSOR_STATIC;

                              changed = TRUE;
                        }
                  }
            }
            break;

      case SQL_KEYSET_SIZE: /* ignored, but saved and returned  */
            mylog("SetStmtOption(): SQL_KEYSET_SIZE, vParam = %d\n", vParam);

            if (conn) conn->stmtOptions.keyset_size = vParam;
            if (stmt) stmt->options.keyset_size = vParam;

            break;

            /*
            if (globals.lie)
                  stmt->keyset_size = vParam;
            else {
                  stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
                  stmt->errormsg = "Driver does not support keyset size option";
                  SC_log_error(func, "", stmt);
                  return SQL_ERROR;
            }
            */

      case SQL_MAX_LENGTH:/* ignored, but saved */
            mylog("SetStmtOption(): SQL_MAX_LENGTH, vParam = %d\n", vParam);
            if (conn) conn->stmtOptions.maxLength = vParam;
            if (stmt) stmt->options.maxLength = vParam;
            break;

      case SQL_MAX_ROWS: /* ignored, but saved */
            mylog("SetStmtOption(): SQL_MAX_ROWS, vParam = %d\n", vParam);
            if (conn) conn->stmtOptions.maxRows = vParam;
            if (stmt) stmt->options.maxRows = vParam;
            break;

      case SQL_NOSCAN: /* ignored */
            mylog("SetStmtOption: SQL_NOSCAN, vParam = %d\n", vParam);
            break;

      case SQL_QUERY_TIMEOUT: /* ignored */
            mylog("SetStmtOption: SQL_QUERY_TIMEOUT, vParam = %d\n", vParam);
            /*//  "0" returned in SQLGetStmtOption */
            break;

      case SQL_RETRIEVE_DATA: /* ignored, but saved */
            mylog("SetStmtOption(): SQL_RETRIEVE_DATA, vParam = %d\n", vParam);
            if (conn) conn->stmtOptions.retrieve_data = vParam;
            if (stmt) stmt->options.retrieve_data = vParam;
            break;

      case SQL_ROWSET_SIZE:
            mylog("SetStmtOption(): SQL_ROWSET_SIZE, vParam = %d\n", vParam);


            /*    Save old rowset size for SQLExtendedFetch purposes
                  If the rowset_size is being changed since the last call
                  to fetch rows.
            */

            if (stmt && stmt->save_rowset_size <= 0 && stmt->last_fetch_count > 0 )
                  stmt->save_rowset_size = stmt->options.rowset_size;

            if (vParam < 1) {
                  vParam = 1;
                  changed = TRUE;
            }

            if (conn) conn->stmtOptions.rowset_size = vParam;
            if (stmt) stmt->options.rowset_size = vParam;

            break;

      case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */
            if (stmt) {
                  stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
                  stmt->errormsg = "Simulated positioned update/delete not supported.  Use the cursor library.";
                  SC_log_error(func, "", stmt);
            }
            if (conn) {
                  conn->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
                  conn->errormsg = "Simulated positioned update/delete not supported.  Use the cursor library.";
                  CC_log_error(func, "", conn);
            }
            return SQL_ERROR;

      case SQL_USE_BOOKMARKS:

            if (stmt) stmt->options.use_bookmarks = vParam;
            if (conn) conn->stmtOptions.use_bookmarks = vParam;
            break;

    /*
     * added to be nice to OpenOffice
     */

    case /*SQL_ATTR_CURSOR_SENSITIVITY*/ 65534:
        break;

    default:
            {
            char option[64];

            if (stmt) {
                  stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
                  stmt->errormsg = "Unknown statement option (Set)";
                  sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
                  SC_log_error(func, option, stmt);
            }
            if (conn) {
                  conn->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
                  conn->errormsg = "Unknown statement option (Set)";
                  sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
                  CC_log_error(func, option, conn);
            }

        return SQL_ERROR;
            }
    }

      if (changed) {
            if (stmt) {
                  stmt->errormsg = "Requested value changed.";
                  stmt->errornumber = STMT_OPTION_VALUE_CHANGED;
            }
            if (conn) {
                  conn->errormsg = "Requested value changed.";
                  conn->errornumber = STMT_OPTION_VALUE_CHANGED;
            }
            return SQL_SUCCESS_WITH_INFO;
      }
      else
            return SQL_SUCCESS;
}



/* Implements only SQL_AUTOCOMMIT */
RETCODE SQL_API SQLSetConnectOption(
        HDBC    hdbc,
        UWORD   fOption,
        SQLULEN  vParam)
{
static char *func="SQLSetConnectOption";
ConnectionClass *conn = (ConnectionClass *) hdbc;
char changed = FALSE;
RETCODE retval;
int i;

      mylog("%s: entering...\n", func);

      if ( ! conn)  {
            CC_log_error(func, "", NULL);
            return SQL_INVALID_HANDLE;
      }


      switch (fOption) {
      /* Statement Options --
         (apply to all stmts on the connection and become defaults for new stmts)
      */
      case SQL_ASYNC_ENABLE:
      case SQL_BIND_TYPE:           
      case SQL_CONCURRENCY:
      case SQL_CURSOR_TYPE:
      case SQL_KEYSET_SIZE:
      case SQL_MAX_LENGTH:
      case SQL_MAX_ROWS:
      case SQL_NOSCAN:
      case SQL_QUERY_TIMEOUT:
      case SQL_RETRIEVE_DATA:
      case SQL_ROWSET_SIZE:
      case SQL_SIMULATE_CURSOR:
      case SQL_USE_BOOKMARKS:

            /*    Affect all current Statements */
            for (i = 0; i < conn->num_stmts; i++) {
                  if ( conn->stmts[i]) {
                        set_statement_option(NULL, conn->stmts[i], fOption, vParam);
                  }
            }

            /*    Become the default for all future statements on this connection */
            retval = set_statement_option(conn, NULL, fOption, vParam);

            if (retval == SQL_SUCCESS_WITH_INFO)
                  changed = TRUE;
            else if (retval == SQL_ERROR)
                  return SQL_ERROR;

            break;

      /**********************************/
      /*****      Connection Options  *******/  
      /**********************************/

      case SQL_ACCESS_MODE: /* ignored */
            break;

      case SQL_AUTOCOMMIT:

            /*  Since we are almost always in a transaction, this is now ok.
                  Even if we were, the logic will handle it by sending a commit
                  after the statement.
            
            if (CC_is_in_trans(conn)) {
                  conn->errormsg = "Cannot switch commit mode while a transaction is in progres";
                  conn->errornumber = CONN_TRANSACT_IN_PROGRES;
                  CC_log_error(func, "", conn);
                  return SQL_ERROR;
            }
            */

            mylog("SQLSetConnectOption: AUTOCOMMIT: transact_status=%d, vparam=%d\n", conn->transact_status, vParam);

            switch(vParam) {
            case SQL_AUTOCOMMIT_OFF:
                  CC_set_autocommit_off(conn);
                  break;

            case SQL_AUTOCOMMIT_ON:
                  CC_set_autocommit_on(conn);
                  break;

            default:
                  conn->errormsg = "Illegal parameter value for SQL_AUTOCOMMIT";
                  conn->errornumber = CONN_INVALID_ARGUMENT_NO;
                  CC_log_error(func, "", conn);
                  return SQL_ERROR;
            }

            break;

      case SQL_CURRENT_QUALIFIER: /* ignored */
            break;

      case SQL_LOGIN_TIMEOUT: /* ignored */
            break;

      case SQL_PACKET_SIZE:   /* ignored */
            break;

      case SQL_QUIET_MODE:    /* ignored */
            break;

      case SQL_TXN_ISOLATION: /* ignored */
            break;
            
      /*    These options should be handled by driver manager */
      case SQL_ODBC_CURSORS:
      case SQL_OPT_TRACE:
      case SQL_OPT_TRACEFILE:
      case SQL_TRANSLATE_DLL:
      case SQL_TRANSLATE_OPTION:
            CC_log_error(func, "This connect option (Set) is only used by the Driver Manager", conn);
            break;

      default:
            {
            char option[64];
            conn->errormsg = "Unknown connect option (Set)";
            conn->errornumber = CONN_UNSUPPORTED_OPTION;
            sprintf(option, "fOption=%d, vParam=%ld", fOption, vParam);
            CC_log_error(func, option, conn);
            return SQL_ERROR;
            }

      }

      if (changed) {
            conn->errornumber = CONN_OPTION_VALUE_CHANGED;
            conn->errormsg = "Requested value changed.";
            return SQL_SUCCESS_WITH_INFO;
      }
      else
            return SQL_SUCCESS;
}

/*//      -       -       -       -       -       -       -       -       - */

/* This function just can tell you whether you are in Autcommit mode or not */
RETCODE SQL_API SQLGetConnectOption(
        HDBC    hdbc,
        UWORD   fOption,
        PTR     pvParam)
{
static char *func="SQLGetConnectOption";
ConnectionClass *conn = (ConnectionClass *) hdbc;

      mylog("%s: entering...\n", func);

      if (! conn)  {
            CC_log_error(func, "", NULL);
            return SQL_INVALID_HANDLE;
      }

      switch (fOption) {
      case SQL_ACCESS_MODE:/* NOT SUPPORTED */
            *((UDWORD *) pvParam) = SQL_MODE_READ_WRITE;
            break;

      case SQL_AUTOCOMMIT:
            *((UDWORD *)pvParam) = (UDWORD)( CC_is_in_autocommit(conn) ?
                                    SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
            break;

      case SQL_CURRENT_QUALIFIER:   /* don't use qualifiers */
            if(pvParam)
                  strcpy(pvParam, "");

            break;

      case SQL_LOGIN_TIMEOUT: /* NOT SUPPORTED */
            *((UDWORD *) pvParam) = 0;
            break;

      case SQL_PACKET_SIZE: /* NOT SUPPORTED */
            *((UDWORD *) pvParam) = globals.socket_buffersize;
            break;

      case SQL_QUIET_MODE:/* NOT SUPPORTED */
            *((UDWORD *) pvParam) = (UDWORD) NULL;
            break;

      case SQL_TXN_ISOLATION:/* NOT SUPPORTED */
            *((UDWORD *) pvParam) = SQL_TXN_SERIALIZABLE;
            break;

      /*    These options should be handled by driver manager */
      case SQL_ODBC_CURSORS:
      case SQL_OPT_TRACE:
      case SQL_OPT_TRACEFILE:
      case SQL_TRANSLATE_DLL:
      case SQL_TRANSLATE_OPTION:
            CC_log_error(func, "This connect option (Get) is only used by the Driver Manager", conn);
            break;

      default:
            {
            char option[64];
            conn->errormsg = "Unknown connect option (Get)";
            conn->errornumber = CONN_UNSUPPORTED_OPTION;
            sprintf(option, "fOption=%d", fOption);
            CC_log_error(func, option, conn);
            return SQL_ERROR;
            break;
            }

      }

      return SQL_SUCCESS;
}

/*//      -       -       -       -       -       -       -       -       - */

RETCODE SQL_API SQLSetStmtOption(
        HSTMT   hstmt,
        UWORD   fOption,
        SQLULEN  vParam)
{
static char *func="SQLSetStmtOption";
StatementClass *stmt = (StatementClass *) hstmt;
char changed = FALSE;

      mylog("%s: entering...\n", func);

    /*// thought we could fake Access out by just returning SQL_SUCCESS */
    /*// all the time, but it tries to set a huge value for SQL_MAX_LENGTH */
    /*// and expects the driver to reduce it to the real value */

      if( ! stmt) {
            SC_log_error(func, "", NULL);
            return SQL_INVALID_HANDLE;
      }

      return set_statement_option(NULL, stmt, fOption, vParam);
}


/*//      -       -       -       -       -       -       -       -       - */

RETCODE SQL_API SQLGetStmtOption(
        HSTMT   hstmt,
        UWORD   fOption,
        PTR     pvParam)
{
static char *func="SQLGetStmtOption";
StatementClass *stmt = (StatementClass *) hstmt;
QResultClass *res;

      mylog("%s: entering...\n", func);

    /*// thought we could fake Access out by just returning SQL_SUCCESS */
    /*// all the time, but it tries to set a huge value for SQL_MAX_LENGTH */
    /*// and expects the driver to reduce it to the real value */

      if( ! stmt) {
            SC_log_error(func, "", NULL);
            return SQL_INVALID_HANDLE;
      }

      switch(fOption) {
      case SQL_GET_BOOKMARK:
      case SQL_ROW_NUMBER:

            res = stmt->result;

            if ( stmt->manual_result || ! globals.use_declarefetch) {
                  /*// make sure we're positioned on a valid row */
                  if((stmt->currTuple < 0) ||
                     (stmt->currTuple >= QR_get_num_tuples(res))) {
                        stmt->errormsg = "Not positioned on a valid row.";
                        stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
                        SC_log_error(func, "", stmt);
                        return SQL_ERROR;
                  }
            }
            else {
                  if (stmt->currTuple == -1 || ! res || ! res->tupleField) {
                        stmt->errormsg = "Not positioned on a valid row.";
                        stmt->errornumber = STMT_INVALID_CURSOR_STATE_ERROR;
                        SC_log_error(func, "", stmt);
                        return SQL_ERROR;
                  }
            }

            if (fOption == SQL_GET_BOOKMARK && stmt->options.use_bookmarks == SQL_UB_OFF) {
                  stmt->errormsg = "Operation invalid because use bookmarks not enabled.";
                  stmt->errornumber = STMT_OPERATION_INVALID;
                  SC_log_error(func, "", stmt);
                  return SQL_ERROR;
            }

            *((UDWORD *) pvParam) = SC_get_bookmark(stmt);
            
            break;

      case SQL_ASYNC_ENABLE:  /* NOT SUPPORTED */
            *((SDWORD *) pvParam) = SQL_ASYNC_ENABLE_OFF;
            break;

      case SQL_BIND_TYPE:
            *((SDWORD *) pvParam) = stmt->options.bind_size;
            break;

      case SQL_CONCURRENCY: /* NOT REALLY SUPPORTED */
            mylog("GetStmtOption(): SQL_CONCURRENCY\n");
            *((SDWORD *)pvParam) = stmt->options.scroll_concurrency;
            break;

      case SQL_CURSOR_TYPE: /* PARTIAL SUPPORT */
            mylog("GetStmtOption(): SQL_CURSOR_TYPE\n");
            *((SDWORD *)pvParam) = stmt->options.cursor_type;
            break;

      case SQL_KEYSET_SIZE: /* NOT SUPPORTED, but saved */
            mylog("GetStmtOption(): SQL_KEYSET_SIZE\n");
            *((SDWORD *)pvParam) = stmt->options.keyset_size;
            break;

      case SQL_MAX_LENGTH: /* NOT SUPPORTED, but saved */
            *((SDWORD *)pvParam) = stmt->options.maxLength;
            break;

      case SQL_MAX_ROWS: /* NOT SUPPORTED, but saved */
            *((SDWORD *)pvParam) = stmt->options.maxRows;
            mylog("GetSmtOption: MAX_ROWS, returning %d\n", stmt->options.maxRows);
            break;

      case SQL_NOSCAN:/* NOT SUPPORTED */
            *((SDWORD *) pvParam) = SQL_NOSCAN_ON;
            break;

      case SQL_QUERY_TIMEOUT: /* NOT SUPPORTED */
            *((SDWORD *) pvParam) = 0;
            break;

      case SQL_RETRIEVE_DATA: /* NOT SUPPORTED, but saved */
            *((SDWORD *) pvParam) = stmt->options.retrieve_data;
            break;

      case SQL_ROWSET_SIZE:
            *((SDWORD *) pvParam) = stmt->options.rowset_size;
            break;

      case SQL_SIMULATE_CURSOR:/* NOT SUPPORTED */
            *((SDWORD *) pvParam) = SQL_SC_NON_UNIQUE;
            break;

      case SQL_USE_BOOKMARKS:
            *((SDWORD *) pvParam) = stmt->options.use_bookmarks;
            break;

    /*
     * added to be nice to StarOffice and OpenOffice
     */

    case /*SQL_ATTR_CURSOR_SENSITIVITY*/ 65534:
            *((SDWORD *) pvParam) = /*SQL_UNSPECIFIED*/ 0;
        break;

      default:
            {
            char option[64];
            stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
            stmt->errormsg = "Unknown statement option (Get)";
            sprintf(option, "fOption=%d", fOption);
            SC_log_error(func, option, stmt);
            return SQL_ERROR;
            }
      }

      return SQL_SUCCESS;
}

/*//      -       -       -       -       -       -       -       -       - */

Generated by  Doxygen 1.6.0   Back to index