Created
April 15, 2020 19:57
-
-
Save mloskot/207fed21c6ec14bb3a6f817b4bc9b8c6 to your computer and use it in GitHub Desktop.
Conversion with CAST(? AS BIT) only works for 0 or 1 when using ODBC API. 22003: [Microsoft][ODBC Driver 17 for SQL Server]Numeric value out of rang
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// MWE for bug report submitted to SQL Server: | |
// https://feedback.azure.com/forums/908035-sql-server/suggestions/40180918-conversion-with-cast-as-bit-only-works-for-0-or | |
#include <cassert> | |
#include <cstdint> | |
#include <iostream> | |
#include <string> | |
#include <vector> | |
#define NOMINMAX | |
#include <windows.h> | |
#include <sql.h> | |
#include <sqlext.h> | |
int main() | |
{ | |
SQLRETURN rc = 0; | |
SQLHENV henv = SQL_NULL_HENV; | |
rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); | |
assert(rc == SQL_SUCCESS); | |
rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3_80, 0); | |
assert(rc == SQL_SUCCESS); | |
SQLHDBC hdbc = SQL_NULL_HDBC; | |
rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); | |
assert(rc == SQL_SUCCESS); | |
char* cs = "Driver={ODBC Driver 17 for SQL Server};Server=myserver;Database=mydb;UID=myuser;PWD=mypwd;"; | |
rc = SQLDriverConnect(hdbc, nullptr, (SQLCHAR*)cs, SQL_NTS, nullptr, 0, nullptr, SQL_DRIVER_NOPROMPT); | |
assert(rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO); | |
SQLHSTMT hstmt = SQL_NULL_HSTMT; | |
rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt); | |
assert(rc == SQL_SUCCESS); | |
rc = SQLExecDirect(hstmt, (SQLCHAR*)"DROP TABLE IF EXISTS [t_bit]", SQL_NTS); | |
assert(rc == SQL_SUCCESS); | |
rc = SQLExecDirect(hstmt, (SQLCHAR*)"CREATE TABLE [t_bit]([fid] [int] IDENTITY(1,1) NOT NULL,[b] [bit] NULL)", SQL_NTS); | |
assert(rc == SQL_SUCCESS); | |
// NOTE: 22003 failures happen for any negative or positive value other than j0 or 1 | |
// Originally, the issue was discovered for -1 which is raw value of VARIANT_TRUE | |
SQLINTEGER bit_value = -1; | |
// Case 0: SQL State=22003 Error=[Microsoft][ODBC Driver 17 for SQL Server]Numeric value out of range | |
//rc = SQLPrepare(hstmt, (SQLCHAR*)"INSERT INTO [t_bit] ([b]) VALUES (?)", SQL_NTS); | |
// Case 1: SQL State=22003 Error=[Microsoft][ODBC Driver 17 for SQL Server]Numeric value out of range | |
rc = SQLPrepare(hstmt, (SQLCHAR*)"INSERT INTO [t_bit] ([b]) VALUES (CAST(? AS BIT))", SQL_NTS); | |
// Case 2: OK | |
//rc = SQLPrepare(hstmt, (SQLCHAR*)"INSERT INTO [t_bit] ([b]) VALUES (CAST(CAST(? AS INT) AS BIT))", SQL_NTS); | |
// Case 3: OK | |
//rc = SQLPrepare(hstmt, (SQLCHAR*)"INSERT INTO [t_bit] ([b]) VALUES (CAST(ABS(?) AS BIT))", SQL_NTS); | |
assert(rc == SQL_SUCCESS); | |
SQLSMALLINT p_type{0}, p_scale{0}, p_nullable{0}; | |
SQLULEN p_size = 0; | |
rc = SQLDescribeParam(hstmt, 1, &p_type, &p_size, &p_scale, &p_nullable); | |
SQLLEN cb_value = 0; | |
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, p_type, p_size, p_scale, &bit_value, p_size, &cb_value); | |
assert(rc == SQL_SUCCESS); | |
rc = SQLExecute(hstmt); | |
if (rc != SQL_SUCCESS) | |
{ | |
SQLCHAR s[6] = {0}; | |
SQLINTEGER e = 0; | |
SQLSMALLINT b = 0; | |
rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, s, &e, 0, 0,& b); | |
assert(rc == SQL_SUCCESS); | |
std::vector<SQLCHAR> v; v.resize(b > 0 ? b + 1 : 512); | |
rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, s, &e, v.data(), v.size(),& b); | |
assert(rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO); | |
std::string m(v.begin(), v.end()); | |
std::cout << "SQL State=" << s << "\tError=" << m << std::endl; | |
} | |
SQLDisconnect(hdbc); | |
SQLFreeHandle(SQL_HANDLE_DBC, hdbc); | |
SQLFreeHandle(SQL_HANDLE_ENV, henv); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment