in driver/handles.c [589:918]
SQLRETURN EsSQLSetStmtAttrW(
SQLHSTMT StatementHandle,
SQLINTEGER Attribute,
SQLPOINTER ValuePtr,
SQLINTEGER BufferLength)
{
SQLRETURN ret;
SQLULEN ulen;
esodbc_desc_st *desc;
esodbc_stmt_st *stmt = STMH(StatementHandle);
/*INDENT-OFF*/
switch(Attribute) {
case SQL_ATTR_USE_BOOKMARKS:
DBGH(stmt, "setting use-bookmarks to: %llu.", (uint64_t)ValuePtr);
if ((SQLULEN)ValuePtr != SQL_UB_OFF) {
ERRH(stmt, "bookmarks are not supported by driver.");
RET_HDIAG(stmt, SQL_STATE_HYC00,
"bookmarks are not supported by driver", 0);
}
break;
do {
/* "If this field is non-null, the driver dereferences the pointer,
* adds the dereferenced value to each of the deferred fields in the
* descriptor record (SQL_DESC_DATA_PTR, SQL_DESC_INDICATOR_PTR, and
* SQL_DESC_OCTET_LENGTH_PTR), and uses the new pointer values when
* binding. It is set to null by default." */
case SQL_ATTR_ROW_BIND_OFFSET_PTR:
/* offset in bytes */
/* "Setting this statement attribute sets the
* SQL_DESC_BIND_OFFSET_PTR field in the ARD header." */
DBGH(stmt, "setting row-bind-offset pointer to: 0x%p.", ValuePtr);
desc = stmt->ard;
break;
case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
DBGH(stmt, "setting param-bind-offset pointer to: 0x%p.", ValuePtr);
desc = stmt->apd;
break;
} while (0);
ret = EsSQLSetDescFieldW(desc, NO_REC_NR, SQL_DESC_BIND_OFFSET_PTR,
ValuePtr, BufferLength);
if (ret != SQL_SUCCESS) { /* _WITH_INFO wud be "error" here */
/* if SetDescField() fails, DM will check statement's diag */
HDIAG_COPY(desc, stmt);
}
return ret;
do {
/* "Setting this statement attribute sets the SQL_DESC_ARRAY_SIZE
* field in the ARD header." */
case SQL_ATTR_ROW_ARRAY_SIZE:
DBGH(stmt, "setting row array size to: %d.", (SQLULEN)ValuePtr);
desc = stmt->ard;
break;
/* "Setting this statement attribute sets the SQL_DESC_ARRAY_SIZE
* field in the APD header." */
case SQL_ATTR_PARAMSET_SIZE:
DBGH(stmt, "setting param set size to: %d.", (SQLULEN)ValuePtr);
desc = stmt->apd;
break;
} while (0);
ret = EsSQLSetDescFieldW(desc, NO_REC_NR, SQL_DESC_ARRAY_SIZE,
ValuePtr, BufferLength);
if (ret != SQL_SUCCESS) { /* _WITH_INFO wud be "error" here */
/* if SetDescField() fails, DM will check statement's diag */
HDIAG_COPY(desc, stmt);
}
return ret;
do {
/* "sets the binding orientation to be used when SQLFetch or
* SQLFetchScroll is called on the associated statement" */
/* "Setting this statement attribute sets the SQL_DESC_BIND_TYPE field
* in the ARD header." */
case SQL_ATTR_ROW_BIND_TYPE:
DBGH(stmt, "setting row bind type to: %d.", (SQLULEN)ValuePtr);
/* value is SQL_BIND_BY_COLUMN (0UL) or struct len */
/* "the driver can calculate the address of the data for a
* particular row and column as:
* Address = Bound Address + ((Row Number - 1) * Structure Size)"
* https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/column-wise-binding
* https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/row-wise-binding
*/
desc = stmt->ard;
break;
case SQL_ATTR_PARAM_BIND_TYPE:
DBGH(stmt, "setting param bind type to: %d.", (SQLULEN)ValuePtr);
desc = stmt->apd;
break;
} while (0);
ret = EsSQLSetDescFieldW(desc, NO_REC_NR, SQL_DESC_BIND_TYPE,
/* note: SetStmt()'s spec defineds the ValuePtr as
* SQLULEN, but SetDescField()'s as SQLUINTEGER.. */
ValuePtr, BufferLength);
if (ret != SQL_SUCCESS) { /* _WITH_INFO wud be "error" here */
/* if SetDescField() fails, DM will check statement's diag */
HDIAG_COPY(desc, stmt);
}
return ret;
do {
/* "an array of SQLUSMALLINT values containing row status values after
* a call to SQLFetch or SQLFetchScroll." */
/* https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/row-status-array */
/* "Setting this statement attribute sets the
* SQL_DESC_ARRAY_STATUS_PTR field in the IRD header." */
case SQL_ATTR_ROW_STATUS_PTR:
// TODO: call SQLSetDescField(IRD) here?
DBGH(stmt, "setting row status pointer to: 0x%p.", ValuePtr);
desc = stmt->ird;
break;
case SQL_ATTR_PARAM_STATUS_PTR:
DBGH(stmt, "setting param status pointer to: 0x%p.", ValuePtr);
desc = stmt->ipd;
break;
case SQL_ATTR_ROW_OPERATION_PTR:
DBGH(stmt, "setting row operation array pointer to: 0x%p.",
ValuePtr);
desc = stmt->ard;
break;
case SQL_ATTR_PARAM_OPERATION_PTR:
DBGH(stmt, "setting param operation array pointer to: 0x%p.",
ValuePtr);
desc = stmt->apd;
break;
} while (0);
ret = EsSQLSetDescFieldW(desc, NO_REC_NR,
SQL_DESC_ARRAY_STATUS_PTR, ValuePtr, BufferLength);
if (ret != SQL_SUCCESS) { /* _WITH_INFO wud be "error" here */
/* if SetDescField() fails, DM will check statement's diag */
HDIAG_COPY(desc, stmt);
}
return ret;
do {
/* "Setting this statement attribute sets the
* SQL_DESC_ROWS_PROCESSED_PTR field in the IRD header." */
case SQL_ATTR_ROWS_FETCHED_PTR:
DBGH(stmt, "setting rows fetched pointer to: 0x%p.", ValuePtr);
/* NOTE: documentation writes about "ARD", while also stating that
* this field is unused in the ARD. I assume the former as wrong */
desc = stmt->ird;
break;
case SQL_ATTR_PARAMS_PROCESSED_PTR:
DBGH(stmt, "setting params processed pointer to: 0x%p.", ValuePtr);
desc = stmt->ipd;
break;
} while (0);
ret = EsSQLSetDescFieldW(desc, NO_REC_NR,
SQL_DESC_ROWS_PROCESSED_PTR, ValuePtr, BufferLength);
if (ret != SQL_SUCCESS) { /* _WITH_INFO wud be "error" here */
/* if SetDescField() fails, DM will check statement's diag */
HDIAG_COPY(desc, stmt);
}
return ret;
case SQL_ATTR_APP_ROW_DESC:
desc = DSCH(ValuePtr);
if (desc == stmt->ard) {
WARNH(stmt, "trying to overwrite ARD with same value (@0x%p).",
ValuePtr);
break; /* nop */
}
if (desc == &stmt->i_ard || desc == SQL_NULL_HDESC) {
DBGH(stmt, "unbinding current ARD (@0x%p), rebinding with "
"implicit value (@0x%p).", stmt->ard, &stmt->i_ard);
/* re-anonymize the descriptor, makingit re-usable */
stmt->ard = &stmt->i_ard;
} else {
/* "This attribute cannot be set to a descriptor handle that
* was implicitly allocated for another statement or to
* another descriptor handle that was implicitly set on the
* same statement; implicitly allocated descriptor handles
* cannot be associated with more than one statement or
* descriptor handle." */
if (desc->alloc_type == SQL_DESC_ALLOC_AUTO) {
ERRH(stmt, "source ARD (@0x%p) is implicit (alloc: %d).",
desc, desc->alloc_type);
RET_HDIAGS(stmt, SQL_STATE_HY017);
} else {
switch (desc->type) {
case DESC_TYPE_ANON:
desc->type = DESC_TYPE_ARD;
case DESC_TYPE_ARD:
break;
default:
// TODO: should this be allowed?
/* this means a descriptor can not be changed from
* APD to ARD (IxD is also ruled out) */
ERRH(stmt, "can't convert descriptor from type %d"
" to ARD.", desc->type);
RET_HDIAGS(stmt, SQL_STATE_HY024);
}
DBGH(stmt, "overwritting current ARD (@0x%p) with new "
"value (@0x%p).", stmt->ard, desc);
stmt->ard = desc;
}
}
break;
case SQL_ATTR_APP_PARAM_DESC:
// FIXME: same logic for ARD as above (part of params passing)
FIXME;
break;
case SQL_ATTR_IMP_ROW_DESC:
case SQL_ATTR_IMP_PARAM_DESC:
ERRH(stmt, "trying to set IxD (%d) descriptor (to @0x%p).",
Attribute, ValuePtr);
RET_HDIAGS(stmt, SQL_STATE_HY017);
case SQL_ATTR_ROW_NUMBER:
ERRH(stmt, "row number attribute is read-only.");
RET_HDIAGS(stmt, SQL_STATE_HY024);
case SQL_ATTR_METADATA_ID:
DBGH(stmt, "setting metadata_id to: %llu", (uint64_t)ValuePtr);
stmt->metadata_id = (SQLULEN)ValuePtr;
break;
case SQL_ATTR_ASYNC_ENABLE:
ERRH(stmt, "no support for async API (setting param: %llu)",
(uint64_t)ValuePtr);
if ((SQLULEN)ValuePtr == SQL_ASYNC_ENABLE_ON) {
RET_HDIAGS(stmt, SQL_STATE_HYC00);
}
break;
case SQL_ATTR_ASYNC_STMT_EVENT:
// case SQL_ATTR_ASYNC_STMT_PCALLBACK:
// case SQL_ATTR_ASYNC_STMT_PCONTEXT:
ERRH(stmt, "no support for async API (attr: %ld)", Attribute);
RET_HDIAGS(stmt, SQL_STATE_S1118);
case SQL_ATTR_MAX_LENGTH:
ulen = (SQLULEN)ValuePtr;
DBGH(stmt, "setting max_length to: %llu.", (uint64_t)ulen);
if (ulen < ESODBC_LO_MAX_LENGTH) {
WARNH(stmt, "MAX_LENGTH lower than min allowed (%d) -- "
"correcting value.", ESODBC_LO_MAX_LENGTH);
ulen = ESODBC_LO_MAX_LENGTH;
} else if (ESODBC_UP_MAX_LENGTH && ESODBC_UP_MAX_LENGTH < ulen) {
WARNH(stmt, "MAX_LENGTH higher than max allowed (%d) -- "
"correcting value", ESODBC_UP_MAX_LENGTH);
ulen = ESODBC_UP_MAX_LENGTH;
}
stmt->max_length = ulen;
if (ulen != (SQLULEN)ValuePtr)
RET_HDIAGS(stmt, SQL_STATE_01S02);
break;
case SQL_ATTR_QUERY_TIMEOUT:
DBGH(stmt, "setting query timeout to: %llu.", (uint64_t)ValuePtr);
stmt->query_timeout = (SQLULEN)ValuePtr;
break;
case SQL_ATTR_CURSOR_TYPE:
DBGH(stmt, "setting cursor type: %llu.", (SQLUBIGINT)ValuePtr);
if ((SQLULEN)ValuePtr != SQL_CURSOR_FORWARD_ONLY) {
WARNH(stmt, "requested cursor_type substituted with "
"forward-only (%lu).", SQL_CURSOR_FORWARD_ONLY);
RET_HDIAGS(stmt, SQL_STATE_01S02);
}
break;
case SQL_ATTR_NOSCAN:
DBGH(stmt, "setting escape seq scanning: %llu -- NOOP.",
(uint64_t)ValuePtr);
/* nothing to do: the driver never scans the input, ESSQL processes
* the escape sequences */
break;
case SQL_ATTR_CONCURRENCY:
DBGH(stmt, "setting concurrency: %llu.", (uint64_t)ValuePtr);
if ((SQLULEN)ValuePtr != SQL_CONCUR_READ_ONLY) {
WARNH(stmt, "requested concurrency substituted with "
"read-only (%d).", SQL_CONCUR_READ_ONLY);
RET_HDIAGS(stmt, SQL_STATE_01S02);
}
break;
case SQL_ATTR_MAX_ROWS:
DBGH(stmt, "setting max rows: %llu.", (uint64_t)ValuePtr);
if ((SQLULEN)ValuePtr != 0) {
WARNH(stmt, "requested max_rows substituted with 0.");
RET_HDIAGS(stmt, SQL_STATE_01S02);
}
break;
case SQL_ATTR_CURSOR_SENSITIVITY:
DBGH(stmt, "setting cursor sensitivity: %llu.",
(uint64_t)ValuePtr);
if ((SQLULEN)ValuePtr != SQL_UNSPECIFIED) {
ERRH(stmt, "driver supports forward-only cursors.");
RET_HDIAGS(stmt, SQL_STATE_HYC00);
}
break;
case SQL_ATTR_CURSOR_SCROLLABLE:
DBGH(stmt, "setting scrollable cursor: %llu.", (uint64_t)ValuePtr);
if ((SQLULEN)ValuePtr != SQL_NONSCROLLABLE) {
ERRH(stmt, "driver supports only non-scrollable cursors.");
RET_HDIAGS(stmt, SQL_STATE_HYC00);
}
break;
case SQL_ATTR_RETRIEVE_DATA:
DBGH(stmt, "setting data retrieving: %llu.", (uint64_t)ValuePtr);
if ((SQLULEN)ValuePtr != SQL_RD_ON) {
WARNH(stmt, "no fetching without data retrieval possible.");
RET_HDIAGS(stmt, SQL_STATE_01S02);
}
break;
/* SQL Server non-standard attributes */
case 1226:
case 1227:
case 1228:
ERRH(stmt, "non-standard attribute: %d.", Attribute);
/* "Invalid attribute/option identifier" */
RET_HDIAGS(stmt, SQL_STATE_HY092);
default:
// FIXME
BUGH(stmt, "unknown Attribute: %d.", Attribute);
RET_HDIAGS(stmt, SQL_STATE_HY092);
}
/*INDENT-ON*/
return SQL_SUCCESS;
}