SQLRETURN SQL_API RsOptions::RS_SQLSetConnectAttr()

in src/odbc/rsodbc/rsoptions.cpp [945:1266]


SQLRETURN  SQL_API RsOptions::RS_SQLSetConnectAttr(SQLHDBC phdbc,
                                           SQLINTEGER    iAttribute, 
                                           SQLPOINTER    pValue,
                                           SQLINTEGER    cbLen)
{
    SQLRETURN rc = SQL_SUCCESS;
    RS_CONN_INFO *pConn = (RS_CONN_INFO *)phdbc;
    RS_CONN_ATTR_INFO *pConnAttr;
    RS_CONNECT_PROPS_INFO *pConnectProps;

    int iVal = (int)(long)pValue;

    if(!VALID_HDBC(phdbc))
    {
        rc = SQL_INVALID_HANDLE;
        goto error;
    }

    // Clear error list
    pConn->pErrorList = clearErrorList(pConn->pErrorList);

    pConnAttr = pConn->pConnAttr;
    pConnectProps = pConn->pConnectProps;

    switch(iAttribute)
    {
        case SQL_ATTR_ACCESS_MODE:
        {
            // Check valid values
            if(iVal != SQL_MODE_READ_ONLY && iVal != SQL_MODE_READ_WRITE)
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HY024", "Invalid attribute value", 0, NULL);
                goto error;
            }

            pConnAttr->iAccessMode = iVal;

			if (pConn->iStatus == RS_OPEN_CONNECTION
					&& iVal == SQL_MODE_READ_ONLY)
			{
				// Set readonly mode
				rc = onConnectExecute(pConn, "SET READONLY=1");
			}

            break;
        }

        case SQL_ATTR_ASYNC_ENABLE:
        {
            // Check valid values
            if(iVal != SQL_ASYNC_ENABLE_OFF && iVal != SQL_ASYNC_ENABLE_ON)
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HY024", "Invalid attribute value", 0, NULL);
                goto error;
            }

            pConnAttr->iAsyncEnable = iVal;

            break;
        }

        case SQL_ATTR_AUTOCOMMIT:
        {
            // Check valid values
            if(iVal != SQL_TRUE && iVal != SQL_FALSE)
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HY024", "Invalid attribute value", 0, NULL);
                goto error;
            }

            if(pConn->isConnectionOpen())
            {
                if(!pConnAttr->iAutoCommit && iVal)
                {
                    // Commit the changes
                  RsTransaction::RS_SQLTransact(NULL, phdbc, SQL_COMMIT);
                }
            }

            pConnAttr->iAutoCommit = iVal;

            break;
        }

        case SQL_ATTR_CONNECTION_TIMEOUT:
        {
            // This is for login as well as any execution on the connection.
            // Right now we are using only for login timeout. 
            // When we support actual query timeout, we will use it.
            pConnAttr->iConnectionTimeout = iVal;
			if(pConnAttr->iLoginTimeout == 0)
				pConnAttr->iLoginTimeout = pConnAttr->iConnectionTimeout;

            break;
        }

        case SQL_ATTR_CURRENT_CATALOG:
        {
            if(pValue == NULL)
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HY009", "Invalid use of null pointer", 0, NULL);
                goto error;
            }

            if(pConn->isConnectionOpen())
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HY011", "Attribute cannot be set now", 0, NULL);
                goto error;
            }
            else
            {
                // Free previously allocated buffer, if any.
                pConnAttr->pCurrentCatalog = (char *)rs_free(pConnAttr->pCurrentCatalog);

                // Allocate and copy new value
                pConnAttr->pCurrentCatalog = rs_strdup((char *)pValue, cbLen);
            }

            break;
        }

        case SQL_ATTR_LOGIN_TIMEOUT:
        {
            pConnAttr->iLoginTimeout = iVal;
            break;
        }

        case SQL_ATTR_METADATA_ID:
        {
            if(iVal != SQL_TRUE && iVal != SQL_FALSE)
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HY024", "Invalid attribute value", 0, NULL);
                goto error;
            }

            pConnAttr->iMetaDataId = iVal;

            break;
        }

        case SQL_ATTR_ODBC_CURSORS:
        {
            if(iVal != SQL_CUR_USE_IF_NEEDED 
                && iVal != SQL_CUR_USE_ODBC
                && iVal != SQL_CUR_USE_DRIVER)
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HY024", "Invalid attribute value", 0, NULL);
                goto error;
            }

            pConnAttr->iOdbcCursors = iVal;

            break;
        }

        case SQL_ATTR_PACKET_SIZE:
        {
            if(pConn->isConnectionOpen())
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HY011", "Attribute cannot be set now", 0, NULL);
                goto error;
            }

            pConnAttr->iPacketSize = iVal;
            break;
        }

        case SQL_ATTR_QUIET_MODE:
        {
            pConnAttr->hQuietMode = pValue;
            break;
        }

        case SQL_ATTR_TRACE:
        {
            if(iVal != SQL_OPT_TRACE_OFF && iVal != SQL_OPT_TRACE_ON)
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HY024", "Invalid attribute value", 0, NULL);
                goto error;
            }

            pConnAttr->iTrace = iVal;

            if(pConnAttr->iTrace == SQL_OPT_TRACE_ON)
                pConnectProps->iTraceLevel = LOG_LEVEL_DEBUG;
            else
            if(pConnAttr->iTrace == SQL_OPT_TRACE_OFF)
                pConnectProps->iTraceLevel = LOG_LEVEL_OFF;

            break;
        }

        case SQL_ATTR_TRACEFILE:
        {
            if(pValue == NULL)
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HY009", "Invalid use of null pointer", 0, NULL);
                goto error;
            }

            pConnAttr->pTraceFile = (char *)rs_free(pConnAttr->pTraceFile);
            pConnAttr->pTraceFile = rs_strdup((char *)pValue, cbLen);

            break;
        }

        case SQL_ATTR_TRANSLATE_LIB:
        {
            if(pValue == NULL)
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HY009", "Invalid use of null pointer", 0, NULL);
                goto error;
            }

            pConnAttr->pTranslateLib = (char *)rs_free(pConnAttr->pTranslateLib);
            pConnAttr->pTranslateLib = rs_strdup((char *)pValue, cbLen);

            break;
        }

        case SQL_ATTR_TRANSLATE_OPTION:
        {
            pConnAttr->iTranslateOption = iVal;

            break;
        }

        case SQL_ATTR_TXN_ISOLATION:
        {
            if(pConn->isConnectionOpen())
            {
                // Is connection has active transaction?
                if(!libpqIsTransactionIdle(pConn))
                {
                    rc = SQL_ERROR;
                    addError(&pConn->pErrorList,"HY011", "Attribute cannot be set now", 0, NULL);
                    goto error;
                }

                if(iVal != SQL_TXN_READ_UNCOMMITTED 
                    && iVal != SQL_TXN_READ_COMMITTED 
                    && iVal != SQL_TXN_REPEATABLE_READ
                    && iVal != SQL_TXN_SERIALIZABLE)
                {
                    rc = SQL_ERROR;
                    addError(&pConn->pErrorList,"HY024", "Invalid attribute value", 0, NULL);
                    goto error;
                }

                if(iVal != SQL_TXN_SERIALIZABLE)
                {
                    iVal = SQL_TXN_SERIALIZABLE;
                    rc = SQL_SUCCESS_WITH_INFO;
                    addError(&pConn->pErrorList,"01S02", "Option value changed", 0, NULL);
                }
            } 

            pConnAttr->iTxnIsolation = iVal;

            break;
        }

        case SQL_ATTR_APP_WCHAR_TYPE: // DD DM specific attribute.
        {
            if(iVal == SQL_DD_CP_UTF16)
            {
                // We support WCHAR as UTF-16. So that will be fine.
            }
            else
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HYC00", "Optional feature not implemented::RS_SQLSetConnectAttr-1", 0, NULL);
                goto error;
            }

            break;
        }

        case SQL_ATTR_QUERY_TIMEOUT:
        {
            if(iVal < 0)
            {
                rc = SQL_ERROR;
                addError(&pConn->pErrorList,"HY024", "Invalid attribute value", 0, NULL);
                goto error;
            } 

            pConnectProps->iQueryTimeout = iVal;
            break;
        }

        case SQL_ATTR_ANSI_APP:
        /*
        Since we can handle both unicode as well as ANSI, we'll return SQL_ERROR as per
        https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/unicode-drivers?view=sql-server-ver16
        */
            rc = SQL_ERROR;
            break;
        default:
        {
            rc = SQL_ERROR;
            addError(&pConn->pErrorList,"HYC00", "Optional feature not implemented::RS_SQLSetConnectAttr-2", 0, NULL);
            goto error;
        }

    } // Switch

error:

    return rc;
}