/*------- * Module: odbcapi30w.c * * Description: This module contains UNICODE routines * * Classes: n/a * * API functions: SQLColAttributeW, SQLGetStmtAttrW, SQLSetStmtAttrW, SQLSetConnectAttrW, SQLGetConnectAttrW, SQLGetDescFieldW, SQLGetDescRecW, SQLGetDiagFieldW, SQLGetDiagRecW, *------- */ #include "psqlodbc.h" #include "unicode_support.h" #include #include #include "pgapifunc.h" #include "connection.h" #include "statement.h" #include "misc.h" RETCODE SQL_API SQLGetStmtAttrW(SQLHSTMT hstmt, SQLINTEGER fAttribute, PTR rgbValue, SQLINTEGER cbValueMax, SQLINTEGER *pcbValue) { RETCODE ret; StatementClass *stmt = (StatementClass *) hstmt; MYLOG(0, "Entering\n"); ENTER_STMT_CS((StatementClass *) hstmt); SC_clear_error((StatementClass *) hstmt); StartRollbackState(stmt); ret = PGAPI_GetStmtAttr(hstmt, fAttribute, rgbValue, cbValueMax, pcbValue); ret = DiscardStatementSvp(stmt, ret, FALSE); LEAVE_STMT_CS((StatementClass *) hstmt); return ret; } RETCODE SQL_API SQLSetStmtAttrW(SQLHSTMT hstmt, SQLINTEGER fAttribute, PTR rgbValue, SQLINTEGER cbValueMax) { RETCODE ret; StatementClass *stmt = (StatementClass *) hstmt; MYLOG(0, "Entering\n"); ENTER_STMT_CS(stmt); SC_clear_error(stmt); StartRollbackState(stmt); ret = PGAPI_SetStmtAttr(hstmt, fAttribute, rgbValue, cbValueMax); ret = DiscardStatementSvp(stmt, ret, FALSE); LEAVE_STMT_CS(stmt); return ret; } RETCODE SQL_API SQLGetConnectAttrW(HDBC hdbc, SQLINTEGER fAttribute, PTR rgbValue, SQLINTEGER cbValueMax, SQLINTEGER *pcbValue) { RETCODE ret; MYLOG(0, "Entering\n"); CC_examine_global_transaction((ConnectionClass *) hdbc); ENTER_CONN_CS((ConnectionClass *) hdbc); CC_clear_error((ConnectionClass *) hdbc); ret = PGAPI_GetConnectAttr(hdbc, fAttribute, rgbValue, cbValueMax, pcbValue); LEAVE_CONN_CS((ConnectionClass *) hdbc); return ret; } RETCODE SQL_API SQLSetConnectAttrW(HDBC hdbc, SQLINTEGER fAttribute, PTR rgbValue, SQLINTEGER cbValue) { RETCODE ret; ConnectionClass *conn = (ConnectionClass *) hdbc; MYLOG(0, "Entering\n"); CC_examine_global_transaction(conn); ENTER_CONN_CS(conn); CC_clear_error(conn); CC_set_in_unicode_driver(conn); ret = PGAPI_SetConnectAttr(hdbc, fAttribute, rgbValue, cbValue); LEAVE_CONN_CS(conn); return ret; } /* new function */ RETCODE SQL_API SQLSetDescFieldW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, SQLINTEGER BufferLength) { RETCODE ret; SQLLEN vallen; char *uval = NULL; BOOL val_alloced = FALSE; MYLOG(0, "Entering\n"); if (BufferLength > 0 || SQL_NTS == BufferLength) { switch (FieldIdentifier) { case SQL_DESC_BASE_COLUMN_NAME: case SQL_DESC_BASE_TABLE_NAME: case SQL_DESC_CATALOG_NAME: case SQL_DESC_LABEL: case SQL_DESC_LITERAL_PREFIX: case SQL_DESC_LITERAL_SUFFIX: case SQL_DESC_LOCAL_TYPE_NAME: case SQL_DESC_NAME: case SQL_DESC_SCHEMA_NAME: case SQL_DESC_TABLE_NAME: case SQL_DESC_TYPE_NAME: uval = ucs2_to_utf8(Value, BufferLength > 0 ? BufferLength / WCLEN : BufferLength, &vallen, FALSE); val_alloced = TRUE; break; } } if (!val_alloced) { uval = Value; vallen = BufferLength; } ret = PGAPI_SetDescField(DescriptorHandle, RecNumber, FieldIdentifier, uval, (SQLINTEGER) vallen); if (val_alloced) free(uval); return ret; } RETCODE SQL_API SQLGetDescFieldW(SQLHDESC hdesc, SQLSMALLINT iRecord, SQLSMALLINT iField, PTR rgbValue, SQLINTEGER cbValueMax, SQLINTEGER *pcbValue) { RETCODE ret; SQLINTEGER blen = 0, bMax, *pcbV; char *rgbV = NULL, *rgbVt; MYLOG(0, "Entering\n"); if(cbValueMax < 0) { mylog("cbValueMax should be non-negative\n"); return SQL_ERROR; } switch (iField) { case SQL_DESC_BASE_COLUMN_NAME: case SQL_DESC_BASE_TABLE_NAME: case SQL_DESC_CATALOG_NAME: case SQL_DESC_LABEL: case SQL_DESC_LITERAL_PREFIX: case SQL_DESC_LITERAL_SUFFIX: case SQL_DESC_LOCAL_TYPE_NAME: case SQL_DESC_NAME: case SQL_DESC_SCHEMA_NAME: case SQL_DESC_TABLE_NAME: case SQL_DESC_TYPE_NAME: bMax = cbValueMax * 3 / WCLEN; rgbV = malloc(bMax + 1); if (!rgbV) { mylog("out of memory\n"); DC_set_error(hdesc, DESC_NO_MEMORY_ERROR, "Out of memory while allocating memory for rgbV."); return SQL_ERROR; } pcbV = &blen; for (rgbVt = rgbV;; bMax = blen + 1, rgbVt = realloc(rgbV, bMax)) { if (!rgbVt) { ret = SQL_ERROR; break; } rgbV = rgbVt; ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbV, bMax, pcbV); if (SQL_SUCCESS_WITH_INFO != ret || blen < bMax) break; } if (SQL_SUCCEEDED(ret)) { blen = (SQLINTEGER) utf8_to_ucs2(rgbV, blen, (SQLWCHAR *) rgbValue, cbValueMax / WCLEN); if (SQL_SUCCESS == ret && blen * WCLEN >= cbValueMax) { ret = SQL_SUCCESS_WITH_INFO; DC_set_error(hdesc, STMT_TRUNCATED, "The buffer was too small for the rgbDesc."); } if (pcbValue) *pcbValue = blen * WCLEN; } if (rgbV) free(rgbV); break; default: rgbV = rgbValue; bMax = cbValueMax; pcbV = pcbValue; ret = PGAPI_GetDescField(hdesc, iRecord, iField, rgbV, bMax, pcbV); break; } return ret; } RETCODE SQL_API SQLGetDiagRecW(SQLSMALLINT fHandleType, SQLHANDLE handle, SQLSMALLINT iRecord, SQLWCHAR *szSqlState, SQLINTEGER *pfNativeError, SQLWCHAR *szErrorMsg, SQLSMALLINT cbErrorMsgMax, SQLSMALLINT *pcbErrorMsg) { RETCODE ret; SQLSMALLINT buflen, tlen; char qstr_ansi[8], *mtxt = NULL; MYLOG(0, "Entering\n"); buflen = 0; if (szErrorMsg && cbErrorMsgMax > 0) { buflen = cbErrorMsgMax; mtxt = malloc(buflen); } ret = PGAPI_GetDiagRec(fHandleType, handle, iRecord, (SQLCHAR *) qstr_ansi, pfNativeError, (SQLCHAR *) mtxt, buflen, &tlen); if (SQL_SUCCEEDED(ret)) { if (szSqlState) utf8_to_ucs2(qstr_ansi, -1, szSqlState, 6); if (mtxt && tlen <= cbErrorMsgMax) { SQLULEN ulen = utf8_to_ucs2_lf(mtxt, tlen, FALSE, szErrorMsg, cbErrorMsgMax, TRUE); if (ulen == (SQLULEN) -1) tlen = (SQLSMALLINT) locale_to_sqlwchar((SQLWCHAR *) szErrorMsg, mtxt, cbErrorMsgMax, FALSE); else tlen = (SQLSMALLINT) ulen; if (tlen >= cbErrorMsgMax) ret = SQL_SUCCESS_WITH_INFO; else if (tlen < 0) { char errc[32]; SPRINTF_FIXED(errc, "Error: SqlState=%s", qstr_ansi); tlen = utf8_to_ucs2(errc, -1, szErrorMsg, cbErrorMsgMax); } } if (pcbErrorMsg) *pcbErrorMsg = tlen; } if (mtxt) free(mtxt); return ret; } SQLRETURN SQL_API SQLColAttributeW(SQLHSTMT hstmt, SQLUSMALLINT iCol, SQLUSMALLINT iField, SQLPOINTER pCharAttr, SQLSMALLINT cbCharAttrMax, SQLSMALLINT *pcbCharAttr, #if defined(_WIN64) || defined(SQLCOLATTRIBUTE_SQLLEN) SQLLEN *pNumAttr #else SQLPOINTER pNumAttr #endif ) { CSTR func = "SQLColAttributeW"; RETCODE ret; StatementClass *stmt = (StatementClass *) hstmt; SQLSMALLINT *rgbL, blen = 0, bMax; char *rgbD = NULL, *rgbDt; MYLOG(0, "Entering\n"); if (SC_connection_lost_check(stmt, __FUNCTION__)) return SQL_ERROR; ENTER_STMT_CS(stmt); SC_clear_error(stmt); StartRollbackState(stmt); switch (iField) { case SQL_DESC_BASE_COLUMN_NAME: case SQL_DESC_BASE_TABLE_NAME: case SQL_DESC_CATALOG_NAME: case SQL_DESC_LABEL: case SQL_DESC_LITERAL_PREFIX: case SQL_DESC_LITERAL_SUFFIX: case SQL_DESC_LOCAL_TYPE_NAME: case SQL_DESC_NAME: case SQL_DESC_SCHEMA_NAME: case SQL_DESC_TABLE_NAME: case SQL_DESC_TYPE_NAME: case SQL_COLUMN_NAME: if (cbCharAttrMax <= 0) { char errmsg[1024]; snprintf(errmsg, sizeof(errmsg), "Invalid BufferLength value %d for FieldIdentifier %d", cbCharAttrMax, iField); SC_set_error(stmt, STMT_INVALID_NULL_ARG, errmsg, func); mylog("Invalid BufferLength value %d for FieldIdentifier %d", cbCharAttrMax, iField); LEAVE_STMT_CS(stmt); return SQL_ERROR; } bMax = cbCharAttrMax * 3 / WCLEN; rgbD = malloc(bMax); rgbL = &blen; for (rgbDt = rgbD;; bMax = blen + 1, rgbDt = realloc(rgbD, bMax)) { if (!rgbDt) { ret = SQL_ERROR; break; } rgbD = rgbDt; ret = PGAPI_ColAttributes(hstmt, iCol, iField, rgbD, bMax, rgbL, pNumAttr); if (SQL_SUCCESS_WITH_INFO != ret || blen < bMax) break; } if (SQL_SUCCEEDED(ret)) { blen = (SQLSMALLINT) utf8_to_ucs2(rgbD, blen, (SQLWCHAR *) pCharAttr, cbCharAttrMax / WCLEN); if (SQL_SUCCESS == ret && blen * WCLEN >= cbCharAttrMax) { ret = SQL_SUCCESS_WITH_INFO; SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the pCharAttr.", func); } if (pcbCharAttr) *pcbCharAttr = blen * WCLEN; } if (rgbD) free(rgbD); break; default: rgbD = pCharAttr; bMax = cbCharAttrMax; rgbL = pcbCharAttr; ret = PGAPI_ColAttributes(hstmt, iCol, iField, rgbD, bMax, rgbL, pNumAttr); break; } ret = DiscardStatementSvp(stmt, ret, FALSE); LEAVE_STMT_CS(stmt); return ret; } RETCODE SQL_API SQLGetDiagFieldW(SQLSMALLINT fHandleType, SQLHANDLE handle, SQLSMALLINT iRecord, SQLSMALLINT fDiagField, SQLPOINTER rgbDiagInfo, SQLSMALLINT cbDiagInfoMax, SQLSMALLINT *pcbDiagInfo) { RETCODE ret; SQLSMALLINT *rgbL, blen = 0, bMax; char *rgbD = NULL, *rgbDt; MYLOG(0, "Entering Handle=(%u,%p) Rec=%d Id=%d info=(%p,%d)\n", fHandleType, handle, iRecord, fDiagField, rgbDiagInfo, cbDiagInfoMax); if(cbDiagInfoMax < 0) { mylog("cbDiagInfoMax should be non-negative\n"); return SQL_ERROR; } switch (fDiagField) { case SQL_DIAG_DYNAMIC_FUNCTION: case SQL_DIAG_CLASS_ORIGIN: case SQL_DIAG_CONNECTION_NAME: case SQL_DIAG_MESSAGE_TEXT: case SQL_DIAG_SERVER_NAME: case SQL_DIAG_SQLSTATE: case SQL_DIAG_SUBCLASS_ORIGIN: bMax = cbDiagInfoMax * 3 / WCLEN + 1; if (rgbD = malloc(bMax), !rgbD) return SQL_ERROR; rgbL = &blen; for (rgbDt = rgbD;; bMax = blen + 1, rgbDt = realloc(rgbD, bMax)) { if (!rgbDt) { free(rgbD); return SQL_ERROR; } rgbD = rgbDt; ret = PGAPI_GetDiagField(fHandleType, handle, iRecord, fDiagField, rgbD, bMax, rgbL); if (SQL_SUCCESS_WITH_INFO != ret || blen < bMax) break; } if (SQL_SUCCEEDED(ret)) { SQLULEN ulen = (SQLSMALLINT) utf8_to_ucs2_lf(rgbD, blen, FALSE, (SQLWCHAR *) rgbDiagInfo, cbDiagInfoMax / WCLEN, TRUE); if (ulen == (SQLULEN) -1) blen = (SQLSMALLINT) locale_to_sqlwchar((SQLWCHAR *) rgbDiagInfo, rgbD, cbDiagInfoMax / WCLEN, FALSE); else blen = (SQLSMALLINT) ulen; if (SQL_SUCCESS == ret && blen * WCLEN >= cbDiagInfoMax) ret = SQL_SUCCESS_WITH_INFO; if (pcbDiagInfo) { *pcbDiagInfo = blen * WCLEN; } } if (rgbD) free(rgbD); break; default: rgbD = rgbDiagInfo; bMax = cbDiagInfoMax; rgbL = pcbDiagInfo; ret = PGAPI_GetDiagField(fHandleType, handle, iRecord, fDiagField, rgbD, bMax, rgbL); break; } return ret; } /* new function */ RETCODE SQL_API SQLGetDescRecW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLWCHAR *Name, SQLSMALLINT BufferLength, SQLSMALLINT *StringLength, SQLSMALLINT *Type, SQLSMALLINT *SubType, SQLLEN *Length, SQLSMALLINT *Precision, SQLSMALLINT *Scale, SQLSMALLINT *Nullable) { MYLOG(0, "Entering\n"); MYLOG(0, "Error not implemented\n"); return SQL_ERROR; } /* new fucntion */ RETCODE SQL_API SQLSetDescRecW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT Type, SQLSMALLINT SubType, SQLLEN Length, SQLSMALLINT Precision, SQLSMALLINT Scale, PTR Data, SQLLEN *StringLength, SQLLEN *Indicator) { MYLOG(0, "Entering\n"); MYLOG(0, "Error not implemented\n"); return SQL_ERROR; }