BOOL CODBC::WriteScorcoData(char* SQL, BYTE* pData, int Length) { SQLRETURN retcode; SQLINTEGER cbObjectParam; SQLPOINTER pToken; char* pSQL = new char[strlen(SQL)]; sprintf(pSQL, SQL, "?"); SQLFreeStmt(hstmt,SQL_CLOSE); retcode = SQLPrepare(hstmt, (unsigned char *)pSQL, SQL_NTS); if (MYSQLSUCCESS(rc)) { SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0, 0, (SQLPOINTER) 2, 0, &cbObjectParam); cbObjectParam = SQL_LEN_DATA_AT_EXEC(0); retcode = SQLExecute(hstmt); while (retcode == SQL_NEED_DATA) { retcode = SQLParamData(hstmt, &pToken); if (retcode == SQL_NEED_DATA) SQLPutData(hstmt, pData, Length); } return TRUE; } else { SaveSQLError(); return FALSE; } }
static bool GetBufferInfo(Cursor* cur, Py_ssize_t index, PyObject* param, ParamInfo& info) { info.ValueType = SQL_C_BINARY; const char* pb; Py_ssize_t cb = PyBuffer_GetMemory(param, &pb); if (cb != -1 && cb <= cur->cnxn->binary_maxlength) { // There is one segment, so we can bind directly into the buffer object. info.ParameterType = SQL_VARBINARY; info.ParameterValuePtr = (SQLPOINTER)pb; info.BufferLength = cb; info.ColumnSize = (SQLUINTEGER)max(cb, 1); info.StrLen_or_Ind = cb; } else { // There are multiple segments, so we'll provide the data at execution time. Pass the PyObject pointer as // the parameter value which will be pased back to us when the data is needed. (If we release threads, we // need to up the refcount!) info.ParameterType = SQL_LONGVARBINARY; info.ParameterValuePtr = param; info.ColumnSize = (SQLUINTEGER)PyBuffer_Size(param); info.BufferLength = sizeof(PyObject*); // How big is ParameterValuePtr; ODBC copies it and gives it back in SQLParamData info.StrLen_or_Ind = cur->cnxn->need_long_data_len ? SQL_LEN_DATA_AT_EXEC((SQLLEN)PyBuffer_Size(param)) : SQL_DATA_AT_EXEC; } return true; }
void CQuery::WriteBlob(LPCTSTR szSQL, void *buf, int size) { SQLINTEGER cbBlob; char tmp[BLOBBATCH],*p; SQLPOINTER pToken; int nPut; //LogAdd("%s", szSQL); cbBlob=SQL_LEN_DATA_AT_EXEC(size); SQLBindParameter(hStmt,1,SQL_PARAM_INPUT,SQL_C_BINARY,SQL_LONGVARBINARY, size,0,(SQLPOINTER)1,0,&cbBlob); SQLExecDirect(hStmt,(SQLCHAR *)szSQL,SQL_NTS); ret=SQLParamData(hStmt, &pToken); while (ret==SQL_NEED_DATA) { if (ret==SQL_NEED_DATA) { if ((int)pToken==1) { for (p=(char *)buf;p<(char *)buf+size;p+=BLOBBATCH) { nPut=min(BLOBBATCH,(char *)buf+size-p); memcpy(tmp,p,nPut); SQLPutData(hStmt,(PTR)tmp,nPut); } } } ret=SQLParamData(hStmt, &pToken); } Clear(); }
static bool GetBytesInfo(Cursor* cur, Py_ssize_t index, PyObject* param, ParamInfo& info) { // In Python 2, a bytes object (ANSI string) is passed as varchar. In Python 3, it is passed as binary. Py_ssize_t len = PyBytes_GET_SIZE(param); #if PY_MAJOR_VERSION >= 3 info.ValueType = SQL_C_BINARY; info.ColumnSize = (SQLUINTEGER)max(len, 1); if (len <= cur->cnxn->binary_maxlength) { info.ParameterType = SQL_VARBINARY; info.StrLen_or_Ind = len; info.ParameterValuePtr = PyBytes_AS_STRING(param); } else { // Too long to pass all at once, so we'll provide the data at execute. info.ParameterType = SQL_LONGVARBINARY; info.StrLen_or_Ind = cur->cnxn->need_long_data_len ? SQL_LEN_DATA_AT_EXEC((SQLLEN)len) : SQL_DATA_AT_EXEC; info.ParameterValuePtr = param; } #else info.ValueType = SQL_C_CHAR; info.ColumnSize = (SQLUINTEGER)max(len, 1); if (len <= cur->cnxn->varchar_maxlength) { info.ParameterType = SQL_VARCHAR; info.StrLen_or_Ind = len; info.ParameterValuePtr = PyBytes_AS_STRING(param); } else { // Too long to pass all at once, so we'll provide the data at execute. info.ParameterType = SQL_LONGVARCHAR; info.StrLen_or_Ind = cur->cnxn->need_long_data_len ? SQL_LEN_DATA_AT_EXEC((SQLLEN)len) : SQL_DATA_AT_EXEC; info.ParameterValuePtr = param; } #endif info.fnToPyObject = ToBytesInfo; return true; }
static bool GetUnicodeInfo(Cursor* cur, Py_ssize_t index, PyObject* param, ParamInfo& info) { Py_UNICODE* pch = PyUnicode_AsUnicode(param); Py_ssize_t len = PyUnicode_GET_SIZE(param); info.ValueType = SQL_C_WCHAR; info.ColumnSize = (SQLUINTEGER)max(len, 1); if (len <= cur->cnxn->wvarchar_maxlength) { if (SQLWCHAR_SIZE == Py_UNICODE_SIZE) { info.ParameterValuePtr = pch; } else { // SQLWCHAR and Py_UNICODE are not the same size, so we need to allocate and copy a buffer. if (len > 0) { info.ParameterValuePtr = SQLWCHAR_FromUnicode(pch, len); if (info.ParameterValuePtr == 0) return false; info.allocated = true; } else { info.ParameterValuePtr = pch; } } info.ParameterType = SQL_WVARCHAR; info.StrLen_or_Ind = (SQLINTEGER)(len * sizeof(SQLWCHAR)); } else { // Too long to pass all at once, so we'll provide the data at execute. info.ParameterType = SQL_WLONGVARCHAR; info.StrLen_or_Ind = cur->cnxn->need_long_data_len ? SQL_LEN_DATA_AT_EXEC((SQLLEN)len * sizeof(SQLWCHAR)) : SQL_DATA_AT_EXEC; info.ParameterValuePtr = param; } return true; }
static void add_test(SQLSMALLINT c_type, SQLSMALLINT sql_type, const char *db_type, unsigned gen1, unsigned gen2) { test_info *t = NULL; size_t buf_len; if (num_tests >= MAX_TESTS) { fprintf(stderr, "too max tests\n"); exit(1); } t = &test_infos[num_tests++]; t->num = num_tests; t->c_type = c_type; t->sql_type = sql_type; t->db_type = db_type; t->gen1 = gen1; t->gen2 = gen2; t->vind = 0; switch (c_type) { case SQL_C_CHAR: buf_len = NBYTES*2+1; break; case SQL_C_WCHAR: buf_len = (NBYTES*2+1) * sizeof(SQLWCHAR); break; default: buf_len = NBYTES; } t->buf = (char*) malloc(buf_len); if (!t->buf) { fprintf(stderr, "memory error\n"); exit(1); } if (c_type != SQL_C_CHAR && c_type != SQL_C_WCHAR) fill_chars(t->buf, NBYTES, t->gen1, t->gen2); else memset(t->buf, 0, buf_len); t->vind = SQL_LEN_DATA_AT_EXEC(buf_len); }
static bool GetByteArrayInfo(Cursor* cur, Py_ssize_t index, PyObject* param, ParamInfo& info) { info.ValueType = SQL_C_BINARY; Py_ssize_t cb = PyByteArray_Size(param); if (cb <= cur->cnxn->binary_maxlength) { info.ParameterType = SQL_VARBINARY; info.ParameterValuePtr = (SQLPOINTER)PyByteArray_AsString(param); info.BufferLength = cb; info.ColumnSize = (SQLUINTEGER)max(cb, 1); info.StrLen_or_Ind = cb; } else { info.ParameterType = SQL_LONGVARBINARY; info.ParameterValuePtr = param; info.ColumnSize = (SQLUINTEGER)cb; info.BufferLength = sizeof(PyObject*); // How big is ParameterValuePtr; ODBC copies it and gives it back in SQLParamData info.StrLen_or_Ind = cur->cnxn->need_long_data_len ? SQL_LEN_DATA_AT_EXEC((SQLLEN)cb) : SQL_DATA_AT_EXEC; } return true; }
int SSmain(int argc, SSchar* argv[]) { HDBC hdbc; HENV henv; HSTMT hstmt; SQLRETURN return_code; UTLDbUtlProgStart (argc, argv, SSText("log.txt"), DB_PD_DDL_EXPORT_PROCNAME); /*1. Connect to DB*/ connectDB(&henv, &hdbc); /* HSTMT hstmt_session; return_code = SQLAllocStmt ((SQLHDBC)hdbc, (SQLHSTMT *)&hstmt_session); if (return_code != SQL_SUCCESS) { printf("ERROR: The SQL statement did not execute successfully.\n"); exit(1); } return_code = SQLExecDirect(hstmt_session, SSText("alter session set NLS_LANGUAGE='SIMPLIFIED CHINESE'"), -3); SQLFreeStmt(hstmt_session, SQL_DROP);*/ /*3. Execute the SQL statement*/ return_code = SQLAllocStmt ((SQLHDBC)hdbc, (SQLHSTMT *)&hstmt); if (return_code != SQL_SUCCESS) { printf("ERROR: The SQL statement did not execute successfully.\n"); exit(1); } SSchar* pFilterStmt = SSText("INSERT INTO TEST_CLOB_COL VALUES (?)"); //SSchar* pFilterStmt = SSText("INSERT INTO test(LOG_DATA_1) VALUES (?)"); return_code = SQLPrepare(hstmt, (SSuchar*)(pFilterStmt), SQL_NTS); SSchar clobcol[] = {0x3042,0x3044,0x3046,0x3048,0x304A, 0x0000}; /* test 1: LONG cbRowId = 10; //return_code= SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_VARCHAR, 4000, 0, clobcol, sizeof(clobcol), &cbRowId); //This is ok! return_code= SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_LONGVARCHAR, 40, 0, clobcol, 10, &cbRowId); return_code = SQLExecute((SQLHSTMT)hstmt); */ /*test 2*/ //test a: LONG cbRowId = SQL_DATA_AT_EXEC; LONG cbRowId = SQL_LEN_DATA_AT_EXEC(11); return_code= SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_LONGVARCHAR, 40, 0, clobcol, 10, &cbRowId); return_code = SQLExecute((SQLHSTMT)hstmt); SSchar *buf = clobcol; return_code = SQLParamData(hstmt, (SQLPOINTER *)&buf); return_code = SQLPutData(hstmt, buf, 10); return_code = SQLParamData(hstmt, (SQLPOINTER *)&buf); if (return_code == SQL_SUCCESS) { printf("The SQL statement executed successfully.\n"); } else{ printf("The SQL statement did not execute successfully.\n"); ODBC_error ((HENV)henv, (HDBC)hdbc, (HSTMT)hstmt) ; } SSchar* pSelectStmt = SSText("select userenv('language') from dual"); //SSchar* pFilterStmt = SSText("INSERT INTO test(LOG_DATA_1) VALUES (?)"); return_code = SQLPrepare(hstmt, (SSuchar*)(pSelectStmt), SQL_NTS); return_code = SQLExecute((SQLHSTMT)hstmt); SQLDisconnect ((SQLHDBC)hdbc); SQLFreeConnect ((SQLHDBC)hdbc); SQLFreeEnv ((SQLHENV)henv); return(return_code); }
int main(int argc, char *argv[]) { SQLLEN ind; int len = strlen(test_text), n, i; const char *p; char *pp; SQLPOINTER ptr; unsigned char buf[256], *pb; SQLRETURN RetCode; int type, lc, sql_type; odbc_connect(); /* create table to hold data */ odbc_command("CREATE TABLE #putdata (c TEXT NULL, b IMAGE NULL)"); sql_type = SQL_LONGVARCHAR; type = SQL_C_CHAR; lc = 1; for (;;) { CHKBindParameter(1, SQL_PARAM_INPUT, type, sql_type, 0, 0, (SQLPOINTER) 123, 0, &ind, "S"); /* length required */ ind = SQL_LEN_DATA_AT_EXEC(len * lc); /* * test for char */ CHKPrepare(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "S"); CHKExecute("Ne"); p = test_text; n = 5; CHKParamData(&ptr, "Ne"); if (ptr != (SQLPOINTER) 123) ODBC_REPORT_ERROR("Wrong pointer from SQLParamData"); while (*p) { int l = strlen(p); if (l < n) n = l; if (type == SQL_C_CHAR) { CHKPutData((char *) p, n, "S"); } else { SQLWCHAR buf[256]; CHKPutData((char *) buf, to_sqlwchar(buf, p, n), "S"); } p += n; n *= 2; } CHKParamData(&ptr, "S"); CHKParamData(&ptr, "E"); /* check state and reset some possible buffers */ odbc_command("DECLARE @i INT"); /* use server ntext if available */ if (sql_type == SQL_LONGVARCHAR && odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u) { sql_type = SQL_WLONGVARCHAR; continue; } if (type != SQL_C_CHAR) break; sql_type = SQL_LONGVARCHAR; type = SQL_C_WCHAR; lc = sizeof(SQLWCHAR); } /* update row setting binary field */ for (i = 0; i < 255; ++i) buf[i] = BYTE_AT(i); /* * test for binary */ CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0, 0, (SQLPOINTER) 4567, 0, &ind, "S"); ind = SQL_LEN_DATA_AT_EXEC(254); CHKPrepare(T("UPDATE #putdata SET b = ?"), SQL_NTS, "S"); CHKExecute("Ne"); pb = buf; n = 7; CHKParamData(&ptr, "Ne"); if (ptr != (SQLPOINTER) 4567) ODBC_REPORT_ERROR("Wrong pointer from SQLParamData"); while (pb != (buf + 254)) { int l = buf + 254 - pb; if (l < n) n = l; CHKPutData((char *) pb, n, "S"); pb += n; n *= 2; } CHKParamData(&ptr, "S"); CHKParamData(&ptr, "E"); /* check state and reset some possible buffers */ odbc_command("DECLARE @i2 INT"); CHKFreeStmt(SQL_RESET_PARAMS, "S"); /* check inserts ... there should be all equal rows */ strcpy(sql, "IF EXISTS(SELECT * FROM #putdata WHERE CONVERT(VARBINARY(255),b) <> 0x"); /* append binary */ for (i = 0; i < 254; ++i) sprintf(strchr(sql, 0), "%02x", buf[i]); strcat(sql, " OR CONVERT(VARCHAR(255),c) <> '"); /* append string */ pp = strchr(sql, 0); p = test_text; do { *pp++ = *p; if (*p == '\'') *pp++ = *p; } while(*p++); strcat(sql, "') SELECT 1"); odbc_check_no_row(sql); odbc_command("DELETE FROM #putdata"); /* test len == 0 case from ML */ type = SQL_C_CHAR; for (;;) { CHKPrepare(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "S"); CHKBindParameter(1, SQL_PARAM_INPUT, type, SQL_LONGVARCHAR, 0, 0, (PTR) 2, 0, &ind, "S"); ind = SQL_LEN_DATA_AT_EXEC(0); RetCode = CHKExecute("Ne"); while (RetCode == SQL_NEED_DATA) { RetCode = SQLParamData(odbc_stmt, &ptr); if (RetCode == SQL_NEED_DATA) { if (type == SQL_C_CHAR) { CHKPutData("abc", 3, "S"); } else { SQLWCHAR buf[10]; CHKPutData(buf, to_sqlwchar(buf, "abc", 3), "S"); } } } if (type != SQL_C_CHAR) break; type = SQL_C_WCHAR; odbc_reset_statement(); } /* check inserts ... */ odbc_check_no_row("IF EXISTS(SELECT * FROM #putdata WHERE c NOT LIKE 'abc') SELECT 1"); odbc_command("DELETE FROM #putdata"); /* test putting 0 bytes from Sebastien Flaesch */ if (odbc_db_is_microsoft()) { type = SQL_C_CHAR; for (;;) { CHKPrepare(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "S"); CHKBindParameter(1, SQL_PARAM_INPUT, type, SQL_LONGVARCHAR, 10, 0, (PTR) 2, 10, &ind, "S"); ind = SQL_DATA_AT_EXEC; RetCode = CHKExecute("Ne"); while (RetCode == SQL_NEED_DATA) { RetCode = SQLParamData(odbc_stmt, &ptr); if (RetCode == SQL_NEED_DATA) CHKPutData("", 0, "S"); } if (type != SQL_C_CHAR) break; type = SQL_C_WCHAR; odbc_reset_statement(); } /* check inserts ... */ odbc_check_no_row("IF EXISTS(SELECT * FROM #putdata WHERE c NOT LIKE '') SELECT 1"); } /* TODO test cancel inside SQLExecute */ odbc_disconnect(); printf("Done.\n"); return 0; }
CSqlRecordsetPtr CMssqlConnection::_Execute(const char *string) { cvs::string str = string; SQLRETURN ret; CMssqlRecordset *rs = new CMssqlRecordset(); CServerIo::trace(3,"%s",str.c_str()); bool inquote = false; for(size_t n=0; n<str.size(); n++) { if(str[n]=='\'') { inquote = !inquote; if(inquote) str.insert(n++,1,'N'); } } HSTMT hStmt; if(!SQL_SUCCEEDED(m_lasterror=SQLAllocHandle(SQL_HANDLE_STMT,m_hDbc,&hStmt))) { SQLFreeStmt(hStmt,SQL_DROP); return rs; } for(std::map<int,CSqlVariant>::iterator i = m_bindVars.begin(); i!=m_bindVars.end(); ++i) { switch(i->second.type()) { case CSqlVariant::vtNull: m_sqli[i->first]=SQL_NULL_DATA; ret = SQLBindParameter(hStmt,i->first+1,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,0,0,NULL,0,&m_sqli[i->first]); break; case CSqlVariant::vtChar: CServerIo::trace(3,"Bind vtChar (SQL Server) = \"%c\"",m_sqlv[i->first].c); m_sqli[i->first]=0; m_sqlv[i->first].c=i->second; ret = SQLBindParameter(hStmt,i->first+1,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,1,0,&m_sqlv[i->first].c,1,&m_sqli[i->first]); break; case CSqlVariant::vtUChar: m_sqli[i->first]=0; m_sqlv[i->first].c=i->second; ret = SQLBindParameter(hStmt,i->first+1,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_CHAR,1,0,&m_sqlv[i->first].c,1,&m_sqli[i->first]); break; case CSqlVariant::vtShort: m_sqli[i->first]=0; m_sqlv[i->first].s=i->second; ret = SQLBindParameter(hStmt,i->first+1,SQL_PARAM_INPUT,SQL_C_SSHORT,SQL_INTEGER,0,0,&m_sqlv[i->first].s,0,&m_sqli[i->first]); break; case CSqlVariant::vtUShort: m_sqli[i->first]=0; m_sqlv[i->first].s=i->second; ret = SQLBindParameter(hStmt,i->first+1,SQL_PARAM_INPUT,SQL_C_USHORT,SQL_INTEGER,0,0,&m_sqlv[i->first].s,0,&m_sqli[i->first]); break; case CSqlVariant::vtInt: case CSqlVariant::vtLong: m_sqli[i->first]=0; m_sqlv[i->first].l=i->second; ret = SQLBindParameter(hStmt,i->first+1,SQL_PARAM_INPUT,SQL_C_SLONG,SQL_INTEGER,0,0,&m_sqlv[i->first].l,0,&m_sqli[i->first]); break; case CSqlVariant::vtUInt: case CSqlVariant::vtULong: m_sqli[i->first]=0; m_sqlv[i->first].l=i->second; ret = SQLBindParameter(hStmt,i->first+1,SQL_PARAM_INPUT,SQL_C_ULONG,SQL_INTEGER,0,0,&m_sqlv[i->first].l,0,&m_sqli[i->first]); break; case CSqlVariant::vtLongLong: m_sqli[i->first]=0; m_sqlv[i->first].ll=i->second; ret = SQLBindParameter(hStmt,i->first+1,SQL_PARAM_INPUT,SQL_C_SBIGINT,SQL_BIGINT,0,0,&m_sqlv[i->first].ll,0,&m_sqli[i->first]); break; case CSqlVariant::vtULongLong: m_sqli[i->first]=0; m_sqlv[i->first].ll=i->second; ret = SQLBindParameter(hStmt,i->first+1,SQL_PARAM_INPUT,SQL_C_UBIGINT,SQL_BIGINT,0,0,&m_sqlv[i->first].ll,0,&m_sqli[i->first]); break; case CSqlVariant::vtString: CServerIo::trace(3,"Bind vtString (SQL Server)"); if (m_sqlv[i->first].ws.length()+1<256) { CServerIo::trace(3,"Bind vtString as type SQL_NTS (Null Terminated String)"); m_sqli[i->first]=SQL_NTS; m_sqlv[i->first].ws=cvs::wide(i->second); CServerIo::trace(3,"Bind vtString as SQL_VARCHAR/text C_WCHAR"); ret = SQLBindParameter(hStmt,i->first+1,SQL_PARAM_INPUT,SQL_C_WCHAR,SQL_VARCHAR,(SQLINTEGER)m_sqlv[i->first].ws.size()+1,0,(SQLPOINTER)m_sqlv[i->first].ws.c_str(),(SQLINTEGER)m_sqlv[i->first].ws.size(),&m_sqli[i->first]); } else { CServerIo::trace(3,"Bind vtString as type LEN_DATA_AT_EXEC"); m_sqli[i->first]=SQL_LEN_DATA_AT_EXEC((SQLINTEGER)((m_sqlv[i->first].ws.size()+1)*sizeof(wchar_t))); m_sqlv[i->first].ws=cvs::wide(i->second); CServerIo::trace(3,"Bind vtString as SQL_WLONGVARCHAR/text BLOB"); ret = SQLBindParameter(hStmt,i->first+1,SQL_PARAM_INPUT,SQL_C_WCHAR,SQL_WLONGVARCHAR,(SQLINTEGER)((m_sqlv[i->first].ws.size()+1)*sizeof(wchar_t)),0,(VOID *)NULL,0,&m_sqli[i->first]); } break; case CSqlVariant::vtWString: CServerIo::trace(3,"Bind vtWString (SQL Server)"); m_sqli[i->first]=SQL_NTS; m_sqlv[i->first].ws=i->second; CServerIo::trace(3,"Bind vtWString (SQL Server)"); ret = SQLBindParameter(hStmt,i->first+1,SQL_PARAM_INPUT,SQL_C_WCHAR,SQL_WVARCHAR,(SQLINTEGER)m_sqlv[i->first].ws.size()+1,0,(SQLPOINTER)m_sqlv[i->first].ws.c_str(),(SQLINTEGER)m_sqlv[i->first].ws.size()+1,&m_sqli[i->first]); break; } } CServerIo::trace(3,"%s",str.c_str()); rs->Init(this,hStmt,str.c_str()); // Ignore return... it's handled by the error routines m_bindVars.clear(); return rs; }
static int odbc_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type) { pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; RETCODE rc; SWORD sqltype = 0, ctype = 0, scale = 0, nullable = 0; SQLULEN precision = 0; pdo_odbc_param *P; zval *parameter; /* we're only interested in parameters for prepared SQL right now */ if (param->is_param) { switch (event_type) { case PDO_PARAM_EVT_FETCH_PRE: case PDO_PARAM_EVT_FETCH_POST: case PDO_PARAM_EVT_NORMALIZE: /* Do nothing */ break; case PDO_PARAM_EVT_FREE: P = param->driver_data; if (P) { efree(P); } break; case PDO_PARAM_EVT_ALLOC: { /* figure out what we're doing */ switch (PDO_PARAM_TYPE(param->param_type)) { case PDO_PARAM_LOB: break; case PDO_PARAM_STMT: return 0; default: break; } rc = SQLDescribeParam(S->stmt, (SQLUSMALLINT) param->paramno+1, &sqltype, &precision, &scale, &nullable); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { /* MS Access, for instance, doesn't support SQLDescribeParam, * so we need to guess */ sqltype = PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB ? SQL_LONGVARBINARY : SQL_LONGVARCHAR; precision = 4000; scale = 5; nullable = 1; if (param->max_value_len > 0) { precision = param->max_value_len; } } if (sqltype == SQL_BINARY || sqltype == SQL_VARBINARY || sqltype == SQL_LONGVARBINARY) { ctype = SQL_C_BINARY; } else { ctype = SQL_C_CHAR; } P = emalloc(sizeof(*P)); param->driver_data = P; P->len = 0; /* is re-populated each EXEC_PRE */ P->outbuf = NULL; P->is_unicode = pdo_odbc_sqltype_is_unicode(S, sqltype); if (P->is_unicode) { /* avoid driver auto-translation: we'll do it ourselves */ ctype = SQL_C_BINARY; } if ((param->param_type & PDO_PARAM_INPUT_OUTPUT) == PDO_PARAM_INPUT_OUTPUT) { P->paramtype = SQL_PARAM_INPUT_OUTPUT; } else if (param->max_value_len <= 0) { P->paramtype = SQL_PARAM_INPUT; } else { P->paramtype = SQL_PARAM_OUTPUT; } if (P->paramtype != SQL_PARAM_INPUT) { if (PDO_PARAM_TYPE(param->param_type) != PDO_PARAM_NULL) { /* need an explicit buffer to hold result */ P->len = param->max_value_len > 0 ? param->max_value_len : precision; if (P->is_unicode) { P->len *= 2; } P->outbuf = emalloc(P->len + (P->is_unicode ? 2:1)); } } if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->paramtype != SQL_PARAM_INPUT) { pdo_odbc_stmt_error("Can't bind a lob for output"); return 0; } rc = SQLBindParameter(S->stmt, (SQLUSMALLINT) param->paramno+1, P->paramtype, ctype, sqltype, precision, scale, P->paramtype == SQL_PARAM_INPUT ? (SQLPOINTER)param : P->outbuf, P->len, &P->len ); if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { return 1; } pdo_odbc_stmt_error("SQLBindParameter"); return 0; } case PDO_PARAM_EVT_EXEC_PRE: P = param->driver_data; if (!Z_ISREF(param->parameter)) { parameter = ¶m->parameter; } else { parameter = Z_REFVAL(param->parameter); } if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) { if (Z_TYPE_P(parameter) == IS_RESOURCE) { php_stream *stm; php_stream_statbuf sb; php_stream_from_zval_no_verify(stm, parameter); if (!stm) { return 0; } if (0 == php_stream_stat(stm, &sb)) { if (P->outbuf) { int len, amount; char *ptr = P->outbuf; char *end = P->outbuf + P->len; P->len = 0; do { amount = end - ptr; if (amount == 0) { break; } if (amount > 8192) amount = 8192; len = php_stream_read(stm, ptr, amount); if (len == 0) { break; } ptr += len; P->len += len; } while (1); } else { P->len = SQL_LEN_DATA_AT_EXEC(sb.sb.st_size); } } else { if (P->outbuf) { P->len = 0; } else { P->len = SQL_LEN_DATA_AT_EXEC(0); } } } else { convert_to_string(parameter); if (P->outbuf) { P->len = Z_STRLEN_P(parameter); memcpy(P->outbuf, Z_STRVAL_P(parameter), P->len); } else { P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(parameter)); } } } else if (Z_TYPE_P(parameter) == IS_NULL || PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL) { P->len = SQL_NULL_DATA; } else { convert_to_string(parameter); if (P->outbuf) { zend_ulong ulen; switch (pdo_odbc_utf82ucs2(stmt, P->is_unicode, Z_STRVAL_P(parameter), Z_STRLEN_P(parameter), &ulen)) { case PDO_ODBC_CONV_FAIL: case PDO_ODBC_CONV_NOT_REQUIRED: P->len = Z_STRLEN_P(parameter); memcpy(P->outbuf, Z_STRVAL_P(parameter), P->len); break; case PDO_ODBC_CONV_OK: P->len = ulen; memcpy(P->outbuf, S->convbuf, P->len); break; } } else { P->len = SQL_LEN_DATA_AT_EXEC(Z_STRLEN_P(parameter)); } } return 1; case PDO_PARAM_EVT_EXEC_POST: P = param->driver_data; if (P->outbuf) { zend_ulong ulen; char *srcbuf; zend_ulong srclen = 0; if (Z_ISREF(param->parameter)) { parameter = Z_REFVAL(param->parameter); } else { parameter = ¶m->parameter; } zval_ptr_dtor(parameter); ZVAL_NULL(parameter); switch (P->len) { case SQL_NULL_DATA: break; default: switch (pdo_odbc_ucs22utf8(stmt, P->is_unicode, P->outbuf, P->len, &ulen)) { case PDO_ODBC_CONV_FAIL: /* something fishy, but allow it to come back as binary */ case PDO_ODBC_CONV_NOT_REQUIRED: srcbuf = P->outbuf; srclen = P->len; break; case PDO_ODBC_CONV_OK: srcbuf = S->convbuf; srclen = ulen; break; } ZVAL_NEW_STR(parameter, zend_string_alloc(srclen, 0)); memcpy(Z_STRVAL_P(parameter), srcbuf, srclen); Z_STRVAL_P(parameter)[Z_STRLEN_P(parameter)] = '\0'; } } return 1; } } return 1; }
static BOOL kpc_bindparameter(ATOMID idfName, WORD h, LPFETCH lpFetch, int nParam, ATOMID idMode, WORD wType, OBJECTID idObj, ATOMID idSlot, BOOL bLive) { WORD wMode; WORD sqlType = SQL_LONGVARCHAR, scale = 0, nullable = SQL_NO_NULLS; DWORD colDef = RET_BUFFER_LEN - 1; LPPARAM lpParams, lpParam; LPDESC lpDesc; WORD wNumParams = 0; DWORD dwLen; RETCODE code; if (idMode == Symbol(INPUT)) wMode = SQL_PARAM_INPUT; else if (idMode == Symbol(OUTPUT)) wMode = SQL_PARAM_OUTPUT; else if (idMode == Symbol(INPUT_OUTPUT)) wMode = SQL_PARAM_INPUT_OUTPUT; code = SQLDescribeParam(lpFetch->hstmt, nParam, &sqlType, &colDef, &scale, &nullable); switch (code) { case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO: break; case SQL_INVALID_HANDLE: return KPC_HANDLE_ERROR(IDE_INVALID_HANDLE, h); default: sql_error(idfName, SQL_NULL_HDBC, lpFetch->hstmt); if (!stricmp(sqlstate, "IM001")) { if (nParam < 1) return KPC_ERROR(IDE_OUTOF_RANGE, KppAddAtomInt(nParam)); if (!num_params(idfName, h, lpFetch->hstmt, &wNumParams)) return ERROR; if (nParam > wNumParams) return KPC_ERROR(IDE_OUTOF_RANGE, KppAddAtomInt(nParam)); sqlType = SQL_LONGVARCHAR; colDef = RET_BUFFER_LEN - 1; nullable = SQL_NO_NULLS; } else return ERROR; } if (!lpFetch->params) { if (!wNumParams && !num_params(idfName, h, lpFetch->hstmt, &wNumParams)) return ERROR; lpParams = calloc(sizeof(PARAM), wNumParams); if (!lpParams) return KPC_ERROR(IDE_OUTOF_MEMORY, NULLID); } else lpParams = lpFetch->params; lpParam = lpParams + nParam - 1; lpDesc = &lpParam->desc; lpDesc->sqlType = sqlType; lpDesc->colDef = colDef; lpDesc->scale = scale; lpDesc->nullable = nullable; if (lpFetch->wXParamRows) { lpDesc->pdwLen = calloc(sizeof(DWORD), lpFetch->wXParamRows + 1); if (!lpDesc->pdwLen) return KPC_ERROR(IDE_OUTOF_MEMORY, NULLID); } else lpDesc->pdwLen = &lpDesc->dwLen; if (!fill_bind(idfName, lpDesc, &lpParam->data, lpFetch->wXParamRows, &dwLen)) { free_params(lpParams, lpFetch->wNumParams); return ERROR; } else { lpParam->wMode = wMode; lpParam->wType = wType; lpParam->idObj = idObj; lpParam->idSlot = idSlot; lpDesc->colDef = dwLen; lpFetch->wNumParams = wNumParams; lpFetch->params = lpParams; if (bLive) { int i = -1; while (++i <= lpFetch->wXParamRows) lpDesc->pdwLen[i] = SQL_LEN_DATA_AT_EXEC(0); } else if (!set_parameter_value(idfName, lpParam, lpFetch->wXParamRows)) return ERROR; } code = SQLBindParameter(lpFetch->hstmt, nParam, wMode, lpDesc->cType, lpDesc->sqlType, lpDesc->colDef, lpDesc->scale, lpDesc->address, dwLen, lpDesc->pdwLen); switch (code) { case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO: lpParam->bound = TRUE; return TRUE; case SQL_INVALID_HANDLE: return KPC_HANDLE_ERROR(IDE_INVALID_HANDLE, h); default: return sql_error(idfName, SQL_NULL_HDBC, lpFetch->hstmt); } }
/** * Convert parameters to libtds format * @return SQL_SUCCESS, SQL_ERROR or SQL_NEED_DATA */ SQLRETURN sql2tds(TDS_DBC * dbc, struct _drecord *drec_ipd, struct _drecord *drec_apd, TDSPARAMINFO * info, int nparam) { int dest_type, src_type, res; CONV_RESULT ores; TDSBLOBINFO *blob_info; char *src; unsigned char *dest; TDSCOLINFO *curcol = info->columns[nparam]; int len; TDS_DATETIME dt; TDS_NUMERIC num; SQL_NUMERIC_STRUCT *sql_num; SQLINTEGER sql_len; int need_data = 0, i; /* TODO handle bindings of char like "{d '2002-11-12'}" */ tdsdump_log(TDS_DBG_INFO2, "%s:%d type=%d\n", __FILE__, __LINE__, drec_ipd->sql_desc_concise_type); /* what type to convert ? */ dest_type = odbc_sql_to_server_type(dbc->tds_socket, drec_ipd->sql_desc_concise_type); if (dest_type == TDS_FAIL) return SQL_ERROR; tdsdump_log(TDS_DBG_INFO2, "%s:%d\n", __FILE__, __LINE__); /* TODO what happen for unicode types ?? */ tds_set_param_type(dbc->tds_socket, curcol, dest_type); if (is_numeric_type(curcol->column_type)) { curcol->column_prec = drec_ipd->sql_desc_precision; curcol->column_scale = drec_ipd->sql_desc_scale; } if (drec_ipd->sql_desc_parameter_type != SQL_PARAM_INPUT) curcol->column_output = 1; /* compute destination length */ if (curcol->column_varint_size != 0) { /* curcol->column_size = drec_apd->sql_desc_octet_length; */ /* * TODO destination length should come from sql_desc_length, * however there is the encoding problem to take into account * we should fill destination length after conversion keeping * attention to fill correctly blob/fixed type/variable type */ curcol->column_cur_size = 0; curcol->column_size = drec_ipd->sql_desc_length; if (curcol->column_size < 0) curcol->column_size = 0x7FFFFFFFl; } else { /* TODO only a trick... */ if (curcol->column_varint_size == 0) tds_set_param_type(dbc->tds_socket, curcol, tds_get_null_type(dest_type)); } /* get C type */ src_type = drec_apd->sql_desc_concise_type; if (src_type == SQL_C_DEFAULT) src_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type); /* if only output assume input is NULL */ if (drec_ipd->sql_desc_parameter_type == SQL_PARAM_OUTPUT) sql_len = SQL_NULL_DATA; else sql_len = odbc_get_param_len(dbc->tds_socket, drec_apd, drec_ipd); /* compute source length */ switch (sql_len) { case SQL_NULL_DATA: len = 0; break; case SQL_NTS: len = strlen(drec_apd->sql_desc_data_ptr); break; case SQL_DEFAULT_PARAM: case SQL_DATA_AT_EXEC: /* TODO */ return SQL_ERROR; break; default: len = sql_len; if (sql_len < 0) { /* test for SQL_C_CHAR/SQL_C_BINARY */ switch (src_type) { case SQL_C_CHAR: case SQL_C_BINARY: break; default: return SQL_ERROR; } len = SQL_LEN_DATA_AT_EXEC(sql_len); need_data = 1; /* other trick, set length of destination */ switch (odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type)) { case SQL_C_CHAR: case SQL_C_BINARY: curcol->column_size = len; break; } } } /* allocate given space */ if (!tds_alloc_param_row(info, curcol)) return SQL_ERROR; /* test source type */ /* TODO test intervals */ src_type = odbc_c_to_server_type(src_type); if (src_type == TDS_FAIL) return SQL_ERROR; if (need_data) { curcol->column_cur_size = 0; return SQL_NEED_DATA; } /* set null */ assert(drec_ipd->sql_desc_parameter_type != SQL_PARAM_OUTPUT || sql_len == SQL_NULL_DATA); if (sql_len == SQL_NULL_DATA) { curcol->column_cur_size = 0; tds_set_null(info->current_row, nparam); return TDS_SUCCEED; } /* convert special parameters (not libTDS compatible) */ src = drec_apd->sql_desc_data_ptr; switch (src_type) { case SYBDATETIME: convert_datetime2server(drec_apd->sql_desc_concise_type, src, &dt); src = (char *) &dt; break; case SYBDECIMAL: case SYBNUMERIC: sql_num = (SQL_NUMERIC_STRUCT *) src; num.precision = sql_num->precision; num.scale = sql_num->scale; num.array[0] = sql_num->sign ^ 1; /* TODO test precision so client do not crash our library ?? */ i = tds_numeric_bytes_per_prec[num.precision]; memcpy(num.array + 1, sql_num->val, i); tds_swap_bytes(num.array + 1, i); ++i; if (i < sizeof(num.array)) memset(num.array + i, 0, sizeof(num.array) - i); src = (char *) # /* set output */ /* TODO use descriptors informations ?? */ ores.n.precision = 18; ores.n.scale = 2; break; /* TODO intervals */ } res = tds_convert(dbc->env->tds_ctx, src_type, src, len, dest_type, &ores); if (res < 0) return SQL_ERROR; tdsdump_log(TDS_DBG_INFO2, "%s:%d\n", __FILE__, __LINE__); /* truncate ?? */ /* TODO what happen for blobs ?? */ if (res > curcol->column_size) res = curcol->column_size; curcol->column_cur_size = res; /* free allocated memory */ dest = &info->current_row[curcol->column_offset]; switch ((TDS_SERVER_TYPE) dest_type) { case SYBCHAR: case SYBVARCHAR: case XSYBCHAR: case XSYBVARCHAR: memcpy(&info->current_row[curcol->column_offset], ores.c, res); free(ores.c); break; case SYBTEXT: blob_info = (TDSBLOBINFO *) dest; if (blob_info->textvalue) free(blob_info->textvalue); blob_info->textvalue = ores.c; break; case SYBBINARY: case SYBVARBINARY: case XSYBBINARY: case XSYBVARBINARY: memcpy(&info->current_row[curcol->column_offset], ores.ib, res); free(ores.ib); break; case SYBLONGBINARY: case SYBIMAGE: blob_info = (TDSBLOBINFO *) dest; if (blob_info->textvalue) free(blob_info->textvalue); blob_info->textvalue = ores.ib; break; case SYBINTN: case SYBINT1: case SYBINT2: case SYBINT4: case SYBINT8: case SYBFLT8: case SYBDATETIME: case SYBBIT: case SYBMONEY4: case SYBMONEY: case SYBDATETIME4: case SYBREAL: case SYBBITN: case SYBNUMERIC: case SYBDECIMAL: case SYBFLTN: case SYBMONEYN: case SYBDATETIMN: case SYBSINT1: case SYBUINT2: case SYBUINT4: case SYBUINT8: case SYBUNIQUE: memcpy(&info->current_row[curcol->column_offset], &ores, res); break; case XSYBNVARCHAR: case XSYBNCHAR: case SYBNVARCHAR: case SYBNTEXT: case SYBVOID: case SYBVARIANT: /* TODO ODBC 3.5 */ assert(0); break; } return SQL_SUCCESS; }
/** * Convert parameters to libtds format * @return SQL_SUCCESS, SQL_ERROR or SQL_NEED_DATA */ SQLRETURN sql2tds(TDS_STMT * stmt, const struct _drecord *drec_ipd, const struct _drecord *drec_apd, TDSCOLUMN *curcol, int compute_row, const TDS_DESC* axd, unsigned int n_row) { TDS_DBC * dbc = stmt->dbc; int dest_type, src_type, sql_src_type, res; CONV_RESULT ores; TDSBLOB *blob; char *src; unsigned char *dest; int len; TDS_DATETIME dt; TDS_NUMERIC num; SQL_NUMERIC_STRUCT *sql_num; SQLINTEGER sql_len; int need_data = 0, i; /* TODO handle bindings of char like "{d '2002-11-12'}" */ tdsdump_log(TDS_DBG_INFO2, "type=%d\n", drec_ipd->sql_desc_concise_type); /* what type to convert ? */ dest_type = odbc_sql_to_server_type(dbc->tds_socket, drec_ipd->sql_desc_concise_type); if (dest_type == TDS_FAIL) return SQL_ERROR; tdsdump_log(TDS_DBG_INFO2, "trace\n"); /* TODO what happen for unicode types ?? */ tds_set_param_type(dbc->tds_socket, curcol, dest_type); if (is_numeric_type(curcol->column_type)) { curcol->column_prec = drec_ipd->sql_desc_precision; curcol->column_scale = drec_ipd->sql_desc_scale; } if (drec_ipd->sql_desc_parameter_type != SQL_PARAM_INPUT) curcol->column_output = 1; /* compute destination length */ if (curcol->column_varint_size != 0) { /* curcol->column_size = drec_apd->sql_desc_octet_length; */ /* * TODO destination length should come from sql_desc_length, * however there is the encoding problem to take into account * we should fill destination length after conversion keeping * attention to fill correctly blob/fixed type/variable type */ /* TODO location of this test is correct here ?? */ if (dest_type != SYBUNIQUE && dest_type != SYBBITN && !is_fixed_type(dest_type)) { curcol->column_cur_size = 0; curcol->column_size = drec_ipd->sql_desc_length; if (curcol->column_size < 0) curcol->column_size = 0x7FFFFFFFl; } } else if (dest_type != SYBBIT) { /* TODO only a trick... */ tds_set_param_type(dbc->tds_socket, curcol, tds_get_null_type(dest_type)); } /* get C type */ sql_src_type = drec_apd->sql_desc_concise_type; if (sql_src_type == SQL_C_DEFAULT) sql_src_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type); /* test source type */ /* TODO test intervals */ src_type = odbc_c_to_server_type(sql_src_type); if (src_type == TDS_FAIL) return SQL_ERROR; /* we have no data to convert, just return */ if (!compute_row) return TDS_SUCCEED; src = drec_apd->sql_desc_data_ptr; if (src && n_row) { SQLLEN len; if (axd->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN) { len = axd->header.sql_desc_bind_type; if (axd->header.sql_desc_bind_offset_ptr) src += *axd->header.sql_desc_bind_offset_ptr; } else { len = odbc_get_octet_len(sql_src_type, drec_apd); if (len < 0) /* TODO sure ? what happen to upper layer ?? */ return SQL_ERROR; } src += len * n_row; } /* if only output assume input is NULL */ if (drec_ipd->sql_desc_parameter_type == SQL_PARAM_OUTPUT) { sql_len = SQL_NULL_DATA; } else { sql_len = odbc_get_param_len(drec_apd, drec_ipd, axd, n_row); /* special case, MS ODBC handle conversion from "\0" to any to NULL, DBD::ODBC require it */ if (src_type == SYBVARCHAR && sql_len == 1 && drec_ipd->sql_desc_parameter_type == SQL_PARAM_INPUT_OUTPUT && src && *src == 0) { sql_len = SQL_NULL_DATA; } } /* compute source length */ switch (sql_len) { case SQL_NULL_DATA: len = 0; break; case SQL_NTS: /* check that SQLBindParameter::ParameterValuePtr is not zero for input parameters */ if (!src) { odbc_errs_add(&stmt->errs, "HY090", NULL); return SQL_ERROR; } len = strlen(src); break; case SQL_DEFAULT_PARAM: case SQL_DATA_AT_EXEC: /* TODO */ return SQL_ERROR; break; default: len = sql_len; if (sql_len < 0) { /* test for SQL_C_CHAR/SQL_C_BINARY */ switch (sql_src_type) { case SQL_C_CHAR: case SQL_C_BINARY: break; default: return SQL_ERROR; } len = SQL_LEN_DATA_AT_EXEC(sql_len); need_data = 1; /* dynamic length allowed only for BLOB fields */ switch (drec_ipd->sql_desc_concise_type) { case SQL_LONGVARCHAR: case SQL_LONGVARBINARY: break; default: return SQL_ERROR; } } } /* allocate given space */ if (!tds_alloc_param_data(curcol)) return SQL_ERROR; if (need_data) { curcol->column_cur_size = 0; return SQL_NEED_DATA; } /* set null */ assert(drec_ipd->sql_desc_parameter_type != SQL_PARAM_OUTPUT || sql_len == SQL_NULL_DATA); if (sql_len == SQL_NULL_DATA) { curcol->column_cur_size = -1; return TDS_SUCCEED; } if (!src) { odbc_errs_add(&stmt->errs, "HY090", NULL); return SQL_ERROR; } /* convert special parameters (not libTDS compatible) */ switch (src_type) { case SYBDATETIME: convert_datetime2server(drec_apd->sql_desc_concise_type, src, &dt); src = (char *) &dt; break; case SYBDECIMAL: case SYBNUMERIC: sql_num = (SQL_NUMERIC_STRUCT *) src; num.precision = sql_num->precision; num.scale = sql_num->scale; num.array[0] = sql_num->sign ^ 1; /* test precision so client do not crash our library */ if (num.precision <= 0 || num.precision > 38 || num.scale > num.precision) /* TODO add proper error */ return SQL_ERROR; i = tds_numeric_bytes_per_prec[num.precision]; memcpy(num.array + 1, sql_num->val, i - 1); tds_swap_bytes(num.array + 1, i - 1); if (i < sizeof(num.array)) memset(num.array + i, 0, sizeof(num.array) - i); src = (char *) # break; /* TODO intervals */ } dest = curcol->column_data; switch ((TDS_SERVER_TYPE) dest_type) { case SYBCHAR: case SYBVARCHAR: case XSYBCHAR: case XSYBVARCHAR: ores.cc.c = (TDS_CHAR*) dest; ores.cc.len = curcol->column_size; res = tds_convert(dbc->env->tds_ctx, src_type, src, len, TDS_CONVERT_CHAR, &ores); if (res > curcol->column_size) res = curcol->column_size; break; case SYBBINARY: case SYBVARBINARY: case XSYBBINARY: case XSYBVARBINARY: ores.cb.ib = (TDS_CHAR*) dest; ores.cb.len = curcol->column_size; res = tds_convert(dbc->env->tds_ctx, src_type, src, len, TDS_CONVERT_BINARY, &ores); if (res > curcol->column_size) res = curcol->column_size; break; case SYBTEXT: case SYBLONGBINARY: case SYBIMAGE: res = tds_convert(dbc->env->tds_ctx, src_type, src, len, dest_type, &ores); if (res < 0) return SQL_ERROR; blob = (TDSBLOB *) dest; free(blob->textvalue); blob->textvalue = ores.ib; break; case SYBNUMERIC: case SYBDECIMAL: ((TDS_NUMERIC *) dest)->precision = drec_ipd->sql_desc_precision; ((TDS_NUMERIC *) dest)->scale = drec_ipd->sql_desc_scale; case SYBINTN: case SYBINT1: case SYBINT2: case SYBINT4: case SYBINT8: case SYBFLT8: case SYBDATETIME: case SYBBIT: case SYBMONEY4: case SYBMONEY: case SYBDATETIME4: case SYBREAL: case SYBBITN: case SYBFLTN: case SYBMONEYN: case SYBDATETIMN: case SYBSINT1: case SYBUINT2: case SYBUINT4: case SYBUINT8: case SYBUNIQUE: res = tds_convert(dbc->env->tds_ctx, src_type, src, len, dest_type, (CONV_RESULT*) dest); break; default: case XSYBNVARCHAR: case XSYBNCHAR: case SYBNVARCHAR: case SYBNTEXT: case SYBVOID: case SYBVARIANT: /* TODO ODBC 3.5 */ assert(0); res = -1; break; } if (res < 0) return SQL_ERROR; curcol->column_cur_size = res; return SQL_SUCCESS; }
/** * Convert parameters to libtds format * @return SQL_SUCCESS, SQL_ERROR or SQL_NEED_DATA */ SQLRETURN odbc_sql2tds(TDS_STMT * stmt, const struct _drecord *drec_ipd, const struct _drecord *drec_apd, TDSCOLUMN *curcol, int compute_row, const TDS_DESC* axd, unsigned int n_row) { TDS_DBC * dbc = stmt->dbc; TDSCONNECTION * conn = dbc->tds_socket->conn; int dest_type, src_type, sql_src_type, res; CONV_RESULT ores; TDSBLOB *blob; char *src, *converted_src; unsigned char *dest; int len; TDS_DATETIMEALL dta; TDS_NUMERIC num; SQL_NUMERIC_STRUCT *sql_num; SQLINTEGER sql_len; int need_data = 0, i; /* TODO handle bindings of char like "{d '2002-11-12'}" */ tdsdump_log(TDS_DBG_INFO2, "type=%d\n", drec_ipd->sql_desc_concise_type); /* what type to convert ? */ dest_type = odbc_sql_to_server_type(conn, drec_ipd->sql_desc_concise_type, drec_ipd->sql_desc_unsigned); if (!dest_type) { odbc_errs_add(&stmt->errs, "07006", NULL); /* Restricted data type attribute violation */ return SQL_ERROR; } tdsdump_log(TDS_DBG_INFO2, "trace\n"); /* get C type */ sql_src_type = drec_apd->sql_desc_concise_type; if (sql_src_type == SQL_C_DEFAULT) sql_src_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type); /* TODO what happen for unicode types ?? */ if (is_char_type(dest_type) && sql_src_type == SQL_C_WCHAR) { TDSICONV *conv = conn->char_convs[is_unicode_type(dest_type) ? client2ucs2 : client2server_chardata]; tds_set_param_type(conn, curcol, dest_type); curcol->char_conv = tds_iconv_get(conn, odbc_get_wide_name(conn), conv->to.charset.name); memcpy(curcol->column_collation, conn->collation, sizeof(conn->collation)); } else { #ifdef ENABLE_ODBC_WIDE TDSICONV *conv = conn->char_convs[is_unicode_type(dest_type) ? client2ucs2 : client2server_chardata]; tds_set_param_type(conn, curcol, dest_type); /* use binary format for binary to char */ if (is_char_type(dest_type)) curcol->char_conv = sql_src_type == SQL_C_BINARY ? NULL : tds_iconv_get(conn, tds_dstr_cstr(&dbc->original_charset), conv->to.charset.name); #else tds_set_param_type(conn, curcol, dest_type); /* use binary format for binary to char */ if (sql_src_type == SQL_C_BINARY && is_char_type(dest_type)) curcol->char_conv = NULL; #endif } if (is_numeric_type(curcol->column_type)) { curcol->column_prec = drec_ipd->sql_desc_precision; curcol->column_scale = drec_ipd->sql_desc_scale; } if (drec_ipd->sql_desc_parameter_type != SQL_PARAM_INPUT) curcol->column_output = 1; /* compute destination length */ if (curcol->column_varint_size != 0) { /* curcol->column_size = drec_apd->sql_desc_octet_length; */ /* * TODO destination length should come from sql_desc_length, * however there is the encoding problem to take into account * we should fill destination length after conversion keeping * attention to fill correctly blob/fixed type/variable type */ /* TODO location of this test is correct here ?? */ if (dest_type != SYBUNIQUE && dest_type != SYBBITN && !is_fixed_type(dest_type)) { curcol->column_cur_size = 0; curcol->column_size = drec_ipd->sql_desc_length; if (curcol->column_size < 0) { curcol->on_server.column_size = curcol->column_size = 0x7FFFFFFFl; } else { if (is_unicode_type(dest_type)) curcol->on_server.column_size = curcol->column_size * 2; else curcol->on_server.column_size = curcol->column_size; } } } else if (dest_type != SYBBIT) { /* TODO only a trick... */ tds_set_param_type(conn, curcol, tds_get_null_type(dest_type)); } /* test source type */ /* TODO test intervals */ src_type = odbc_c_to_server_type(sql_src_type); if (!src_type) { odbc_errs_add(&stmt->errs, "07006", NULL); /* Restricted data type attribute violation */ return SQL_ERROR; } /* we have no data to convert, just return */ if (!compute_row) return SQL_SUCCESS; src = drec_apd->sql_desc_data_ptr; if (src && n_row) { SQLLEN len; if (axd->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN) { len = axd->header.sql_desc_bind_type; if (axd->header.sql_desc_bind_offset_ptr) src += *axd->header.sql_desc_bind_offset_ptr; } else { len = odbc_get_octet_len(sql_src_type, drec_apd); if (len < 0) /* TODO sure ? what happen to upper layer ?? */ /* TODO fill error */ return SQL_ERROR; } src += len * n_row; } /* if only output assume input is NULL */ if (drec_ipd->sql_desc_parameter_type == SQL_PARAM_OUTPUT) { sql_len = SQL_NULL_DATA; } else { sql_len = odbc_get_param_len(drec_apd, drec_ipd, axd, n_row); /* special case, MS ODBC handle conversion from "\0" to any to NULL, DBD::ODBC require it */ if (src_type == SYBVARCHAR && sql_len == 1 && drec_ipd->sql_desc_parameter_type == SQL_PARAM_INPUT_OUTPUT && src && *src == 0) { sql_len = SQL_NULL_DATA; } } /* compute source length */ switch (sql_len) { case SQL_NULL_DATA: len = 0; break; case SQL_NTS: /* check that SQLBindParameter::ParameterValuePtr is not zero for input parameters */ if (!src) { odbc_errs_add(&stmt->errs, "HY090", NULL); return SQL_ERROR; } if (sql_src_type == SQL_C_WCHAR) len = sqlwcslen((const SQLWCHAR *) src) * sizeof(SQLWCHAR); else len = strlen(src); break; case SQL_DEFAULT_PARAM: odbc_errs_add(&stmt->errs, "07S01", NULL); /* Invalid use of default parameter */ return SQL_ERROR; break; case SQL_DATA_AT_EXEC: default: len = sql_len; if (sql_len < 0) { /* test for SQL_C_CHAR/SQL_C_BINARY */ switch (sql_src_type) { case SQL_C_CHAR: case SQL_C_WCHAR: case SQL_C_BINARY: break; default: odbc_errs_add(&stmt->errs, "HY090", NULL); return SQL_ERROR; } len = SQL_LEN_DATA_AT_EXEC(sql_len); need_data = 1; /* dynamic length allowed only for BLOB fields */ switch (drec_ipd->sql_desc_concise_type) { case SQL_LONGVARCHAR: case SQL_WLONGVARCHAR: case SQL_LONGVARBINARY: break; default: odbc_errs_add(&stmt->errs, "HY090", NULL); return SQL_ERROR; } } } /* set NULL. For NULLs we don't need to allocate row buffer so avoid it */ if (!need_data) { assert(drec_ipd->sql_desc_parameter_type != SQL_PARAM_OUTPUT || sql_len == SQL_NULL_DATA); if (sql_len == SQL_NULL_DATA) { curcol->column_cur_size = -1; return SQL_SUCCESS; } } switch (dest_type) { case SYBCHAR: case SYBVARCHAR: case XSYBCHAR: case XSYBVARCHAR: case XSYBNVARCHAR: case XSYBNCHAR: case SYBNVARCHAR: case SYBNTEXT: case SYBTEXT: if (!need_data && (sql_src_type == SQL_C_CHAR || sql_src_type == SQL_C_WCHAR || sql_src_type == SQL_C_BINARY)) { if (curcol->column_data && curcol->column_data_free) curcol->column_data_free(curcol); curcol->column_data_free = NULL; if (is_blob_col(curcol)) { /* trick to set blob without freeing it, _odbc_blob_free does not free TDSBLOB->textvalue */ TDSBLOB *blob = (TDSBLOB *) calloc(1, sizeof(TDSBLOB)); if (!blob) { odbc_errs_add(&stmt->errs, "HY001", NULL); return SQL_ERROR; } blob->textvalue = src; curcol->column_data = (TDS_UCHAR*) blob; curcol->column_data_free = _odbc_blob_free; } else { curcol->column_data = (TDS_UCHAR*) src; } curcol->column_size = len; curcol->column_cur_size = len; return SQL_SUCCESS; } } /* allocate given space */ if (!tds_alloc_param_data(curcol)) { odbc_errs_add(&stmt->errs, "HY001", NULL); return SQL_ERROR; } /* fill data with SQLPutData */ if (need_data) { curcol->column_cur_size = 0; return SQL_NEED_DATA; } if (!src) { odbc_errs_add(&stmt->errs, "HY090", NULL); return SQL_ERROR; } /* convert special parameters (not libTDS compatible) */ switch (src_type) { case SYBMSDATETIME2: convert_datetime2server(drec_apd->sql_desc_concise_type, src, &dta); src = (char *) &dta; break; case SYBDECIMAL: case SYBNUMERIC: sql_num = (SQL_NUMERIC_STRUCT *) src; num.precision = sql_num->precision; num.scale = sql_num->scale; num.array[0] = sql_num->sign ^ 1; /* test precision so client do not crash our library */ if (num.precision <= 0 || num.precision > 38 || num.scale > num.precision) /* TODO add proper error */ return SQL_ERROR; i = tds_numeric_bytes_per_prec[num.precision]; memcpy(num.array + 1, sql_num->val, i - 1); tds_swap_bytes(num.array + 1, i - 1); if (i < sizeof(num.array)) memset(num.array + i, 0, sizeof(num.array) - i); src = (char *) # break; /* TODO intervals */ } converted_src = NULL; if (sql_src_type == SQL_C_WCHAR) { converted_src = src = odbc_wstr2str(stmt, src, &len); if (!src) return SQL_ERROR; src_type = SYBVARCHAR; } dest = curcol->column_data; switch ((TDS_SERVER_TYPE) dest_type) { case SYBCHAR: case SYBVARCHAR: case XSYBCHAR: case XSYBVARCHAR: case XSYBNVARCHAR: case XSYBNCHAR: case SYBNVARCHAR: ores.cc.c = (TDS_CHAR*) dest; ores.cc.len = curcol->column_size; res = tds_convert(dbc->env->tds_ctx, src_type, src, len, TDS_CONVERT_CHAR, &ores); if (res > curcol->column_size) res = curcol->column_size; break; case SYBBINARY: case SYBVARBINARY: case XSYBBINARY: case XSYBVARBINARY: ores.cb.ib = (TDS_CHAR*) dest; ores.cb.len = curcol->column_size; res = tds_convert(dbc->env->tds_ctx, src_type, src, len, TDS_CONVERT_BINARY, &ores); if (res > curcol->column_size) res = curcol->column_size; break; case SYBNTEXT: dest_type = SYBTEXT; case SYBTEXT: case SYBLONGBINARY: case SYBIMAGE: res = tds_convert(dbc->env->tds_ctx, src_type, src, len, dest_type, &ores); if (res >= 0) { blob = (TDSBLOB *) dest; free(blob->textvalue); blob->textvalue = ores.ib; } break; case SYBNUMERIC: case SYBDECIMAL: ((TDS_NUMERIC *) dest)->precision = drec_ipd->sql_desc_precision; ((TDS_NUMERIC *) dest)->scale = drec_ipd->sql_desc_scale; case SYBINTN: case SYBINT1: case SYBINT2: case SYBINT4: case SYBINT8: case SYBFLT8: case SYBDATETIME: case SYBBIT: case SYBMONEY4: case SYBMONEY: case SYBDATETIME4: case SYBREAL: case SYBBITN: case SYBFLTN: case SYBMONEYN: case SYBDATETIMN: case SYBSINT1: case SYBUINT2: case SYBUINT4: case SYBUINT8: case SYBUNIQUE: case SYBMSTIME: case SYBMSDATE: case SYBMSDATETIME2: case SYBMSDATETIMEOFFSET: res = tds_convert(dbc->env->tds_ctx, src_type, src, len, dest_type, (CONV_RESULT*) dest); break; default: case SYBVOID: case SYBVARIANT: /* TODO ODBC 3.5 */ assert(0); res = -1; break; } free(converted_src); if (res < 0) { odbc_convert_err_set(&stmt->errs, res); return SQL_ERROR; } curcol->column_cur_size = res; return SQL_SUCCESS; }
void sql_blobInsert(const char *tabname, const char *colname, int rowid, const char *filename, void *offset, int length) { char blobcmd[100]; SQLINTEGER output_length; bool isfile; int fd; /* basic sanity checks */ checkConnect(); if(isnullstring(tabname)) errorPrint("2blobInsert, null table name"); if(isnullstring(colname)) errorPrint("2blobInsert, null column name"); if(rowid <= 0) errorPrint("2invalid rowid in blobInsert"); if(length < 0) errorPrint("2invalid length in blobInsert"); if(strlen(tabname) + strlen(colname) + 42 >= sizeof (blobcmd)) errorPrint("@internal blobInsert command too long"); isfile = true; if(isnullstring(filename)) { isfile = false; if(!offset) errorPrint("2blobInsert is given null filename and null buffer"); } else { offset = blobbuf; fd = eopen(filename, O_RDONLY | O_BINARY, 0); length = fileSizeByHandle(fd); if(length == 0) { isfile = false; close(fd); } } /* set up the blob insert command, using one host variable */ sprintf(blobcmd, "update %s set %s = %s where rowid = %d", tabname, colname, (length ? "?" : "NULL"), rowid); stmt_text = blobcmd; debugStatement(); newStatement(); rv_lastNrows = 0; output_length = length; rc = SQL_SUCCESS; if(isfile) { output_length = SQL_LEN_DATA_AT_EXEC(length); rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARCHAR, length, 0, blobcmd, length, &output_length); if(rc) close(fd); } else if(length) { rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARCHAR, length, 0, offset, length, &output_length); } if(errorTrap(0)) { SQLFreeHandle(SQL_HANDLE_STMT, hstmt); return; } rc = SQLExecDirect(hstmt, blobcmd, SQL_NTS); SQLRowCount(hstmt, &rv_lastNrows); if(isfile) { if(rc != SQL_NEED_DATA) { close(fd); if(rc == SQL_SUCCESS) errorPrint("@blobInsert expected SQL_NEED_DATA"); errorTrap(0); SQLFreeHandle(SQL_HANDLE_STMT, hstmt); return; } output_length = 0; rc = SQLParamData(hstmt, (void **)&output_length); if((char *)output_length != blobcmd) { close(fd); errorPrint("2blobInsert got bad key from SQLParamData"); } lseek(fd, 0L, 0); while(length) { int n = length; if(n > sizeof (blobbuf)) n = sizeof (blobbuf); if(read(fd, blobbuf, n) != n) { close(fd); errorPrint("2cannot read file %s, errno %d", filename, errno); } length -= n; rc = SQLPutData(hstmt, blobbuf, n); if(rc) { close(fd); errorTrap(0); SQLFreeHandle(SQL_HANDLE_STMT, hstmt); return; } } /* loop reading the file */ close(fd); /* since there are no more exec-time parameters, * this call completes the execution of the SQL statement. */ rc = SQLParamData(hstmt, (void **)&output_length); } if(errorTrap(0)) { SQLFreeHandle(SQL_HANDLE_STMT, hstmt); return; } if(sql_debug) appendFile(sql_debuglog, "%d rows affected", rv_lastNrows); if(sql_debug2) printf("%d rows affected\n", rv_lastNrows); SQLFreeHandle(SQL_HANDLE_STMT, hstmt); exclist = 0; } /* sql_blobInsert */