473 lines
12 KiB
C
473 lines
12 KiB
C
/*-------
|
|
* 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 <stdio.h>
|
|
#include <string.h>
|
|
|
|
#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;
|
|
}
|