DOC: Explanation of Length Arguments for Unicode ODBC Functions

Article translations Article translations
Article ID: 294169 - View products that this article applies to.
This article was previously published under Q294169
Expand all | Collapse all

SUMMARY

The ODBC Driver Manager version 3.5 or later supports both ANSI and Unicode versions of all functions that accept pointers to character strings or SQLPOINTER in their arguments. The Unicode functions are implemented as functions with a suffix of "W", such as SQLExecDirectW and SQLGetInfoW.

For many of these Unicode functions, the ODBC Programmer's Reference provides incorrect or ambiguous descriptions for some of the function arguments. Specifically, this problem relates to arguments that are used to specify the length of character string input and output values.

MORE INFORMATION

The problems in the ODBC documentation involve whether a length argument should specify the number of bytes or the number of characters in an input or output string. For the ANSI version of these functions, the count of bytes in a string is equal to the count of characters (because ANSI characters occupy just one byte each), so the terms "bytes" and "characters" can effectively be used interchangeably. However, with Unicode strings, each character occupies two bytes. Therefore, it is very important to distinguish whether length inputs to a Unicode function must specify a count of bytes or of characters.

In some cases, the documentation uses the word "bytes" when the word "characters" should have been used instead. In other cases, the documentation is not necessarily incorrect, but specifies that a "length" of a string is required, without explicitly documenting whether this value should be a count of bytes or a count of characters.

Regardless of what the documentation says for each ODBC function, the following paragraph from the Unicode section of "Chapter 17: Programming Considerations" in the ODBC Programmer's Reference is the ultimate rule to use for length arguments in Unicode functions:
"Unicode functions that always return or take strings or length arguments are passed as count-of-characters. For functions that return length information for server data, the display size and precision are described in number of characters. When a length (transfer size of the data) could refer to string or nonstring data, the length is described in octet lengths. For example, SQLGetInfoW will still take the length as count-of-bytes, but SQLExecDirectW will use count-of-characters."
This means that if the argument in question describes the length of another argument that is always a string (typically represented as a SQLCHAR), then the length reflects the number of characters in the string. If the length argument describes another argument that could be a string or some other data type (typically represented as a SQLPOINTER), the length is in bytes.

The following table lists all of the ODBC API functions that have Unicode versions. For each function listed, the table highlights the known problems in the ODBC documentation, and provides a more complete description of the length arguments in question.

Collapse this tableExpand this table
FunctionArgument NameCurrent DescriptionCorrected Description
SQLBrowseConnectStringLength1Length of *InConnectionString.Length of *InConnectionString, in characters.
BufferLengthLength of the *OutConnectionString buffer.Length of the *OutConnectionString buffer, in characters.
StringLength2PtrThe total number of bytes (excluding the null-termination byte) available to return in *OutConnectionString.The total number of characters (excluding the null-termination character) available to return in *OutConnectionString.
SQLColAttributeBufferLengthIf FieldIdentifier is an ODBC-defined field and CharacterAttributePtr points to a character string or binary buffer, this argument should be the length of *CharacterAttributePtr. If FieldIdentifier is an ODBC-defined field and *CharacterAttributePtr is an integer, this field is ignored. If the *CharacterAttributePtr is a Unicode string (when calling SQLColAttributeW), the BufferLength argument must be an even numberThis is correct. BufferLength refers to the number of bytes available for the value in CharacterAttributePtr.
StringLengthPtrPointer to a buffer in which to return the total number of bytes (excluding the null-termination byte for character data) available to return in *CharacterAttributePtr.This is correct.
SQLColAttributesThis function as been deprecated to SQLColAttribute (see above).
SQLColumnPrivilegesNameLength1-4Length of *CatalogName. (Note here that there are four different arguments that contain length values. Each one refers to a different input or output buffer, such as CatalogName, SchemaName, TableName, and ColumnName. For simplicity, for any functions with similar input values, this tables combines all such NameLength arguments, rather than listing each one separately.)Length of *CatalogName, in characters.
SQLColumnsNameLength1-4Length of *CatalogName.Length of *CatalogName, in characters.
SQLConnectNameLength1-3Length of *ServerName.Length of *ServerName, in characters.
SQLDataSourcesBufferLength1Length of the *ServerName buffer, in bytes.Length of the *ServerName buffer, in characters.
NameLength1PtrPointer to a buffer in which to return the total number of bytes (excluding the null-termination byte). Pointer to a buffer in which to return the total number of characters (excluding the null-termination character).
BufferLength2Length of the *Description buffer.Length of the *Description buffer, in characters.
NameLength2PtrPointer to a buffer in which to return the total number of bytes (excluding the null-termination byte) available to return in *Description.Pointer to a buffer in which to return the total number of characters (excluding the null-termination character) available to return in *Description.
SQLDescribeColBufferLengthLength of the *ColumnName buffer, in characters.This is correct.
NameLengthPtrPointer to a buffer in which to return the total number of bytes (excluding the null-termination byte) available to return in *ColumnName.Pointer to a buffer in which to return the total number of characters (excluding the null-termination character) available to return in *ColumnName.
SQLDriverConnectStringLength1Length of *InConnectionString, in bytes.Length of *InConnectionString, in characters.
BufferLengthLength of the *OutConnectionString buffer. If the *OutConnectionString value is a Unicode string (when calling SQLDriverConnectW), the BufferLength argument must be an even number.Length of the *OutConnectionString buffer, in characters. (Note that this means this argument does NOT have to be an even number.)
StringLength2PtrPointer to a buffer in which to return the total number of characters (excluding the null-termination character) available to return in *OutConnectionString.This is correct.
SQLDriversBufferLength1Length of the *DriverDescription buffer, in bytes.Length of the *DriverDescription buffer, in characters.
DescriptionLengthPtrPointer to a buffer in which to return the total number of bytes (excluding the null-termination byte) available to return in *DriverDescription.Pointer to a buffer in which to return the total number of characters (excluding the null-termination character) available to return in *DriverDescription.
BufferLength2Length of the *DriverAttributes buffer, in bytes. If the *DriverDescription value is a Unicode string (when calling SQLDriversW), the BufferLength argument must be an even number.Length of the *DriverAttributes buffer, in characters. (Note that this means this argument does NOT have to be an even number.)
AttributesLengthPtrPointer to a buffer in which to return the total number of bytes (excluding the null-termination byte) available to return in *DriverAttributes.Pointer to a buffer in which to return the total number of characters (excluding the null-termination character) available to return in *DriverAttributes.
SQLErrorThis function has been deprecated to SQLGetDiagRec.
SQLExecDirectTextLengthLength of *StatementText.Length of *StatementText, in characters.
SQLForeignKeysNameLength1-2Length of *PKCatalogName, in bytes.Length of *PKCatalogName, in characters.
NameLength3-6Length of *PKTableName.Length of *PKTableName, in characters.
SQLGetConnectAttrBufferLengthIf the value in *ValuePtr is a Unicode string (when calling SQLGetConnectAttrW), the BufferLength argument must be an even number. This is correct. BufferLength should contain a count of bytes.
StringLengthPtrA pointer to a buffer in which to return the total number of bytes (excluding the null-termination character) available to return in *ValuePtr.This is correct.
SQLGetConnectOptionThis function has been deprecated to SQLGetConnectAttr.
SQLGetCursorNameBufferLengthLength of *CursorName, in bytes. If the value in *CursorName is a Unicode string (when calling SQLGetCursorNameW), the BufferLength argument must be an even number.Length of *CursorName, in characters. (Note that this means this argument does NOT have to be an even number.)
NameLengthPtrPointer to memory in which to return the total number of bytes (excluding the null-termination character) available to return in *CursorName.Pointer to memory in which to return the total number of characters (excluding the null-termination character) available to return in *CursorName.
SQLGetDescFieldBufferLengthIf the value in *ValuePtr is of a Unicode data type (when calling SQLGetDescFieldW), the BufferLength argument must be an even number.This is correct. BufferLength should contain a count of bytes.
StringLengthPtrPointer to the buffer in which to return the total number of bytes (excluding the number of bytes required for the null-termination character) available to return in *ValuePtr.This is correct.
SQLGetDescRecBufferLengthLength of the *Name buffer, in bytes.Length of the *Name buffer, in characters.
StringLengthPtrA pointer to a buffer in which to return the number of bytes of data available to return in the *Name buffer, excluding the null-termination character.A pointer to a buffer in which to return the number of characters available to return in the *Name buffer, excluding the null-termination character.
SQLGetDiagFieldBufferLengthIf the value in *DiagInfoPtr is a Unicode string (when calling SQLGetDiagFieldW), the BufferLength argument must be an even number.This is correct. BufferLength should contain a count of bytes.
StringLengthPtrPointer to a buffer in which to return the total number of bytes (excluding the number of bytes required for the null-termination character) available to return in *DiagInfoPtr, for character data. This is correct.
SQLGetDiagRecBufferLengthLength of the *MessageText buffer in characters.This is correct
TextLengthPtrPointer to a buffer in which to return the total number of bytes (excluding the number of bytes required for the null-termination character) available to return in *MessageText. Pointer to a buffer in which to return the total number of characters (excluding the null-termination character) available to return in *MessageText.
SQLGetInfoBufferLengthLength of the *InfoValuePtr buffer. If *InfoValuePtr is a Unicode string (when calling SQLGetInfoW), the BufferLength argument must be an even number.This is correct. BufferLength should contain a count of bytes.
StringLengthPtrPointer to a buffer in which to return the total number of bytes (excluding the null-termination character for character data) available to return in *InfoValuePtr.This is correct.
SQLGetStmtAttrBufferLengthIf Attribute is an ODBC-defined attribute and ValuePtr points to a character string or a binary buffer, this argument should be the length of *ValuePtr. If the value returned in *ValuePtr is a Unicode string (when calling SQLGetStmtAttrW), the BufferLength argument must be an even numberThis is correct. BufferLength should contain a count of bytes.
StringLengthPtrA pointer to a buffer in which to return the total number of bytes (excluding the null-termination character) available to return in *ValuePtr.This is correct.
SQLNativeSQLTextLength1Length of *InStatementText text string.Length of *InStatementText text string, in characters.
BufferLengthLength of the *OutStatementText buffer. If the value returned in *InStatementText is a Unicode string (when calling SQLNativeSqlW), the BufferLength argument must be an even number.Length of the *OutStatementText buffer, in characters. (Note that this means this argument does NOT have to be an even number.)
TextLength2PtrPointer to a buffer in which to return the total number of bytes (excluding the null-termination byte) available to return in *OutStatementText.Pointer to a buffer in which to return the total number of characters (excluding the null-termination character) available to return in *OutStatementText.
SQLPrepareTextLengthLength of *StatementText.Length of *StatementText, in characters.
SQLPrimaryKeysNameLength1-3Length in bytes of *CatalogName.Length of *CatalogName, in characters.
SQLProcedureColumnsNameLength1-4Length of *CatalogName.Length of *CatalogName, in characters.
SQLProceduresNameLength1-3Length in bytes of *CatalogName.Length of *CatalogName, in characters.
SQLSetConnectAttrStringLengthIf Attribute is an ODBC-defined attribute and ValuePtr points to a character string or a binary buffer, this argument should be the length of *ValuePtr.If Attribute is an ODBC-defined attribute and ValuePtr points to a character string or a binary buffer, this argument should be the length of *ValuePtr. For character string data, this argument should contain the number of bytes in the string.
SQLSetConnectOptionThis function has been deprecated to SQLSetConnectAttr.
SQLSetCursorNameNameLengthLength of *CursorName.Length of *CursorName, in characters.
SQLSetDescFieldBufferLengthIf FieldIdentifier is an ODBC-defined field and ValuePtr points to a character string or a binary buffer, this argument should be the length of *ValuePtr.If FieldIdentifier is an ODBC-defined field and ValuePtr points to a character string or a binary buffer, this argument should be the length of *ValuePtr. For character string data, this argument should contain the number of bytes in the string.
SQLSetStmtAttrStringLengthIf Attribute is an ODBC-defined attribute and ValuePtr points to a character string or a binary buffer, this argument should be the length of *ValuePtr.If Attribute is an ODBC-defined attribute and ValuePtr points to a character string or a binary buffer, this argument should be the length of *ValuePtr. For character string data, this argument should contain the number of bytes in the string.
SQLSpecialColumnsNameLength1-3Length of *TableName.Length of *TableName, in characters.
SQLStatisticsNameLength1-3Length of *CatalogName.Length of *CatalogName, in characters.
SQLTablePrivilegesNameLength1-3Length of *CatalogName.Length of *CatalogName, in characters.
SQLTablesNameLength1-4Length of *CatalogName.Length of *CatalogName, in characters.

Using the SQLDriverConnect example from the table above, the InConnectionString and OutConnectionString arguments are both defined as SQLCHAR*, so StringLength1 and BufferLength should indicate the number of characters in the strings. In contrast, consider the SQLGetInfo function. This function takes an input of InfoValuePtr, and the length of this input is passed in BufferLength. Because InfoValuePtr can contain both strings and other types of data, it is a SQLPOINTER. Therefore, applying the rules explained above, BufferLength will be a count of bytes, rather than characters.

REFERENCES

The following Microsoft Knowledge Base article contains information on the above problem that has already been corrected for the SQLGetDiagRecW documentation:
243526 DOC: ODBC Spec Incorrectly says SQLGetDiagRecW Takes in Bufferlength as the Number of Bytes

Properties

Article ID: 294169 - Last Review: May 12, 2003 - Revision: 2.1
APPLIES TO
  • Microsoft Open Database Connectivity 3.5
  • Microsoft Data Access Components 2.1
  • Microsoft Data Access Components 2.5
  • Microsoft Data Access Components 2.6
  • Microsoft Data Access Components 2.7
Keywords: 
kbbug kbdocerr KB294169

Give Feedback

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com