diff --git a/odbcapi30.c b/odbcapi30.c index 9d3662d..7ed8165 100644 --- a/odbcapi30.c +++ b/odbcapi30.c @@ -313,7 +313,35 @@ SQLGetDescField(SQLHDESC DescriptorHandle, return ret; } -/* new function */ +/* + * SQLGetDescRec + * + * Description: + * This function retrieves the current settings or values of fields in a descriptor record. + * It's the ANSI version of the function that works with descriptor records. + * + * Parameters: + * DescriptorHandle - Handle to the descriptor + * RecNumber - The descriptor record number (1-based) + * Name - Buffer to store the descriptor name (ANSI) + * BufferLength - Length of the Name buffer in bytes + * StringLength - Pointer to store the actual length of the name + * Type - Pointer to store the SQL data type + * SubType - Pointer to store the data type subcode + * Length - Pointer to store the data length + * Precision - Pointer to store the numeric precision + * Scale - Pointer to store the numeric scale + * Nullable - Pointer to store the nullability attribute + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Comments: + * This function is a thin wrapper around PGAPI_GetDescRec, which contains + * the actual implementation. Unlike the wide-character version (SQLGetDescRecW), + * this function doesn't need to perform character set conversion since it + * works directly with ANSI strings. + */ RETCODE SQL_API SQLGetDescRec(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLCHAR *Name, @@ -326,9 +354,11 @@ SQLGetDescRec(SQLHDESC DescriptorHandle, MYLOG(0, "Entering h=%p rec=%d name=%p blen=%d\n", DescriptorHandle, RecNumber, Name, BufferLength); MYLOG(0, "str=%p type=%p sub=%p len=%p prec=%p scale=%p null=%p\n", StringLength, Type, SubType, Length, Precision, Scale, Nullable); + ret = PGAPI_GetDescRec(DescriptorHandle, RecNumber, Name, BufferLength, StringLength, Type, SubType, Length, Precision, Scale, Nullable); + return ret; } @@ -416,7 +446,28 @@ SQLGetConnectAttr(HDBC ConnectionHandle, return ret; } -/* SQLGetStmtOption -> SQLGetStmtAttr */ +/* + * SQLGetStmtAttr + * + * Description: + * This function retrieves the current setting of a statement attribute. + * This is the ANSI version of the function. + * + * Parameters: + * StatementHandle - Handle to the statement + * Attribute - The attribute to retrieve (SQL_ATTR_* constant) + * Value - Buffer to store the attribute value + * BufferLength - Length of the Value buffer in bytes + * StringLength - Pointer to store the actual length of string data + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Comments: + * This function replaces the deprecated SQLGetStmtOption function. + * It provides thread-safe access to statement attributes by using + * critical sections to protect shared resources. + */ RETCODE SQL_API SQLGetStmtAttr(HSTMT StatementHandle, SQLINTEGER Attribute, PTR Value, @@ -426,13 +477,20 @@ SQLGetStmtAttr(HSTMT StatementHandle, StatementClass *stmt = (StatementClass *) StatementHandle; MYLOG(0, "Entering Handle=%p " FORMAT_INTEGER "\n", StatementHandle, Attribute); + ENTER_STMT_CS(stmt); + SC_clear_error(stmt); + StartRollbackState(stmt); + ret = PGAPI_GetStmtAttr(StatementHandle, Attribute, Value, BufferLength, StringLength); - ret = DiscardStatementSvp(stmt,ret, FALSE); + + ret = DiscardStatementSvp(stmt, ret, FALSE); + LEAVE_STMT_CS(stmt); + return ret; } @@ -455,7 +513,27 @@ SQLSetConnectAttr(HDBC ConnectionHandle, return ret; } -/* new function */ +/* + * SQLSetDescField + * + * Description: + * This function sets the value of a field in a descriptor record. + * This is the ANSI version of the function. + * + * Parameters: + * DescriptorHandle - Handle to the descriptor + * RecNumber - The descriptor record number (1-based, 0 for header fields) + * FieldIdentifier - The field identifier (SQL_DESC_* constant) + * Value - The value to set for the field + * BufferLength - Length of the Value buffer in bytes (for string data) + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Comments: + * This function simply passes through to the core implementation function + * PGAPI_SetDescField without any additional processing. + */ RETCODE SQL_API SQLSetDescField(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, @@ -464,12 +542,39 @@ SQLSetDescField(SQLHDESC DescriptorHandle, RETCODE ret; MYLOG(0, "Entering h=%p rec=%d field=%d val=%p\n", DescriptorHandle, RecNumber, FieldIdentifier, Value); + ret = PGAPI_SetDescField(DescriptorHandle, RecNumber, FieldIdentifier, Value, BufferLength); + return ret; } -/* new function */ +/* + * SQLSetDescRec + * + * Description: + * This function sets multiple descriptor fields with a single call. + * This is the ANSI version of the function. + * + * Parameters: + * DescriptorHandle - Handle to the descriptor + * RecNumber - The descriptor record number (1-based) + * Type - SQL data type + * SubType - Datetime or interval subcode + * Length - Maximum data length + * Precision - Precision of numeric types + * Scale - Scale of numeric types + * Data - Pointer to data buffer + * StringLength - Pointer to buffer length + * Indicator - Pointer to indicator variable + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Comments: + * This function provides a more efficient way to set multiple descriptor + * fields that are commonly used together. + */ RETCODE SQL_API SQLSetDescRec(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT Type, @@ -482,9 +587,11 @@ SQLSetDescRec(SQLHDESC DescriptorHandle, MYLOG(0, "Entering h=%p rec=%d type=%d sub=%d len=" FORMAT_LEN " prec=%d scale=%d data=%p\n", DescriptorHandle, RecNumber, Type, SubType, Length, Precision, Scale, Data); MYLOG(0, "str=%p ind=%p\n", StringLength, Indicator); + ret = PGAPI_SetDescRec(DescriptorHandle, RecNumber, Type, SubType, Length, Precision, Scale, Data, StringLength, Indicator); + return ret; } #endif /* UNICODE_SUPPORTXX */ @@ -550,7 +657,27 @@ SQLSetEnvAttr(HENV EnvironmentHandle, } #ifndef UNICODE_SUPPORTXX -/* SQLSet(Param/Scroll/Stmt)Option -> SQLSetStmtAttr */ +/* + * SQLSetStmtAttr + * + * Description: + * This function sets the current setting of a statement attribute. + * This is the ANSI version of the function. + * + * Parameters: + * StatementHandle - Handle to the statement + * Attribute - The attribute to set (SQL_ATTR_* constant) + * Value - The value to set for the attribute + * StringLength - Length of the Value buffer in bytes (for string data) + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Comments: + * This function replaces the deprecated SQLSetStmtOption function. + * It provides thread-safe access to statement attributes by using + * critical sections to protect shared resources. + */ RETCODE SQL_API SQLSetStmtAttr(HSTMT StatementHandle, SQLINTEGER Attribute, PTR Value, @@ -560,12 +687,21 @@ SQLSetStmtAttr(HSTMT StatementHandle, RETCODE ret; MYLOG(0, "Entering Handle=%p " FORMAT_INTEGER "," FORMAT_ULEN "\n", StatementHandle, Attribute, (SQLULEN) Value); + ENTER_STMT_CS(stmt); + SC_clear_error(stmt); + StartRollbackState(stmt); + + /* Call the core implementation function */ ret = PGAPI_SetStmtAttr(StatementHandle, Attribute, Value, StringLength); - ret = DiscardStatementSvp(stmt,ret, FALSE); + + /* Handle transaction state and cleanup */ + ret = DiscardStatementSvp(stmt, ret, FALSE); + LEAVE_STMT_CS(stmt); + return ret; } #endif /* UNICODE_SUPPORTXX */ diff --git a/odbcapi30w.c b/odbcapi30w.c index ec21aea..182e7c2 100644 --- a/odbcapi30w.c +++ b/odbcapi30w.c @@ -23,6 +23,29 @@ #include "misc.h" +/* + * SQLGetStmtAttrW + * + * Description: + * This function retrieves the current setting of a statement attribute. + * This is the Unicode (wide-character) version of SQLGetStmtAttr. + * + * Parameters: + * hstmt - Handle to the statement + * fAttribute - The attribute to retrieve (SQL_ATTR_* constant) + * rgbValue - Buffer to store the attribute value + * cbValueMax - Length of the rgbValue buffer in bytes + * pcbValue - Pointer to store the actual length of string data + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Comments: + * Unlike some other Unicode functions, this function doesn't need to perform + * character set conversion since statement attributes are not string-based + * or already handle Unicode conversion internally. It simply passes through + * to the core implementation function PGAPI_GetStmtAttr. + */ RETCODE SQL_API SQLGetStmtAttrW(SQLHSTMT hstmt, SQLINTEGER fAttribute, @@ -34,16 +57,46 @@ SQLGetStmtAttrW(SQLHSTMT hstmt, StatementClass *stmt = (StatementClass *) hstmt; MYLOG(0, "Entering\n"); + ENTER_STMT_CS((StatementClass *) hstmt); + SC_clear_error((StatementClass *) hstmt); + + /* Set up savepoint for transaction safety */ StartRollbackState(stmt); + ret = PGAPI_GetStmtAttr(hstmt, fAttribute, rgbValue, cbValueMax, pcbValue); + ret = DiscardStatementSvp(stmt, ret, FALSE); + LEAVE_STMT_CS((StatementClass *) hstmt); + return ret; } +/* + * SQLSetStmtAttrW + * + * Description: + * This function sets the current setting of a statement attribute. + * This is the Unicode (wide-character) version of SQLSetStmtAttr. + * + * Parameters: + * hstmt - Handle to the statement + * fAttribute - The attribute to set (SQL_ATTR_* constant) + * rgbValue - The value to set for the attribute + * cbValueMax - Length of the rgbValue buffer in bytes (for string data) + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Comments: + * Unlike some other Unicode functions, this function doesn't need to perform + * character set conversion since statement attributes are not string-based + * or already handle Unicode conversion internally. It simply passes through + * to the core implementation function PGAPI_SetStmtAttr. + */ RETCODE SQL_API SQLSetStmtAttrW(SQLHSTMT hstmt, SQLINTEGER fAttribute, @@ -54,13 +107,21 @@ SQLSetStmtAttrW(SQLHSTMT hstmt, StatementClass *stmt = (StatementClass *) hstmt; MYLOG(0, "Entering\n"); + ENTER_STMT_CS(stmt); + SC_clear_error(stmt); + + /* Set up savepoint for transaction safety */ StartRollbackState(stmt); + ret = PGAPI_SetStmtAttr(hstmt, fAttribute, rgbValue, cbValueMax); + ret = DiscardStatementSvp(stmt, ret, FALSE); + LEAVE_STMT_CS(stmt); + return ret; } @@ -103,7 +164,27 @@ SQLSetConnectAttrW(HDBC hdbc, return ret; } -/* new function */ +/* + * SQLSetDescFieldW + * + * Description: + * This function sets the value of a field in a descriptor record. + * This is the Unicode (wide-character) version of SQLSetDescField. + * + * Parameters: + * DescriptorHandle - Handle to the descriptor + * RecNumber - The descriptor record number (1-based, 0 for header fields) + * FieldIdentifier - The field identifier (SQL_DESC_* constant) + * Value - The value to set for the field + * BufferLength - Length of the Value buffer in bytes (for string data) + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Comments: + * This function handles Unicode to UTF-8 conversion for string fields + * before calling the core implementation function PGAPI_SetDescField. + */ RETCODE SQL_API SQLSetDescFieldW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, PTR Value, @@ -111,10 +192,12 @@ SQLSetDescFieldW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, { RETCODE ret; SQLLEN vallen; - char *uval = NULL; + char *uval = NULL; BOOL val_alloced = FALSE; MYLOG(0, "Entering\n"); + + /* Convert Unicode strings to UTF-8 for specific string fields */ if (BufferLength > 0 || SQL_NTS == BufferLength) { switch (FieldIdentifier) @@ -135,15 +218,21 @@ SQLSetDescFieldW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, break; } } + + /* For non-string fields or if conversion wasn't needed, use the original value */ if (!val_alloced) { uval = Value; vallen = BufferLength; } + ret = PGAPI_SetDescField(DescriptorHandle, RecNumber, FieldIdentifier, uval, (SQLINTEGER) vallen); + + /* Free the converted string if we allocated one */ if (val_alloced) free(uval); + return ret; } @@ -417,7 +506,29 @@ SQLGetDiagFieldW(SQLSMALLINT fHandleType, return ret; } -/* new function */ +/* + * SQLGetDescRecW + * + * Description: + * This function retrieves the current settings or values of fields in a descriptor record. + * It's the wide-character (Unicode) version of SQLGetDescRec. + * + * Parameters: + * DescriptorHandle - Handle to the descriptor + * RecNumber - The descriptor record number (1-based) + * Name - Buffer to store the descriptor name (Unicode) + * BufferLength - Length of the Name buffer in characters + * StringLength - Pointer to store the actual length of the name + * Type - Pointer to store the SQL data type + * SubType - Pointer to store the data type subcode + * Length - Pointer to store the data length + * Precision - Pointer to store the numeric precision + * Scale - Pointer to store the numeric scale + * Nullable - Pointer to store the nullability attribute + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + */ RETCODE SQL_API SQLGetDescRecW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLWCHAR *Name, @@ -427,39 +538,78 @@ SQLGetDescRecW(SQLHDESC DescriptorHandle, SQLSMALLINT *Scale, SQLSMALLINT *Nullable) { RETCODE ret; - char *NameA = NULL; - SQLSMALLINT nlen; + char *NameA = NULL; /* Temporary buffer for ANSI version of name */ + SQLSMALLINT nlen; /* Length of the name string */ MYLOG(0, "Entering h=%p rec=%d name=%p blen=%d\n", DescriptorHandle, RecNumber, Name, BufferLength); MYLOG(0, "str=%p type=%p sub=%p len=%p prec=%p scale=%p null=%p\n", StringLength, Type, SubType, Length, Precision, Scale, Nullable); + /* Allocate temporary buffer for ANSI version if buffer length is provided */ if (BufferLength > 0) NameA = malloc(BufferLength); + /* Call the core implementation with ANSI parameters */ ret = PGAPI_GetDescRec(DescriptorHandle, RecNumber, (SQLCHAR *) NameA, BufferLength, &nlen, Type, SubType, Length, Precision, Scale, Nullable); + if (SQL_SUCCEEDED(ret)) { + /* Convert ANSI name to Unicode if we have a valid name and buffer */ if (NameA && nlen <= BufferLength) { + /* Try UTF-8 to UCS-2 conversion first */ SQLULEN ulen = utf8_to_ucs2_lf(NameA, nlen, FALSE, Name, BufferLength, TRUE); + if (ulen == (SQLULEN) -1) + /* Fall back to locale-based conversion if UTF-8 conversion fails */ nlen = (SQLSMALLINT) locale_to_sqlwchar((SQLWCHAR *) Name, NameA, BufferLength, FALSE); else nlen = (SQLSMALLINT) ulen; + + /* If the name was truncated, return success with info */ if (nlen >= BufferLength) ret = SQL_SUCCESS_WITH_INFO; } + + /* Return the actual string length if the caller wants it */ if (StringLength) *StringLength = nlen; } + + /* Clean up the temporary buffer */ if (NameA) free(NameA); + return ret; } -/* new function */ +/* + * SQLSetDescRecW + * + * Description: + * This function sets multiple descriptor fields with a single call. + * This is the Unicode (wide-character) version of SQLSetDescRec. + * + * Parameters: + * DescriptorHandle - Handle to the descriptor + * RecNumber - The descriptor record number (1-based) + * Type - SQL data type + * SubType - Datetime or interval subcode + * Length - Maximum data length + * Precision - Precision of numeric types + * Scale - Scale of numeric types + * Data - Pointer to data buffer (Unicode) + * StringLength - Pointer to buffer length + * Indicator - Pointer to indicator variable + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Comments: + * This function handles Unicode to UTF-8 conversion for string data + * before calling the core implementation function PGAPI_SetDescRec. + */ RETCODE SQL_API SQLSetDescRecW(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT Type, @@ -475,21 +625,29 @@ SQLSetDescRecW(SQLHDESC DescriptorHandle, MYLOG(0, "Entering h=%p rec=%d type=%d sub=%d len=" FORMAT_LEN " prec=%d scale=%d data=%p\n", DescriptorHandle, RecNumber, Type, SubType, Length, Precision, Scale, Data); MYLOG(0, "str=%p ind=%p\n", StringLength, Indicator); - + + /* Convert Unicode string to UTF-8 if needed */ if (Length > 0 || SQL_NTS == Length) { uval = ucs2_to_utf8(Data, Length > 0 ? Length / WCLEN : Length, &vallen, FALSE); val_alloced = TRUE; } + + /* For non-string data or if conversion wasn't needed, use the original value */ if (!val_alloced) { uval = Data; vallen = Length; } + + /* Call the core implementation function */ ret = PGAPI_SetDescRec(DescriptorHandle, RecNumber, Type, SubType, Length, Precision, Scale, uval, &vallen, Indicator); + + /* Free the converted string if we allocated one */ if (val_alloced) free(uval); + return ret; } diff --git a/pgapi30.c b/pgapi30.c index ca437c9..7f04755 100644 --- a/pgapi30.c +++ b/pgapi30.c @@ -1657,7 +1657,29 @@ IPDGetField(DescriptorClass *desc, SQLSMALLINT RecNumber, return ret; } -/* SQLGetStmtOption -> SQLGetStmtAttr */ +/* + * PGAPI_GetStmtAttr + * + * Description: + * Core implementation function that retrieves the current setting of a statement attribute. + * This function is called by both SQLGetStmtAttr (ANSI) and SQLGetStmtAttrW (Unicode) functions. + * + * Parameters: + * StatementHandle - Handle to the statement + * Attribute - The attribute to retrieve (SQL_ATTR_* constant) + * Value - Buffer to store the attribute value + * BufferLength - Length of the Value buffer in bytes + * StringLength - Pointer to store the actual length of string data + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Implementation Strategy: + * This function uses a switch statement to handle different attribute types. + * Most attributes are stored directly in the statement structure or its descriptors. + * For unsupported attributes, it returns an error. + * For backward compatibility with ODBC 2.0, it calls PGAPI_GetStmtOption for some attributes. + */ RETCODE SQL_API PGAPI_GetStmtAttr(HSTMT StatementHandle, SQLINTEGER Attribute, PTR Value, @@ -1672,50 +1694,62 @@ PGAPI_GetStmtAttr(HSTMT StatementHandle, switch (Attribute) { case SQL_ATTR_FETCH_BOOKMARK_PTR: /* 16 */ + /* Pointer to bookmark value */ *((void **) Value) = stmt->options.bookmark_ptr; len = sizeof(SQLPOINTER); break; case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */ + /* Pointer to parameter binding offset */ *((SQLULEN **) Value) = SC_get_APDF(stmt)->param_offset_ptr; len = sizeof(SQLPOINTER); break; case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */ + /* Parameter binding type */ *((SQLUINTEGER *) Value) = SC_get_APDF(stmt)->param_bind_type; len = sizeof(SQLUINTEGER); break; case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */ + /* Pointer to parameter operation array */ *((SQLUSMALLINT **) Value) = SC_get_APDF(stmt)->param_operation_ptr; len = sizeof(SQLPOINTER); break; case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */ + /* Pointer to parameter status array */ *((SQLUSMALLINT **) Value) = SC_get_IPDF(stmt)->param_status_ptr; len = sizeof(SQLPOINTER); break; case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */ + /* Pointer to count of processed parameters */ *((SQLULEN **) Value) = SC_get_IPDF(stmt)->param_processed_ptr; len = sizeof(SQLPOINTER); break; case SQL_ATTR_PARAMSET_SIZE: /* 22 */ + /* Number of sets of parameters */ *((SQLULEN *) Value) = SC_get_APDF(stmt)->paramset_size; len = sizeof(SQLUINTEGER); break; case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */ + /* Pointer to row binding offset */ *((SQLULEN **) Value) = SC_get_ARDF(stmt)->row_offset_ptr; len = 4; break; case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */ + /* Pointer to row operation array */ *((SQLUSMALLINT **) Value) = SC_get_ARDF(stmt)->row_operation_ptr; len = 4; break; case SQL_ATTR_ROW_STATUS_PTR: /* 25 */ + /* Pointer to row status array */ *((SQLUSMALLINT **) Value) = SC_get_IRDF(stmt)->rowStatusArray; len = 4; break; case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */ + /* Pointer to count of fetched rows */ *((SQLULEN **) Value) = SC_get_IRDF(stmt)->rowsFetched; len = 4; break; case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */ + /* Number of rows to fetch */ *((SQLULEN *) Value) = SC_get_ARDF(stmt)->size_of_rowset; len = 4; break; @@ -1723,11 +1757,13 @@ PGAPI_GetStmtAttr(HSTMT StatementHandle, case SQL_ATTR_APP_PARAM_DESC: /* 10011 */ case SQL_ATTR_IMP_ROW_DESC: /* 10012 */ case SQL_ATTR_IMP_PARAM_DESC: /* 10013 */ + /* Descriptor handles */ len = 4; *((HSTMT *) Value) = descHandleFromStatementHandle(StatementHandle, Attribute); break; case SQL_ATTR_CURSOR_SCROLLABLE: /* -1 */ + /* Whether cursor is scrollable */ len = 4; if (SQL_CURSOR_FORWARD_ONLY == stmt->options.cursor_type) *((SQLUINTEGER *) Value) = SQL_NONSCROLLABLE; @@ -1735,6 +1771,7 @@ PGAPI_GetStmtAttr(HSTMT StatementHandle, *((SQLUINTEGER *) Value) = SQL_SCROLLABLE; break; case SQL_ATTR_CURSOR_SENSITIVITY: /* -2 */ + /* Cursor sensitivity to changes made by others */ len = 4; if (SQL_CONCUR_READ_ONLY == stmt->options.scroll_concurrency) *((SQLUINTEGER *) Value) = SQL_INSENSITIVE; @@ -1742,16 +1779,19 @@ PGAPI_GetStmtAttr(HSTMT StatementHandle, *((SQLUINTEGER *) Value) = SQL_UNSPECIFIED; break; case SQL_ATTR_METADATA_ID: /* 10014 */ + /* Whether identifiers are quoted */ *((SQLUINTEGER *) Value) = stmt->options.metadata_id; break; case SQL_ATTR_ENABLE_AUTO_IPD: /* 15 */ + /* Whether automatic population of IPD is supported */ *((SQLUINTEGER *) Value) = SQL_FALSE; break; case SQL_ATTR_AUTO_IPD: /* 10001 */ - /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */ + /* Unsupported attributes */ SC_set_error(stmt, DESC_INVALID_OPTION_IDENTIFIER, "Unsupported statement option (Get)", func); return SQL_ERROR; default: + /* For backward compatibility with ODBC 2.0 */ ret = PGAPI_GetStmtOption(StatementHandle, (SQLSMALLINT) Attribute, Value, &len, BufferLength); } if (ret == SQL_SUCCESS && StringLength) @@ -1925,7 +1965,31 @@ PGAPI_SetConnectAttr(HDBC ConnectionHandle, return ret; } -/* new function */ +/* + * PGAPI_GetDescField + * + * Description: + * Core implementation function that retrieves the current setting or value of a single field + * of a descriptor record. This function is called by both SQLGetDescField (ANSI) and + * SQLGetDescFieldW (Unicode) functions. + * + * Parameters: + * DescriptorHandle - Handle to the descriptor + * RecNumber - The descriptor record number (1-based, 0 for header fields) + * FieldIdentifier - The field identifier (SQL_DESC_* constant) + * Value - Buffer to store the field value + * BufferLength - Length of the Value buffer in bytes + * StringLength - Pointer to store the actual length of string data + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Implementation Strategy: + * 1. Cast the generic SQLHDESC handle to the internal DescriptorClass structure + * 2. Determine the descriptor type (ARD, APD, IRD, IPD) + * 3. Call the appropriate type-specific handler function + * 4. Handle any errors that occur during processing + */ RETCODE SQL_API PGAPI_GetDescField(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, @@ -1934,26 +1998,37 @@ PGAPI_GetDescField(SQLHDESC DescriptorHandle, { CSTR func = "PGAPI_GetDescField"; RETCODE ret = SQL_SUCCESS; + /* Cast the generic ODBC handle to our internal descriptor structure */ DescriptorClass *desc = (DescriptorClass *) DescriptorHandle; MYLOG(0, "entering h=%p rec=" FORMAT_SMALLI " field=" FORMAT_SMALLI " blen=" FORMAT_INTEGER "\n", DescriptorHandle, RecNumber, FieldIdentifier, BufferLength); + + /* Route the request to the appropriate handler based on descriptor type */ switch (DC_get_desc_type(desc)) { case SQL_ATTR_APP_ROW_DESC: + /* Application Row Descriptor - handles column bindings */ ret = ARDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); break; case SQL_ATTR_APP_PARAM_DESC: + /* Application Parameter Descriptor - handles parameter bindings */ ret = APDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); break; case SQL_ATTR_IMP_ROW_DESC: + /* Implementation Row Descriptor - handles result set metadata */ ret = IRDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); break; case SQL_ATTR_IMP_PARAM_DESC: + /* Implementation Parameter Descriptor - handles parameter metadata */ ret = IPDGetField(desc, RecNumber, FieldIdentifier, Value, BufferLength, StringLength); break; - default:ret = SQL_ERROR; + default: + /* Unknown descriptor type - return error */ + ret = SQL_ERROR; DC_set_error(desc, DESC_INTERNAL_ERROR, "Error not implemented"); } + + /* Handle error cases by setting appropriate error messages */ if (ret == SQL_ERROR) { if (!DC_get_errormsg(desc)) @@ -1976,7 +2051,34 @@ PGAPI_GetDescField(SQLHDESC DescriptorHandle, return ret; } -/* new function */ +/* + * PGAPI_SetDescField + * + * Description: + * Core implementation function that sets the value of a single field of a descriptor record. + * This function is called by both SQLSetDescField (ANSI) and SQLSetDescFieldW (Unicode) functions. + * + * Parameters: + * DescriptorHandle - Handle to the descriptor + * RecNumber - The descriptor record number (1-based, 0 for header fields) + * FieldIdentifier - The field identifier (SQL_DESC_* constant) + * Value - The value to set for the field + * BufferLength - Length of the Value buffer in bytes (for string data) + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Implementation Strategy: + * 1. Cast the generic SQLHDESC handle to the internal DescriptorClass structure + * 2. Determine the descriptor type (ARD, APD, IRD, IPD) + * 3. Call the appropriate type-specific handler function + * 4. Handle any errors that occur during processing + * + * Notes: + * - Implementation Row Descriptor (IRD) fields are generally read-only + * - Some Implementation Parameter Descriptor (IPD) fields are read-only + * - Setting certain fields may affect other related fields automatically + */ RETCODE SQL_API PGAPI_SetDescField(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, @@ -1984,26 +2086,37 @@ PGAPI_SetDescField(SQLHDESC DescriptorHandle, { CSTR func = "PGAPI_SetDescField"; RETCODE ret = SQL_SUCCESS; + /* Cast the generic ODBC handle to our internal descriptor structure */ DescriptorClass *desc = (DescriptorClass *) DescriptorHandle; MYLOG(0, "entering h=%p(%d) rec=" FORMAT_SMALLI " field=" FORMAT_SMALLI " val=%p," FORMAT_INTEGER "\n", DescriptorHandle, DC_get_desc_type(desc), RecNumber, FieldIdentifier, Value, BufferLength); + + /* Route the request to the appropriate handler based on descriptor type */ switch (DC_get_desc_type(desc)) { case SQL_ATTR_APP_ROW_DESC: + /* Application Row Descriptor - handles column bindings */ ret = ARDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength); break; case SQL_ATTR_APP_PARAM_DESC: + /* Application Parameter Descriptor - handles parameter bindings */ ret = APDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength); break; case SQL_ATTR_IMP_ROW_DESC: + /* Implementation Row Descriptor - handles result set metadata (mostly read-only) */ ret = IRDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength); break; case SQL_ATTR_IMP_PARAM_DESC: + /* Implementation Parameter Descriptor - handles parameter metadata (partially read-only) */ ret = IPDSetField(desc, RecNumber, FieldIdentifier, Value, BufferLength); break; - default:ret = SQL_ERROR; + default: + /* Unknown descriptor type - return error */ + ret = SQL_ERROR; DC_set_error(desc, DESC_INTERNAL_ERROR, "Error not implemented"); } + + /* Handle error cases by setting appropriate error messages */ if (ret == SQL_ERROR) { if (!DC_get_errormsg(desc)) @@ -2027,7 +2140,33 @@ PGAPI_SetDescField(SQLHDESC DescriptorHandle, return ret; } -/* new function */ +/* + * PGAPI_SetDescRec + * + * Description: + * Core implementation function that sets multiple descriptor fields with a single call. + * This function is called by both SQLSetDescRec (ANSI) and SQLSetDescRecW (Unicode) functions. + * + * Parameters: + * DescriptorHandle - Handle to the descriptor + * RecNumber - The descriptor record number (1-based) + * Type - SQL data type + * SubType - Datetime or interval subcode + * Length - Maximum data length + * Precision - Precision of numeric types + * Scale - Scale of numeric types + * Data - Pointer to data buffer + * StringLength - Pointer to buffer length + * Indicator - Pointer to indicator variable + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Implementation Strategy: + * This function sets multiple descriptor fields by making individual calls + * to PGAPI_SetDescField for each field. It's a convenience function that + * allows setting commonly used fields with a single function call. + */ RETCODE SQL_API PGAPI_SetDescRec(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT Type, @@ -2105,7 +2244,35 @@ PGAPI_SetDescRec(SQLHDESC DescriptorHandle, return SQL_SUCCESS; } -/* new function */ +/* + * PGAPI_GetDescRec + * + * Description: + * Core implementation function that retrieves the current settings or values + * of fields in a descriptor record. This function is called by both SQLGetDescRec + * (ANSI) and SQLGetDescRecW (Unicode) functions. + * + * Parameters: + * DescriptorHandle - Handle to the descriptor + * RecNumber - The descriptor record number (1-based) + * Name - Buffer to store the descriptor name + * BufferLength - Length of the Name buffer in bytes + * StringLength - Pointer to store the actual length of the name + * Type - Pointer to store the SQL data type + * SubType - Pointer to store the data type subcode + * Length - Pointer to store the data length + * Precision - Pointer to store the numeric precision + * Scale - Pointer to store the numeric scale + * Nullable - Pointer to store the nullability attribute + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Implementation Strategy: + * This function retrieves multiple descriptor fields by making individual calls + * to PGAPI_GetDescField for each requested attribute. It handles the complexity + * of retrieving all the necessary descriptor information in one function call. + */ RETCODE SQL_API PGAPI_GetDescRec(SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLCHAR *Name, @@ -2115,10 +2282,11 @@ PGAPI_GetDescRec(SQLHDESC DescriptorHandle, SQLSMALLINT *Scale, SQLSMALLINT *Nullable) { RETCODE ret = SQL_SUCCESS; + DescriptorClass *desc = (DescriptorClass *) DescriptorHandle; SQLINTEGER strlen, typ, subtyp, len, prec, scal, null; - MYLOG(0, "entering h=%p(%d) rec=" FORMAT_SMALLI " name=%p blen=" FORMAT_SMALLI "\n", DescriptorHandle, DC_get_desc_type(desc), RecNumber, Name, BufferLength); + MYLOG(0, "entering h=%p(%d) rec=" FORMAT_SMALLI " name=%p blen=" FORMAT_SMALLI "\n", DescriptorHandle, DC_get_desc_type((DescriptorClass *) DescriptorHandle), RecNumber, Name, BufferLength); MYLOG(0, "str=%p type=%p sub=%p len=%p prec=%p scale=%p null=%p\n", StringLength, Type, SubType, Length, Precision, Scale, Nullable); /* @@ -2133,6 +2301,7 @@ PGAPI_GetDescRec(SQLHDESC DescriptorHandle, - SQL_DESC_NAME */ + /* Retrieve SQL data type if requested */ if (Type != NULL) { ret = PGAPI_GetDescField(DescriptorHandle, RecNumber, SQL_DESC_TYPE, &typ, 0, NULL); @@ -2140,6 +2309,7 @@ PGAPI_GetDescRec(SQLHDESC DescriptorHandle, *Type = typ; } + /* For datetime and interval types, retrieve the subtype code if requested */ if (SubType != NULL && (typ == SQL_DATETIME || typ == SQL_INTERVAL)) { ret = PGAPI_GetDescField(DescriptorHandle, RecNumber, SQL_DESC_DATETIME_INTERVAL_CODE, &subtyp, 0, NULL); @@ -2147,6 +2317,7 @@ PGAPI_GetDescRec(SQLHDESC DescriptorHandle, *SubType = subtyp; } + /* Retrieve octet length (buffer size needed) if requested */ if (Length != NULL) { ret = PGAPI_GetDescField(DescriptorHandle, RecNumber, SQL_DESC_OCTET_LENGTH, &len, 0, NULL); @@ -2154,6 +2325,7 @@ PGAPI_GetDescRec(SQLHDESC DescriptorHandle, *Length = (SQLLEN) len; } + /* Retrieve numeric precision if requested */ if (Precision != NULL) { ret = PGAPI_GetDescField(DescriptorHandle, RecNumber, SQL_DESC_PRECISION, &prec, 0, NULL); @@ -2161,6 +2333,7 @@ PGAPI_GetDescRec(SQLHDESC DescriptorHandle, *Precision = prec; } + /* Retrieve numeric scale if requested */ if (Scale != NULL) { ret = PGAPI_GetDescField(DescriptorHandle, RecNumber, SQL_DESC_SCALE, &scal, 0, NULL); @@ -2168,14 +2341,18 @@ PGAPI_GetDescRec(SQLHDESC DescriptorHandle, *Scale = scal; } - if (Nullable != NULL && (DC_get_desc_type(desc) == SQL_ATTR_IMP_ROW_DESC || DC_get_desc_type(desc) == SQL_ATTR_IMP_PARAM_DESC)) + /* Retrieve nullability information if requested (only for implementation descriptors) */ + if (Nullable != NULL && (DC_get_desc_type((DescriptorClass *) DescriptorHandle) == SQL_ATTR_IMP_ROW_DESC + || DC_get_desc_type((DescriptorClass *) DescriptorHandle) == SQL_ATTR_IMP_PARAM_DESC)) { ret = PGAPI_GetDescField(DescriptorHandle, RecNumber, SQL_DESC_NULLABLE, &null, 0, NULL); if (ret != SQL_SUCCESS) return ret; *Nullable = null; } - if (Name != NULL && (DC_get_desc_type(desc) == SQL_ATTR_IMP_ROW_DESC || DC_get_desc_type(desc) == SQL_ATTR_IMP_PARAM_DESC)) + /* Retrieve column/parameter name if requested (only for implementation descriptors) */ + if (Name != NULL && (DC_get_desc_type((DescriptorClass *) DescriptorHandle) == SQL_ATTR_IMP_ROW_DESC + || DC_get_desc_type((DescriptorClass *) DescriptorHandle) == SQL_ATTR_IMP_PARAM_DESC)) { ret = PGAPI_GetDescField(DescriptorHandle, RecNumber, SQL_DESC_NAME, Name, BufferLength, (SQLINTEGER *) &strlen); if (ret != SQL_SUCCESS) return ret; @@ -2186,7 +2363,28 @@ PGAPI_GetDescRec(SQLHDESC DescriptorHandle, return SQL_SUCCESS; } -/* SQLSet(Param/Scroll/Stmt)Option -> SQLSetStmtAttr */ +/* + * PGAPI_SetStmtAttr + * + * Description: + * Core implementation function that sets the value of a statement attribute. + * This function is called by both SQLSetStmtAttr (ANSI) and SQLSetStmtAttrW (Unicode) functions. + * + * Parameters: + * StatementHandle - Handle to the statement + * Attribute - The attribute to set (SQL_ATTR_* constant) + * Value - The value to set for the attribute + * StringLength - Length of the Value buffer in bytes (for string data) + * + * Returns: + * SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE + * + * Implementation Strategy: + * This function uses a switch statement to handle different attribute types. + * Most attributes are stored directly in the statement structure or its descriptors. + * For unsupported attributes, it returns an error. + * For backward compatibility with ODBC 2.0, it calls PGAPI_SetStmtOption for some attributes. + */ RETCODE SQL_API PGAPI_SetStmtAttr(HSTMT StatementHandle, SQLINTEGER Attribute, PTR Value, @@ -2200,28 +2398,29 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle, switch (Attribute) { case SQL_ATTR_ENABLE_AUTO_IPD: /* 15 */ + /* Whether automatic population of IPD is supported */ if (SQL_FALSE == Value) break; case SQL_ATTR_CURSOR_SCROLLABLE: /* -1 */ case SQL_ATTR_CURSOR_SENSITIVITY: /* -2 */ case SQL_ATTR_AUTO_IPD: /* 10001 */ + /* Unsupported attributes */ SC_set_error(stmt, DESC_OPTION_NOT_FOR_THE_DRIVER, "Unsupported statement option (Set)", func); return SQL_ERROR; /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */ case SQL_ATTR_IMP_ROW_DESC: /* 10012 (read-only) */ case SQL_ATTR_IMP_PARAM_DESC: /* 10013 (read-only) */ - - /* - * case SQL_ATTR_PREDICATE_PTR: case - * SQL_ATTR_PREDICATE_OCTET_LENGTH_PTR: - */ + /* Read-only attributes */ SC_set_error(stmt, DESC_INVALID_OPTION_IDENTIFIER, "Unsupported statement option (Set)", func); return SQL_ERROR; case SQL_ATTR_METADATA_ID: /* 10014 */ + /* Whether identifiers are quoted */ stmt->options.metadata_id = CAST_UPTR(SQLUINTEGER, Value); break; case SQL_ATTR_APP_ROW_DESC: /* 10010 */ + /* Application Row Descriptor */ + /* Application Row Descriptor */ if (SQL_NULL_HDESC == Value) { stmt->ard = &(stmt->ardi); @@ -2229,10 +2428,11 @@ PGAPI_SetStmtAttr(HSTMT StatementHandle, else { stmt->ard = (DescriptorClass *) Value; -MYLOG(DETAIL_LOG_LEVEL, "set ard=%p\n", stmt->ard); + MYLOG(DETAIL_LOG_LEVEL, "set ard=%p\n", stmt->ard); } break; case SQL_ATTR_APP_PARAM_DESC: /* 10011 */ + /* Application Parameter Descriptor */ if (SQL_NULL_HDESC == Value) { stmt->apd = &(stmt->apdi); @@ -2243,42 +2443,55 @@ MYLOG(DETAIL_LOG_LEVEL, "set ard=%p\n", stmt->ard); } break; case SQL_ATTR_FETCH_BOOKMARK_PTR: /* 16 */ + /* Pointer to bookmark value */ stmt->options.bookmark_ptr = Value; break; case SQL_ATTR_PARAM_BIND_OFFSET_PTR: /* 17 */ + /* Pointer to parameter binding offset */ SC_get_APDF(stmt)->param_offset_ptr = (SQLULEN *) Value; break; case SQL_ATTR_PARAM_BIND_TYPE: /* 18 */ + /* Parameter binding type */ SC_get_APDF(stmt)->param_bind_type = CAST_UPTR(SQLUINTEGER, Value); break; case SQL_ATTR_PARAM_OPERATION_PTR: /* 19 */ + /* Pointer to parameter operation array */ SC_get_APDF(stmt)->param_operation_ptr = Value; break; case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */ + /* Pointer to parameter status array */ SC_get_IPDF(stmt)->param_status_ptr = (SQLUSMALLINT *) Value; break; case SQL_ATTR_PARAMS_PROCESSED_PTR: /* 21 */ + /* Pointer to count of processed parameters */ SC_get_IPDF(stmt)->param_processed_ptr = (SQLULEN *) Value; break; case SQL_ATTR_PARAMSET_SIZE: /* 22 */ + /* Number of sets of parameters */ SC_get_APDF(stmt)->paramset_size = CAST_UPTR(SQLULEN, Value); break; case SQL_ATTR_ROW_BIND_OFFSET_PTR: /* 23 */ + /* Pointer to row binding offset */ SC_get_ARDF(stmt)->row_offset_ptr = (SQLULEN *) Value; break; case SQL_ATTR_ROW_OPERATION_PTR: /* 24 */ + /* Pointer to row operation array */ SC_get_ARDF(stmt)->row_operation_ptr = Value; break; case SQL_ATTR_ROW_STATUS_PTR: /* 25 */ + /* Pointer to row status array */ SC_get_IRDF(stmt)->rowStatusArray = (SQLUSMALLINT *) Value; break; case SQL_ATTR_ROWS_FETCHED_PTR: /* 26 */ + /* Pointer to count of fetched rows */ SC_get_IRDF(stmt)->rowsFetched = (SQLULEN *) Value; break; case SQL_ATTR_ROW_ARRAY_SIZE: /* 27 */ + /* Number of rows to fetch */ SC_get_ARDF(stmt)->size_of_rowset = CAST_UPTR(SQLULEN, Value); break; default: + /* For backward compatibility with ODBC 2.0 */ return PGAPI_SetStmtOption(StatementHandle, (SQLUSMALLINT) Attribute, (SQLULEN) Value); } return ret; diff --git a/pgtypes.c b/pgtypes.c index 4b508d1..31955d2 100644 --- a/pgtypes.c +++ b/pgtypes.c @@ -8,6 +8,14 @@ * even data types that are not directly supported can be * used (it is handled as char data). * + * This module is responsible for mapping between PostgreSQL native + * data types and ODBC SQL data types. It provides functions to: + * - Convert PostgreSQL types to ODBC SQL types + * - Determine appropriate buffer sizes for data transfer + * - Calculate precision and scale for numeric types + * - Handle display formatting requirements + * - Support metadata operations + * * Classes: n/a * * API functions: none @@ -27,6 +35,21 @@ #define EXPERIMENTAL_CURRENTLY + +/** + * @function ansi_to_wtype + * + * @brief Converts ANSI SQL types to wide (Unicode) types when appropriate + * + * This function maps standard ANSI SQL types to their Unicode equivalents + * based on the connection settings. If Unicode support is not enabled or + * not allowed for the connection, the original type is returned unchanged. + * + * @param self Pointer to the connection object + * @param ansitype The ANSI SQL type to convert + * + * @return The corresponding Unicode SQL type if applicable, otherwise the original type + */ SQLSMALLINT ansi_to_wtype(const ConnectionClass *self, SQLSMALLINT ansitype) { #ifndef UNICODE_SUPPORT @@ -50,15 +73,13 @@ SQLSMALLINT ansi_to_wtype(const ConnectionClass *self, SQLSMALLINT ansitype) Int4 getCharColumnSize(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as); /* - * these are the types we support. all of the pgtype_ functions should + * These are the types we support. All of the pgtype_ functions should * return values for each one of these. * Even types not directly supported are handled as character types * so all types should work (points, etc.) - */ - -/* - * ALL THESE TYPES ARE NO LONGER REPORTED in SQLGetTypeInfo. Instead, all - * the SQL TYPES are reported and mapped to a corresponding Postgres Type + * + * Note: This historical comment is kept for reference. The actual implementation + * now uses SQL types reported in SQLGetTypeInfo and maps them to PostgreSQL types. */ /* @@ -94,7 +115,11 @@ OID pgtypes_defined[][2] = { */ -/* These are NOW the SQL Types reported in SQLGetTypeInfo. */ +/* + * These are the SQL Types reported in SQLGetTypeInfo. + * This array defines all the SQL data types that the driver supports and reports + * to applications through the SQLGetTypeInfo function. + */ SQLSMALLINT sqlTypes[] = { SQL_BIGINT, /* SQL_BINARY, -- Commented out because VarBinary is more correct. */ @@ -150,6 +175,20 @@ SQLSMALLINT sqlTypes[] = { #define ALLOWED_C_BIGINT SQL_C_CHAR #endif +/** + * @function pg_true_type + * + * @brief Determines the actual PostgreSQL type to use + * + * This function resolves the true PostgreSQL type by considering both the type + * and basetype parameters. It handles special cases like large objects. + * + * @param conn Pointer to the connection object + * @param type The PostgreSQL type OID + * @param basetype The base type OID (for domains, etc.) + * + * @return The resolved PostgreSQL type OID to use + */ OID pg_true_type(const ConnectionClass *conn, OID type, OID basetype) { @@ -169,6 +208,20 @@ pg_true_type(const ConnectionClass *conn, OID type, OID basetype) #define MINUTE_BIT (1 << 27) #define SECOND_BIT (1 << 28) +/** + * @function get_interval_type + * + * @brief Determines the SQL interval type from PostgreSQL interval typmod + * + * This function analyzes the PostgreSQL interval type modifier (atttypmod) + * to determine which SQL interval type it corresponds to (year, month, day, etc.) + * + * @param atttypmod The PostgreSQL type modifier for interval + * @param name If not NULL, will be set to point to a string describing the interval type + * + * @return The corresponding SQL interval type code, or 0 if not determined + */ + static SQLSMALLINT get_interval_type(Int4 atttypmod, const char **name) { @@ -259,6 +312,23 @@ MYLOG(0, "entering atttypmod=%x\n", atttypmod); return 0; } +/** + * @function getCharColumnSizeX + * + * @brief Determines the column size for character data types + * + * This function calculates the appropriate column size for character data types + * based on the PostgreSQL type, type modifier, and driver configuration settings. + * It handles various special cases and unknown size scenarios. + * + * @param conn Pointer to the connection object + * @param type The PostgreSQL type OID + * @param atttypmod The PostgreSQL type modifier + * @param adtsize_or_longestlen The longest value length or attribute size + * @param handle_unknown_size_as How to handle unknown sizes (max, longest, etc.) + * + * @return The calculated column size + */ static Int4 getCharColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as) { @@ -365,6 +435,22 @@ MYLOG(DETAIL_LOG_LEVEL, "!!! catalog_result=%d\n", handle_unknown_size_as); */ #define UNUSED_HANDLE_UNKNOWN_SIZE_AS (-2) +/** + * @function getNumericDecimalDigitsX + * + * @brief Determines the decimal digits for numeric data types + * + * This function calculates the appropriate number of decimal digits for numeric types + * based on the PostgreSQL type modifier or other available information. + * + * @param conn Pointer to the connection object + * @param type The PostgreSQL type OID + * @param atttypmod The PostgreSQL type modifier + * @param adtsize_or_longest The longest value or attribute size + * @param UNUSED_handle_unknown_size_as Unused parameter (for API consistency) + * + * @return The calculated number of decimal digits + */ static SQLSMALLINT getNumericDecimalDigitsX(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longest, int UNUSED_handle_unknown_size_as) { @@ -383,6 +469,23 @@ getNumericDecimalDigitsX(const ConnectionClass *conn, OID type, int atttypmod, i return adtsize_or_longest; } +/** + * @function getNumericColumnSizeX + * + * @brief Determines the column size for numeric data types + * + * This function calculates the appropriate column size for numeric data types + * based on the PostgreSQL type modifier and driver configuration settings. + * It handles various special cases and unknown size scenarios. + * + * @param conn Pointer to the connection object + * @param type The PostgreSQL type OID + * @param atttypmod The PostgreSQL type modifier + * @param adtsize_or_longest The longest value or attribute size + * @param handle_unknown_size_as How to handle unknown sizes + * + * @return The calculated column size + */ static Int4 /* PostgreSQL restriction */ getNumericColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longest, int handle_unknown_size_as) { @@ -421,6 +524,20 @@ getNumericColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod, int return adtsize_or_longest; } +/** + * @function getTimestampDecimalDigitsX + * + * @brief Determines the decimal digits for timestamp data types + * + * This function calculates the appropriate number of decimal digits for timestamp types + * based on the PostgreSQL type modifier. + * + * @param conn Pointer to the connection object + * @param type The PostgreSQL type OID + * @param atttypmod The PostgreSQL type modifier + * + * @return The calculated number of decimal digits + */ static SQLSMALLINT getTimestampDecimalDigitsX(const ConnectionClass *conn, OID type, int atttypmod) { @@ -428,6 +545,20 @@ getTimestampDecimalDigitsX(const ConnectionClass *conn, OID type, int atttypmod) return (atttypmod > -1 ? atttypmod : 6); } +/** + * @function getTimestampColumnSizeX + * + * @brief Determines the column size for timestamp data types + * + * This function calculates the appropriate column size for timestamp data types + * based on the PostgreSQL type and type modifier. + * + * @param conn Pointer to the connection object + * @param type The PostgreSQL type OID + * @param atttypmod The PostgreSQL type modifier + * + * @return The calculated column size + */ static SQLSMALLINT getTimestampColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod) { @@ -457,6 +588,19 @@ getTimestampColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod) return (scale > 0) ? fixed + 1 + scale : fixed; } +/** + * @function getIntervalDecimalDigits + * + * @brief Determines the decimal digits for interval data types + * + * This function calculates the appropriate number of decimal digits for interval types + * based on the PostgreSQL type modifier. + * + * @param type The PostgreSQL type OID + * @param atttypmod The PostgreSQL type modifier + * + * @return The calculated number of decimal digits + */ static SQLSMALLINT getIntervalDecimalDigits(OID type, int atttypmod) { @@ -469,6 +613,19 @@ getIntervalDecimalDigits(OID type, int atttypmod) return (prec = atttypmod & 0xffff) == 0xffff ? 6 : prec ; } +/** + * @function getIntervalColumnSize + * + * @brief Determines the column size for interval data types + * + * This function calculates the appropriate column size for interval data types + * based on the PostgreSQL type and type modifier. + * + * @param type The PostgreSQL type OID + * @param atttypmod The PostgreSQL type modifier + * + * @return The calculated column size + */ static SQLSMALLINT getIntervalColumnSize(OID type, int atttypmod) { @@ -513,7 +670,23 @@ getIntervalColumnSize(OID type, int atttypmod) return (scale > 0) ? ttl + 1 + scale : ttl; } - +/** + * @function pgtype_attr_to_concise_type + * + * @brief Maps PostgreSQL data types to ODBC SQL data types + * + * This function is a core type mapping function that converts PostgreSQL data types + * to their corresponding ODBC SQL data types, considering connection settings, + * type modifiers, and other factors. + * + * @param conn Pointer to the connection object + * @param type The PostgreSQL type OID + * @param atttypmod The PostgreSQL type modifier + * @param adtsize_or_longestlen The longest value length or attribute size + * @param handle_unknown_size_as How to handle unknown sizes + * + * @return The corresponding ODBC SQL data type + */ SQLSMALLINT pgtype_attr_to_concise_type(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as) { @@ -650,6 +823,22 @@ pgtype_attr_to_concise_type(const ConnectionClass *conn, OID type, int atttypmod } } +/** + * @function pgtype_attr_to_sqldesctype + * + * @brief Maps PostgreSQL data types to SQL descriptor types + * + * This function converts PostgreSQL data types to SQL descriptor types, + * which are used in descriptor-based ODBC functions. + * + * @param conn Pointer to the connection object + * @param type The PostgreSQL type OID + * @param atttypmod The PostgreSQL type modifier + * @param adtsize_or_longestlen The longest value length or attribute size + * @param handle_unknown_size_as How to handle unknown sizes + * + * @return The corresponding SQL descriptor type + */ SQLSMALLINT pgtype_attr_to_sqldesctype(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as) {