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;
}