Modified:
trunk/ChangeLog
trunk/driver/catalog.c
trunk/driver/cursor.c
trunk/driver/myutil.h
trunk/driver/results.c
trunk/driver/utility.c
trunk/test/my_basics.c
trunk/test/my_catalog.c
trunk/test/my_datetime.c
trunk/test/my_result.c
trunk/test/my_types.c
Log:
Big cleanup of how column lengths are reported. Fixes a number of known
bugs, and probably some unknown ones.
* Lengths returned by SQLColumns(), SQLDescribeCol(), and SQLColAttribute()
were often incorrect. These lengths should now conform to the ODBC
specification. FLAG_FIELD_LENGTH no longer has any effect. The default
behavior was incorrect. (Bug #27862)
* The SQL_DATA_TYPE column in SQLColumns() results did not report the
correct value for date and time types.
* The SQL_DATETIME_SUB column in SQLColumns() was not correctly set for
date and time types.
* The value for SQL_DESC_FIXED_PREC_SCALE was not returned correctly
for decimal values in MySQL 5.0 and later.
* The wrong value from SQL_DESC_LITERAL_SUFFIX was returned for binary
fields.
* The wrong value for SQL_DESC_TYPE was returned for date and time types.
* The wrong value for DECIMAL_DIGITS in SQLColumns() was reported for
FLOAT and DOUBLE fields, as well as the wrong value for the scale
parameter to SQLDescribeCol(), and the SQL_DESC_SCALE attribute
from SQLColAttribute().
* MySQL BIT(n) fields were always treated as SQL_BIT data. When n > 1,
they are now treated as binary data.
* If the connection character set was set to a multibyte character set,
such as UTF-8, the wrong column size was reported. (Bug #19345)
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2007-08-02 00:48:34 UTC (rev 626)
+++ trunk/ChangeLog 2007-08-02 17:04:03 UTC (rev 627)
@@ -7,6 +7,27 @@
ODBC logging should be used.
Bugs fixed:
+ * Lengths returned by SQLColumns(), SQLDescribeCol(), and SQLColAttribute()
+ were often incorrect. These lengths should now conform to the ODBC
+ specification. FLAG_FIELD_LENGTH no longer has any effect. The default
+ behavior was incorrect. (Bug #27862)
+ * The SQL_DATA_TYPE column in SQLColumns() results did not report the
+ correct value for date and time types.
+ * The SQL_DATETIME_SUB column in SQLColumns() was not correctly set for
+ date and time types.
+ * The value for SQL_DESC_FIXED_PREC_SCALE was not returned correctly
+ for decimal values in MySQL 5.0 and later.
+ * The wrong value from SQL_DESC_LITERAL_SUFFIX was returned for binary
+ fields.
+ * The wrong value for SQL_DESC_TYPE was returned for date and time types.
+ * The wrong value for DECIMAL_DIGITS in SQLColumns() was reported for
+ FLOAT and DOUBLE fields, as well as the wrong value for the scale
+ parameter to SQLDescribeCol(), and the SQL_DESC_SCALE attribute
+ from SQLColAttribute().
+ * MySQL BIT(n) fields were always treated as SQL_BIT data. When n > 1,
+ they are now treated as binary data.
+ * If the connection character set was set to a multibyte character set,
+ such as UTF-8, the wrong column size was reported. (Bug #19345)
* SQLSpecialColumns() returned all TIMESTAMP fields when queried for
SQL_ROWVER, not just an auto-updating TIMESTAMP field. (Bug #9927, still
limited by Bug #30081 in the server.)
Modified: trunk/driver/catalog.c
===================================================================
--- trunk/driver/catalog.c 2007-08-02 00:48:34 UTC (rev 626)
+++ trunk/driver/catalog.c 2007-08-02 17:04:03 UTC (rev 627)
@@ -822,9 +822,8 @@
while ((field= mysql_fetch_field(table_res)))
{
- ulong transfer_length, precision, display_size;
+ SQLSMALLINT type;
char buff[255]; /* @todo justify the size of this buffer */
- int type;
MYSQL_ROW row= stmt->result_array + (SQLCOLUMNS_FIELDS * next_row++);
row[0]= db; /* TABLE_CAT */
@@ -832,38 +831,55 @@
row[2]= strdup_root(alloc, field->table); /* TABLE_NAME */
row[3]= strdup_root(alloc, field->name); /* COLUMN_NAME */
- field->max_length= field->length;
- type= unireg_to_sql_datatype(stmt, field, buff, &transfer_length,
- &precision, &display_size);
+ type= get_sql_data_type(stmt, field, buff);
- /* DATA_TYPE and SQL_DATA_TYPE */
+ row[5]= strdup_root(alloc, buff); /* TYPE_NAME */
+
sprintf(buff, "%d", type);
- row[4]= row[13]= strdup_root(alloc, buff);
+ row[4]= strdup_root(alloc, buff); /* DATA_TYPE */
- row[5]= strdup_root(alloc, buff); /* TYPE_NAME */
+ if (type == SQL_TYPE_DATE || type == SQL_TYPE_TIME ||
+ type == SQL_TYPE_TIMESTAMP)
+ {
+ row[14]= row[4]; /* SQL_DATETIME_SUB */
+ sprintf(buff, "%d", SQL_DATETIME);
+ row[13]= strdup_root(alloc, buff); /* SQL_DATA_TYPE */
+ }
+ else
+ {
+ row[13]= row[4]; /* SQL_DATA_TYPE */
+ row[14]= NULL; /* SQL_DATETIME_SUB */
+ }
/* COLUMN_SIZE */
- sprintf(buff, "%ld", precision);
+ sprintf(buff, "%ld", get_column_size(stmt, field, FALSE));
row[6]= strdup_root(alloc, buff);
/* BUFFER_LENGTH */
- sprintf(buff, "%ld", transfer_length);
+ sprintf(buff, "%ld", get_transfer_octet_length(stmt, field));
row[7]= strdup_root(alloc, buff);
- if (IS_NUM(field->type))
- {
- sprintf(buff, "%d", field->decimals);
- row[8]= strdup_root(alloc,buff); /* DECIMAL_DIGITS */
- row[9]= "10"; /* NUM_PREC_RADIX */
- row[15]= NULL; /* CHAR_OCTET_LENGTH */
- }
+ if (is_char_sql_type(type) || is_wchar_sql_type(type) ||
+ is_binary_sql_type(type))
+ row[15]= strdup_root(alloc, buff); /* CHAR_OCTET_LENGTH */
else
+ row[15]= NULL; /* CHAR_OCTET_LENGTH */
+
{
- row[8]= row[9]= NullS; /* DECIMAL_DIGITS, NUM_PREC_RADIX */
- row[15]= strdup_root(alloc, buff); /* CHAR_OCTET_LENGTH */
+ SQLLEN digits= get_decimal_digits(stmt, field);
+ if (digits != SQL_NO_TOTAL)
+ {
+ sprintf(buff, "%ld", digits);
+ row[8]= strdup_root(alloc, buff); /* DECIMAL_DIGITS */
+ row[9]= "10"; /* NUM_PREC_RADIX */
+ }
+ else
+ {
+ row[8]= row[9]= NullS; /* DECIMAL_DIGITS, NUM_PREC_RADIX */
+ }
}
- if ((field->flags & NOT_NULL_FLAG) == NOT_NULL_FLAG)
+ if (field->flags & NOT_NULL_FLAG)
{
sprintf(buff, "%d", SQL_NO_NULLS);
row[10]= strdup_root(alloc, buff); /* NULLABLE */
@@ -901,7 +917,7 @@
else
{
char *def= alloc_root(alloc, strlen(field->def) + 3);
- if (IS_NUM(field->type))
+ if (is_numeric_mysql_type(field->type))
sprintf(def, "%s", field->def);
else
sprintf(def, "'%s'", field->def);
@@ -909,9 +925,6 @@
}
}
- /** @todo this is not correct. */
- row[14]= NULL; /* SQL_DATETIME_SUB */
-
sprintf(buff, "%d", ++count);
row[16]= strdup_root(alloc, buff); /* ORDINAL_POSITION */
}
@@ -1506,7 +1519,6 @@
MYSQL_RES *result;
MYSQL_FIELD *field;
MEM_ROOT *alloc;
- ulong transfer_length,precision,display_size;
uint field_count;
my_bool primary_key;
@@ -1544,7 +1556,7 @@
for ( row= stmt->result_array;
(field = mysql_fetch_field(result)); )
{
- int type;
+ SQLSMALLINT type;
if ((field->type != MYSQL_TYPE_TIMESTAMP))
continue;
/*
@@ -1555,20 +1567,26 @@
if (!(field->flags & TIMESTAMP_FLAG))
continue;
field_count++;
- sprintf(buff,"%d",SQL_SCOPE_SESSION);
- row[0]= strdup_root(alloc,buff);
+ row[0]= NULL;
row[1]= field->name;
- type= unireg_to_sql_datatype(stmt,field,buff,&transfer_length,
- &precision,&display_size);
+ type= get_sql_data_type(stmt, field, buff);
row[3]= strdup_root(alloc,buff);
sprintf(buff,"%d",type);
row[2]= strdup_root(alloc,buff);
- sprintf(buff,"%ld",precision);
+ sprintf(buff, "%ld", get_column_size(stmt, field, FALSE));
row[4]= strdup_root(alloc,buff);
- sprintf(buff,"%ld",transfer_length);
+ sprintf(buff, "%ld", get_transfer_octet_length(stmt, field));
row[5]= strdup_root(alloc,buff);
- sprintf(buff,"%d",field->decimals);
- row[6]= strdup_root(alloc,buff);
+ {
+ SQLLEN digits= get_decimal_digits(stmt, field);
+ if (digits != SQL_NO_TOTAL)
+ {
+ sprintf(buff,"%ld", digits);
+ row[6]= strdup_root(alloc,buff);
+ }
+ else
+ row[6]= NULL;
+ }
sprintf(buff,"%d",SQL_PC_NOT_PSEUDO);
row[7]= strdup_root(alloc,buff);
row+= SQLSPECIALCOLUMNS_FIELDS;
@@ -1614,7 +1632,7 @@
for ( row= stmt->result_array ;
(field= mysql_fetch_field(result)); )
{
- int type;
+ SQLSMALLINT type;
if ( primary_key && !(field->flags & PRI_KEY_FLAG) )
continue;
#ifndef SQLSPECIALCOLUMNS_RETURN_ALL_COLUMNS
@@ -1627,17 +1645,24 @@
sprintf(buff,"%d",SQL_SCOPE_SESSION);
row[0]= strdup_root(alloc,buff);
row[1]= field->name;
- type= unireg_to_sql_datatype(stmt,field,buff,&transfer_length,
- &precision,&display_size);
+ type= get_sql_data_type(stmt, field, buff);
row[3]= strdup_root(alloc,buff);
sprintf(buff,"%d",type);
row[2]= strdup_root(alloc,buff);
- sprintf(buff,"%ld",precision);
+ sprintf(buff,"%ld", get_column_size(stmt, field, FALSE));
row[4]= strdup_root(alloc,buff);
- sprintf(buff,"%ld",transfer_length);
+ sprintf(buff,"%ld", get_transfer_octet_length(stmt, field));
row[5]= strdup_root(alloc,buff);
- sprintf(buff,"%d",field->decimals);
- row[6]= strdup_root(alloc,buff);
+ {
+ SQLLEN digits= get_decimal_digits(stmt, field);
+ if (digits != SQL_NO_TOTAL)
+ {
+ sprintf(buff,"%ld", digits);
+ row[6]= strdup_root(alloc, buff);
+ }
+ else
+ row[6]= NULL;
+ }
sprintf(buff,"%d",SQL_PC_NOT_PSEUDO);
row[7]= strdup_root(alloc,buff);
row+= SQLSPECIALCOLUMNS_FIELDS;
Modified: trunk/driver/cursor.c
===================================================================
--- trunk/driver/cursor.c 2007-08-02 00:48:34 UTC (rev 626)
+++ trunk/driver/cursor.c 2007-08-02 17:04:03 UTC (rev 627)
@@ -502,7 +502,6 @@
SQLUSMALLINT nSrcCol)
{
PARAM_BIND param;
- ulong transfer_length,precision,display_size;
MYSQL_FIELD *field= mysql_fetch_field_direct(result,nSrcCol);
MYSQL_ROW row_data= result->data_cursor->data + nSrcCol;
NET *net=&stmt->dbc->mysql.net;
@@ -511,12 +510,7 @@
/* Copy row buffer data to statement */
param.used= 1;
- param.SqlType= unireg_to_sql_datatype( stmt,
- field,
- 0,
- &transfer_length,
- &precision,
- &display_size );
+ param.SqlType= get_sql_data_type(stmt, field, 0);
param.CType= SQL_C_CHAR;
if ( row_data && *row_data )
@@ -787,7 +781,6 @@
DYNAMIC_STRING *dynQuery)
{
PARAM_BIND param;
- ulong transfer_length,precision,display_size;
SQLLEN length;
uint ncol, ignore_count= 0;
MYSQL_FIELD *field;
@@ -843,11 +836,7 @@
dynstr_append_mem(dynQuery,"=",1);
param.used= 1;
- param.SqlType= unireg_to_sql_datatype( stmt,field,
- 0,
- &transfer_length,
- &precision,
- &display_size );
+ param.SqlType= get_sql_data_type(stmt, field, NULL);
param.CType= bind->fCType;
param.buffer= (gptr) bind->rgbValue+irow*bind->cbValueMax;
param.ValueMax= bind->cbValueMax;
@@ -1151,7 +1140,6 @@
dynstr_append_mem(ext_query,"(", 1);
for ( ncol= 0; ncol < result->field_count; ncol++ )
{
- ulong transfer_length,precision,display_size;
MYSQL_FIELD *field= mysql_fetch_field_direct(result,ncol);
BIND *bind= stmt->bind+ncol;
SQLINTEGER binding_offset= 0;
@@ -1174,12 +1162,7 @@
else
ind_or_len= bind->cbValueMax;
- param.SqlType= unireg_to_sql_datatype(stmt,
- field,
- 0,
- &transfer_length,
- &precision,
- &display_size);
+ param.SqlType= get_sql_data_type(stmt, field, NULL);
param.CType = bind->fCType;
param.buffer= ((gptr)bind->rgbValue +
binding_offset +
Modified: trunk/driver/myutil.h
===================================================================
--- trunk/driver/myutil.h 2007-08-02 00:48:34 UTC (rev 626)
+++ trunk/driver/myutil.h 2007-08-02 17:04:03 UTC (rev 627)
@@ -47,8 +47,6 @@
#define reset_ptr(x) if (x) x= 0
#define digit(A) ((int) (A - '0'))
#define option_flag(A,B) ((A)->dbc->flag & B)
-#define binary_field(fld) ((fld)->flags & BINARY_FLAG)
-#define num_field(fld) ((fld)->flags & NUM_FLAG)
#ifdef MYODBC_DBG
@@ -112,9 +110,26 @@
SQLRETURN handle_connection_error(STMT *stmt);
void set_mem_error(MYSQL *mysql);
void translate_error(char *save_state,myodbc_errid errid,uint mysql_err);
-int unireg_to_sql_datatype(STMT FAR *stmt, MYSQL_FIELD *field, char *buff,
- ulong *transfer_length,ulong *precision,
- ulong *display_size);
+
+SQLSMALLINT get_sql_data_type(STMT *stmt, MYSQL_FIELD *field, char *buff);
+SQLLEN get_column_size(STMT *stmt, MYSQL_FIELD *field, my_bool actual);
+SQLLEN get_decimal_digits(STMT *stmt, MYSQL_FIELD *field);
+SQLLEN get_transfer_octet_length(STMT *stmt, MYSQL_FIELD *field);
+SQLLEN get_display_size(STMT *stmt, MYSQL_FIELD *field);
+
+#define is_char_sql_type(type) \
+ ((type) == SQL_CHAR || (type) == SQL_VARCHAR || (type) == SQL_LONGVARCHAR)
+#define is_wchar_sql_type(type) \
+ ((type) == SQL_WCHAR || (type) == SQL_WVARCHAR || (type) == SQL_WLONGVARCHAR)
+#define is_binary_sql_type(type) \
+ ((type) == SQL_BINARY || (type) == SQL_VARBINARY || \
+ (type) == SQL_LONGVARBINARY)
+
+#define is_numeric_mysql_type(type) \
+ ((type) <= MYSQL_TYPE_NULL || (type) == MYSQL_TYPE_LONGLONG || \
+ (type) == MYSQL_TYPE_INT24 || (type) == MYSQL_TYPE_BIT || \
+ (type) == MYSQL_TYPE_NEWDECIMAL)
+
SQLRETURN SQL_API my_SQLBindParameter(SQLHSTMT hstmt,SQLUSMALLINT ipar,
SQLSMALLINT fParamType,
SQLSMALLINT fCType, SQLSMALLINT fSqlType,
Modified: trunk/driver/results.c
===================================================================
--- trunk/driver/results.c 2007-08-02 00:48:34 UTC (rev 626)
+++ trunk/driver/results.c 2007-08-02 17:04:03 UTC (rev 627)
@@ -515,8 +515,6 @@
SQLRETURN error;
MYSQL_FIELD *field;
STMT FAR *stmt= (STMT FAR*) hstmt;
- ulong transfer_length,precision,display_size;
- int type;
if ( (error= check_result(stmt)) != SQL_SUCCESS )
return error;
@@ -527,16 +525,12 @@
if ( !(field= mysql_fetch_field(stmt->result)) )
return set_error(stmt,MYERR_S1002,"Invalid column number",0);
- type=
unireg_to_sql_datatype(stmt,field,0,&transfer_length,&precision,&display_size
);
-/*
-printf( "[PAH][%s][%d][%s] type=%d\n", __FILE__, __LINE__, __FUNCTION__, type );
-*/
- if ( pnColumnSize )
- *pnColumnSize = precision;
- if ( pfSqlType )
- *pfSqlType= type;
- if ( pibScale )
- *pibScale= field->decimals;
+ if (pfSqlType)
+ *pfSqlType= get_sql_data_type(stmt, field, NULL);
+ if (pnColumnSize)
+ *pnColumnSize= get_column_size(stmt, field, FALSE);
+ if (pibScale)
+ *pibScale= max(0, get_decimal_digits(stmt, field));
if ( pfNullable )
*pfNullable= (((field->flags & (NOT_NULL_FLAG)) ==
NOT_NULL_FLAG) ?
@@ -581,7 +575,6 @@
SQLSMALLINT str_length;
SQLLEN strparam= 0;
SQLPOINTER nparam= 0;
- ulong transfer_length,precision,display_size;
SQLRETURN error;
if ( check_result(stmt) != SQL_SUCCESS )
@@ -673,56 +666,63 @@
break;
case SQL_DESC_DISPLAY_SIZE:
- (void)
unireg_to_sql_datatype(stmt,field,0,&transfer_length,&precision,
- &display_size);
- *NumericAttributePtr= display_size;
+ *NumericAttributePtr= get_display_size(stmt, field);
break;
- case SQL_DESC_FIXED_PREC_SCALE: /* need to verify later */
- {
- if ( field->type == MYSQL_TYPE_DECIMAL )
- *(SQLINTEGER *)NumericAttributePtr= SQL_TRUE;
- else
- *(SQLINTEGER *)NumericAttributePtr= SQL_FALSE;
- break;
- }
+ case SQL_DESC_FIXED_PREC_SCALE:
+ if (field->type == MYSQL_TYPE_DECIMAL ||
+ field->type == MYSQL_TYPE_NEWDECIMAL)
+ *(SQLINTEGER *)NumericAttributePtr= SQL_TRUE;
+ else
+ *(SQLINTEGER *)NumericAttributePtr= SQL_FALSE;
+ break;
- case SQL_COLUMN_LENGTH:
case SQL_DESC_LENGTH:
- case SQL_DESC_OCTET_LENGTH: /* need to validate again for octet length..*/
- (void)
unireg_to_sql_datatype(stmt,field,0,&transfer_length,&precision,
- &display_size);
- *NumericAttributePtr= transfer_length;
- break;
+ *NumericAttributePtr= get_column_size(stmt, field, TRUE);
+ break;
+ case SQL_COLUMN_LENGTH:
+ case SQL_DESC_OCTET_LENGTH:
+ /* Need to add 1 for \0 on character fields. */
+ *NumericAttributePtr= get_transfer_octet_length(stmt, field) +
+ test(field->charsetnr != 63);
+ break;
+
+ case SQL_DESC_LITERAL_SUFFIX:
case SQL_DESC_LITERAL_PREFIX:
- case SQL_DESC_LITERAL_SUFFIX:
- switch ( field->type )
- {
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_BLOB:
- return copy_str_data(SQL_HANDLE_STMT, stmt,
- CharacterAttributePtr,
- BufferLength, StringLengthPtr, "0x");
+ switch (field->type) {
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_YEAR:
+ if (field->charsetnr == 63)
+ {
+ if (FieldIdentifier == SQL_DESC_LITERAL_PREFIX)
+ return copy_str_data(SQL_HANDLE_STMT, stmt,
+ CharacterAttributePtr,
+ BufferLength, StringLengthPtr, "0x");
+ else
+ return copy_str_data(SQL_HANDLE_STMT, stmt,
+ CharacterAttributePtr,
+ BufferLength, StringLengthPtr, "");
+ }
+ else
+ return copy_str_data(SQL_HANDLE_STMT, stmt,
+ CharacterAttributePtr,
+ BufferLength, StringLengthPtr, "'");
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_YEAR:
- return copy_str_data(SQL_HANDLE_STMT, stmt,
- CharacterAttributePtr,
- BufferLength, StringLengthPtr, "'");
-
- default:
- return copy_str_data(SQL_HANDLE_STMT, stmt,
- CharacterAttributePtr,
- BufferLength, StringLengthPtr,"");
+ default:
+ return copy_str_data(SQL_HANDLE_STMT, stmt,
+ CharacterAttributePtr,
+ BufferLength, StringLengthPtr,"");
}
break;
@@ -760,14 +760,12 @@
case SQL_COLUMN_PRECISION:
case SQL_DESC_PRECISION:
- (void)
unireg_to_sql_datatype(stmt,field,0,&transfer_length,&precision,
- &display_size);
- *(SQLINTEGER *)NumericAttributePtr= precision;
- break;
+ *NumericAttributePtr= get_column_size(stmt, field, FALSE);
+ break;
case SQL_COLUMN_SCALE:
case SQL_DESC_SCALE:
- *(SQLINTEGER *)NumericAttributePtr= field->decimals;
+ *NumericAttributePtr= max(0, get_decimal_digits(stmt, field));
break;
case SQL_DESC_SCHEMA_NAME:
@@ -779,17 +777,25 @@
break;
case SQL_DESC_TYPE:
- case SQL_DESC_CONCISE_TYPE:
- *(SQLINTEGER *)NumericAttributePtr =
- unireg_to_sql_datatype(stmt, field, 0, &transfer_length, &precision,
- &display_size);
+ {
+ SQLSMALLINT type= get_sql_data_type(stmt, field, NULL);
+ if (type == SQL_DATE || type == SQL_TYPE_DATE || type == SQL_TIME ||
+ type == SQL_TYPE_TIME || type == SQL_TIMESTAMP ||
+ type == SQL_TYPE_TIMESTAMP)
+ type= SQL_DATETIME;
+ *(SQLINTEGER *)NumericAttributePtr= type;
break;
+ }
+ case SQL_DESC_CONCISE_TYPE:
+ *(SQLINTEGER *)NumericAttributePtr=
+ get_sql_data_type(stmt, field, NULL);
+ break;
+
case SQL_DESC_TYPE_NAME:
{
char buff[40];
- (void)unireg_to_sql_datatype(stmt,field,(char
*)buff,&transfer_length,
- &precision, &display_size);
+ (void)get_sql_data_type(stmt, field, buff);
return copy_str_data(SQL_HANDLE_STMT, stmt,
CharacterAttributePtr, BufferLength,
StringLengthPtr, buff);
Modified: trunk/driver/utility.c
===================================================================
--- trunk/driver/utility.c 2007-08-02 00:48:34 UTC (rev 626)
+++ trunk/driver/utility.c 2007-08-02 17:04:03 UTC (rev 627)
@@ -342,288 +342,504 @@
}
-/*
- @type : myodbc internal
- @purpose : get type, transfer length and precision for a unireg column
- note that timestamp is changed to YYYY-MM-DD HH:MM:SS type
+/**
+ Get the SQL data type and (optionally) type name for a MYSQL_FIELD.
- SQLUINTEGER
+ @param[in] stmt
+ @param[in] field
+ @param[out] buff
+ @return The SQL data type.
*/
-
-int unireg_to_sql_datatype(STMT FAR *stmt, MYSQL_FIELD *field, char *buff,
- ulong *transfer_length, ulong *precision,
- ulong *display_size)
+SQLSMALLINT get_sql_data_type(STMT *stmt, MYSQL_FIELD *field, char *buff)
{
- char *pos;
- my_bool field_is_binary= binary_field(field);
-/* PAH - SESSION 01
- if ( stmt->dbc->flag & (FLAG_FIELD_LENGTH | FLAG_SAFE) )
-*/ *transfer_length= *precision= *display_size= max(field->length,
- field->max_length);
-/* PAH - SESSION 01
- else
+ my_bool field_is_binary= test(field->charsetnr == 63);
- *transfer_length= *precision= *display_size= field->max_length;
-*/
+ switch (field->type) {
+ case MYSQL_TYPE_BIT:
+ if (buff)
+ (void)strmov(buff, "bit");
+ /*
+ MySQL's BIT type can have more than one bit, in which case we treat
+ it as a BINARY field.
+ */
+ return (field->length > 1) ? SQL_BINARY : SQL_BIT;
-/* PAH - SESSION 01
-printf( "[PAH][%s][%d][%s] field->type=%d field_is_binary=%d\n", __FILE__, __LINE__,
__FUNCTION__, field->type, field_is_binary );
-*/
- switch ( field->type )
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ if (buff)
+ (void)strmov(buff, "decimal");
+ return SQL_DECIMAL;
+
+ case MYSQL_TYPE_TINY:
+ /* MYSQL_TYPE_TINY could either be a TINYINT or a single CHAR. */
+ if (buff)
{
- case MYSQL_TYPE_BIT:
- if ( buff )
- {
- pos= strmov(buff,"bit");
- }
- *transfer_length= 1;
- return SQL_BIT;
+ buff= strmov(buff, (field->flags & NUM_FLAG) ? "tinyint" : "char");
+ if (field->flags & UNSIGNED_FLAG)
+ (void)strmov(buff, " unsigned");
+ }
+ return (field->flags & NUM_FLAG) ? SQL_TINYINT : SQL_CHAR;
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- *display_size= max(field->length,field->max_length) -
- test(!(field->flags & UNSIGNED_FLAG)) -
- test(field->decimals);
- *precision= *display_size;
- if ( buff ) strmov(buff,"decimal");
- return SQL_DECIMAL;
+ case MYSQL_TYPE_SHORT:
+ if (buff)
+ {
+ buff= strmov(buff, "smallint");
+ if (field->flags & UNSIGNED_FLAG)
+ (void)strmov(buff, " unsigned");
+ }
+ return SQL_SMALLINT;
- case MYSQL_TYPE_TINY:
- if ( num_field(field) )
- {
- if ( buff )
- {
- pos= strmov(buff,"tinyint");
- if ( field->flags & UNSIGNED_FLAG )
- strmov(pos," unsigned");
- }
- *transfer_length= 1;
- return SQL_TINYINT;
- }
- if ( buff )
- {
- pos= strmov(buff,"char");
- if ( field->flags & UNSIGNED_FLAG )
- strmov(pos," unsigned");
- }
- *transfer_length= 1;
- return SQL_CHAR;
+ case MYSQL_TYPE_INT24:
+ if (buff)
+ {
+ buff= strmov(buff, "mediumint");
+ if (field->flags & UNSIGNED_FLAG)
+ (void)strmov(buff, " unsigned");
+ }
+ return SQL_INTEGER;
- case MYSQL_TYPE_SHORT:
- if ( buff )
- {
- pos= strmov(buff,"smallint");
- if ( field->flags & UNSIGNED_FLAG )
- strmov(pos," unsigned");
- }
- *transfer_length= 2;
- return SQL_SMALLINT;
+ case MYSQL_TYPE_LONG:
+ if (buff)
+ {
+ buff= strmov(buff, "integer");
+ if (field->flags & UNSIGNED_FLAG)
+ (void)strmov(buff, " unsigned");
+ }
+ return SQL_INTEGER;
- case MYSQL_TYPE_INT24:
- if ( buff )
- {
- pos= strmov(buff,"mediumint");
- if ( field->flags & UNSIGNED_FLAG )
- strmov(pos," unsigned");
- }
- *transfer_length= 4;
- return SQL_INTEGER;
+ case MYSQL_TYPE_LONGLONG:
+ if (buff)
+ {
+ buff= strmov(buff, "bigint");
+ if (field->flags & UNSIGNED_FLAG)
+ (void)strmov(buff, " unsigned");
+ }
- case MYSQL_TYPE_LONG:
- if ( buff )
- {
- pos= strmov(buff,"integer");
- if ( field->flags & UNSIGNED_FLAG )
- strmov(pos," unsigned");
- }
- *transfer_length= 4;
- return SQL_INTEGER;
+ if (stmt->dbc->flag & FLAG_NO_BIGINT)
+ return SQL_INTEGER;
- case MYSQL_TYPE_LONGLONG:
- if ( buff )
- {
- pos= strmov(buff,"bigint");
- if ( field->flags & UNSIGNED_FLAG )
- strmov(pos," unsigned");
- }
- *transfer_length= 20;
- if ( stmt->dbc->flag & FLAG_NO_BIGINT )
- return SQL_INTEGER;
- if ( field->flags & UNSIGNED_FLAG )
- *transfer_length= *precision= 20;
- else
- *transfer_length= *precision= 19;
- return SQL_BIGINT;
+ return SQL_BIGINT;
- case MYSQL_TYPE_FLOAT:
- if ( buff )
- {
- pos= strmov(buff,"float");
- if ( field->flags & UNSIGNED_FLAG )
- strmov(pos," unsigned");
- }
- *transfer_length= 4;
- return SQL_REAL;
- case MYSQL_TYPE_DOUBLE:
- if ( buff )
- {
- pos= strmov(buff,"double");
- if ( field->flags & UNSIGNED_FLAG )
- strmov(pos," unsigned");
- }
- *transfer_length= 8;
- return SQL_DOUBLE;
+ case MYSQL_TYPE_FLOAT:
+ if (buff)
+ {
+ buff= strmov(buff, "float");
+ if (field->flags & UNSIGNED_FLAG)
+ (void)strmov(buff, " unsigned");
+ }
+ return SQL_REAL;
- case MYSQL_TYPE_NULL:
- if ( buff ) strmov(buff,"null");
- return SQL_VARCHAR;
+ case MYSQL_TYPE_DOUBLE:
+ if (buff)
+ {
+ buff= strmov(buff, "double");
+ if (field->flags & UNSIGNED_FLAG)
+ (void)strmov(buff, " unsigned");
+ }
+ return SQL_DOUBLE;
- case MYSQL_TYPE_YEAR:
- if ( buff )
- pos= strmov(buff,"year");
- *transfer_length= 2;
- return SQL_SMALLINT;
+ case MYSQL_TYPE_NULL:
+ if (buff)
+ (void)strmov(buff, "null");
+ return SQL_VARCHAR;
- case MYSQL_TYPE_TIMESTAMP:
- if ( buff ) strmov(buff,"timestamp");
- *transfer_length= 16; /* size of timestamp_struct */
- *precision= *display_size= 19;
- if ( stmt->dbc->env->odbc_ver == SQL_OV_ODBC3 )
- return SQL_TYPE_TIMESTAMP;
- return SQL_TIMESTAMP;
+ case MYSQL_TYPE_YEAR:
+ if (buff)
+ (void)strmov(buff, "year");
+ return SQL_SMALLINT;
- case MYSQL_TYPE_DATETIME:
- if ( buff ) strmov(buff,"datetime");
- *transfer_length= 16; /* size of timestamp_struct */
- *precision= *display_size= 19;
- if ( stmt->dbc->env->odbc_ver == SQL_OV_ODBC3 )
- return SQL_TYPE_TIMESTAMP;
- return SQL_TIMESTAMP;
+ case MYSQL_TYPE_TIMESTAMP:
+ if (buff)
+ (void)strmov(buff, "timestamp");
+ if (stmt->dbc->env->odbc_ver == SQL_OV_ODBC3)
+ return SQL_TYPE_TIMESTAMP;
+ return SQL_TIMESTAMP;
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_DATE:
- if ( buff ) strmov(buff,"date");
- *transfer_length= 6; /* size of date struct */
- *precision= *display_size= 10;
- if ( stmt->dbc->env->odbc_ver == SQL_OV_ODBC3 )
- return SQL_TYPE_DATE;
- return SQL_DATE;
+ case MYSQL_TYPE_DATETIME:
+ if (buff)
+ (void)strmov(buff, "datetime");
+ if (stmt->dbc->env->odbc_ver == SQL_OV_ODBC3)
+ return SQL_TYPE_TIMESTAMP;
+ return SQL_TIMESTAMP;
- case MYSQL_TYPE_TIME:
- if ( buff ) strmov(buff,"time");
- *transfer_length= 6; /* size of time struct */
- *precision= *display_size= 8;
- if ( stmt->dbc->env->odbc_ver == SQL_OV_ODBC3 )
- return SQL_TYPE_TIME;
- return SQL_TIME;
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_DATE:
+ if (buff)
+ (void)strmov(buff, "date");
+ if (stmt->dbc->env->odbc_ver == SQL_OV_ODBC3)
+ return SQL_TYPE_DATE;
+ return SQL_DATE;
- case MYSQL_TYPE_STRING:
- /* Binary flag is for handling "VARCHAR() BINARY" but is unreliable (see
BUG-4578) - PAH */
- if (field_is_binary)
- {
- if (buff) strmov(buff,"binary");
- return SQL_BINARY;
- }
+ case MYSQL_TYPE_TIME:
+ if (buff)
+ (void)strmov(buff, "time");
+ if (stmt->dbc->env->odbc_ver == SQL_OV_ODBC3)
+ return SQL_TYPE_TIME;
+ return SQL_TIME;
- *transfer_length= *precision= *display_size= field->length ?
- (stmt->dbc->mysql.charset ?
- field->length/stmt->dbc->mysql.charset->mbmaxlen:
field->length): 255;
- if ( buff ) strmov(buff,"char");
- return SQL_CHAR;
+ case MYSQL_TYPE_STRING:
+ if (buff)
+ (void)strmov(buff, field_is_binary ? "binary" : "char");
- /*
- MYSQL_TYPE_VARCHAR is never actually sent, this just silences
- a compiler warning.
- */
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VAR_STRING:
- /*
- TODO: field->length should be replaced by max(length, maxlength)
- in order to restore FLAG_FIELD_LENGTH option
- */
- *transfer_length= *precision= *display_size= field->length ?
- (stmt->dbc->mysql.charset ?
- field->length / stmt->dbc->mysql.charset->mbmaxlen :
- field->length) : 255;
+ return field_is_binary ? SQL_BINARY : SQL_CHAR;
- /*
- TODO: Uncomment this code when MySQL Server returns the metadata correctly
+ /*
+ MYSQL_TYPE_VARCHAR is never actually sent, this just silences
+ a compiler warning.
+ */
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ if (buff)
+ (void)strmov(buff, field_is_binary ? "varbinary" : "varchar");
- if (field_is_binary)
- {
- if (buff)
- strmov(buff,"varbinary");
- return SQL_VARBINARY;
- }
- */
+ return field_is_binary ? SQL_VARBINARY : SQL_VARCHAR;
- if (buff)
- strmov(buff,"varchar");
+ case MYSQL_TYPE_TINY_BLOB:
+ if (buff)
+ (void)strmov(buff, field_is_binary ? "tinyblob" : "tinytext");
- return SQL_VARCHAR;
+ return field_is_binary ? SQL_LONGVARBINARY : SQL_LONGVARCHAR;
- case MYSQL_TYPE_TINY_BLOB:
- if ( buff )
- strmov(buff,(field_is_binary) ? "tinyblob" : "tinytext");
-/* PAH - SESSION 01
- if ( stmt->dbc->flag & (FLAG_FIELD_LENGTH | FLAG_SAFE) )
+ case MYSQL_TYPE_BLOB:
+ if (buff)
+ (void)strmov(buff, field_is_binary ? "blob" : "text");
+
+ return field_is_binary ? SQL_LONGVARBINARY : SQL_LONGVARCHAR;
+
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ if (buff)
+ (void)strmov(buff, field_is_binary ? "mediumblob" : "mediumtext");
+
+ return field_is_binary ? SQL_LONGVARBINARY : SQL_LONGVARCHAR;
+
+ case MYSQL_TYPE_LONG_BLOB:
+ if (buff)
+ (void)strmov(buff, field_is_binary ? "longblob" : "longtext");
+
+ return field_is_binary ? SQL_LONGVARBINARY : SQL_LONGVARCHAR;
+
+ case MYSQL_TYPE_ENUM:
+ if (buff)
+ (void)strmov(buff, "enum");
+ return SQL_CHAR;
+
+ case MYSQL_TYPE_SET:
+ if (buff)
+ (void)strmov(buff, "set");
+ return SQL_CHAR;
+
+ case MYSQL_TYPE_GEOMETRY:
+ if (buff)
+ (void)strmov(buff, "geometry");
+ return SQL_LONGVARBINARY;
+ }
+
+ if (buff)
+ *buff= '\0';
+ return SQL_UNKNOWN_TYPE;
+}
+
+
+/**
+ Get the column size (in characters) of a field, as defined at:
+ http://msdn2.microsoft.com/en-us/library/ms711786.aspx
+
+ @param[in] stmt
+ @param[in] field
+ @param[in] actual If true, field->max_length is used instead of
+ field->length, to retrieve the actual length of
+ data in the field
+
+ @return The column size of the field
*/
- *transfer_length= *precision= *display_size= field->length ?
- (stmt->dbc->mysql.charset ?
- field->length/stmt->dbc->mysql.charset->mbmaxlen:
field->length): 255;
- return(field_is_binary) ? SQL_LONGVARBINARY : SQL_LONGVARCHAR;
+SQLLEN get_column_size(STMT *stmt __attribute__((unused)), MYSQL_FIELD *field,
+ my_bool actual)
+{
+ CHARSET_INFO *charset= get_charset(field->charsetnr, MYF(0));
+ unsigned int mbmaxlen= charset ? charset->mbmaxlen : 1;
+ SQLLEN length= actual ? field->max_length : field->length;
- case MYSQL_TYPE_BLOB:
- if ( buff )
- strmov( buff, (field_is_binary) ? "blob" : "text" );
+ switch (field->type) {
+ case MYSQL_TYPE_TINY:
+ return (field->flags & NUM_FLAG) ? 3 : 1;
-/* PAH - SESSION 01
- if ( stmt->dbc->flag & (FLAG_FIELD_LENGTH | FLAG_SAFE) )
+ case MYSQL_TYPE_SHORT:
+ return 5;
+
+ case MYSQL_TYPE_LONG:
+ return 10;
+
+ case MYSQL_TYPE_FLOAT:
+ return 7;
+
+ case MYSQL_TYPE_DOUBLE:
+ return 15;
+
+ case MYSQL_TYPE_NULL:
+ return 0;
+
+ case MYSQL_TYPE_LONGLONG:
+ return (field->flags & UNSIGNED_FLAG) ? 20 : 19;
+
+ case MYSQL_TYPE_INT24:
+ return 8;
+
+ case MYSQL_TYPE_DATE:
+ return 10;
+
+ case MYSQL_TYPE_TIME:
+ return 8;
+
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_NEWDATE:
+ return 19;
+
+ case MYSQL_TYPE_YEAR:
+ return 4;
+
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ return (length -
+ test(!(field->flags & UNSIGNED_FLAG)) - /* sign? */
+ test(field->decimals)); /* decimal point? */
+
+ case MYSQL_TYPE_BIT:
+ /*
+ We treat a BIT(n) as a SQL_BIT if n == 1, otherwise we treat it
+ as a SQL_BINARY, so length is (bits + 7) / 8. * 2
+ */
+ if (length == 1)
+ return 1;
+ return (length + 7) / 8 * 2;
+
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ if (field->charsetnr == 63)
+ return length * 2;
+ else
+ return length / mbmaxlen;
+ }
+
+ return SQL_NO_TOTAL;
+}
+
+
+/**
+ Get the decimal digits of a field, as defined at:
+ http://msdn2.microsoft.com/en-us/library/ms709314.aspx
+
+ @param[in] stmt
+ @param[in] field
+
+ @return The decimal digits, or @c SQL_NO_TOTAL where it makes no sense
*/
- *transfer_length= *precision= *display_size= field->length ?
(stmt->dbc->mysql.charset ?
field->length/stmt->dbc->mysql.charset->mbmaxlen: field->length): 65535;
+SQLLEN get_decimal_digits(STMT *stmt __attribute__((unused)),
+ MYSQL_FIELD *field)
+{
+ switch (field->type) {
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ return field->decimals;
- return ( field_is_binary ) ? SQL_LONGVARBINARY : SQL_LONGVARCHAR;
+ /* All exact numeric types. */
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ return 0;
- case MYSQL_TYPE_MEDIUM_BLOB:
- if ( buff )
- strmov(buff,((field_is_binary) ? "mediumblob" :
- "mediumtext"));
-/* PAH - SESSION 01
- if ( stmt->dbc->flag & (FLAG_FIELD_LENGTH | FLAG_SAFE) )
+ /* We treat MYSQL_TYPE_BIT as an exact numeric type only for BIT(1). */
+ case MYSQL_TYPE_BIT:
+ if (field->length == 1)
+ return 0;
+
+ default:
+ return SQL_NO_TOTAL;
+ }
+}
+
+
+/**
+ Get the transfer octet length of a field, as defined at:
+ http://msdn2.microsoft.com/en-us/library/ms713979.aspx
+
+ @param[in] stmt
+ @param[in] field
+
+ @return The transfer octet length
*/
- *transfer_length= *precision= *display_size= field->length ?
- (stmt->dbc->mysql.charset ?
- field->length/stmt->dbc->mysql.charset->mbmaxlen:
field->length): (1L << 24)-1L;
- return(field_is_binary) ? SQL_LONGVARBINARY : SQL_LONGVARCHAR;
+SQLLEN get_transfer_octet_length(STMT *stmt __attribute__((unused)),
+ MYSQL_FIELD *field)
+{
+ switch (field->type) {
+ case MYSQL_TYPE_TINY:
+ return 1;
- case MYSQL_TYPE_LONG_BLOB:
- if ( buff )
- strmov(buff,((field_is_binary) ? "longblob": "longtext"));
-/* PAH - SESSION 01
- if ( stmt->dbc->flag & (FLAG_FIELD_LENGTH | FLAG_SAFE) )
+ case MYSQL_TYPE_SHORT:
+ return 2;
+
+ case MYSQL_TYPE_INT24:
+ return 3;
+
+ case MYSQL_TYPE_LONG:
+ return 4;
+
+ case MYSQL_TYPE_FLOAT:
+ return 4;
+
+ case MYSQL_TYPE_DOUBLE:
+ return 8;
+
+ case MYSQL_TYPE_NULL:
+ return 1;
+
+ case MYSQL_TYPE_LONGLONG:
+ return 20;
+
+ case MYSQL_TYPE_DATE:
+ return sizeof(SQL_DATE_STRUCT);
+
+ case MYSQL_TYPE_TIME:
+ return sizeof(SQL_TIME_STRUCT);
+
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_NEWDATE:
+ return sizeof(SQL_TIMESTAMP_STRUCT);
+
+ case MYSQL_TYPE_YEAR:
+ return 1;
+
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ return (field->length -
+ test(!(field->flags & UNSIGNED_FLAG)) - /* sign? */
+ test(field->decimals)); /* decimal point? */
+
+ case MYSQL_TYPE_BIT:
+ /*
+ We treat a BIT(n) as a SQL_BIT if n == 1, otherwise we treat it
+ as a SQL_BINARY, so length is (bits + 7) / 8. field->length has
+ the number of bits.
+ */
+ return (field->length + 7) / 8;
+
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ return field->length;
+ }
+
+ return SQL_NO_TOTAL;
+}
+
+
+/**
+ Get the display size of a field, as defined at:
+ http://msdn2.microsoft.com/en-us/library/ms713974.aspx
+
+ @param[in] stmt
+ @param[in] field
+
+ @return The display size
*/
- *transfer_length= *precision= *display_size= field->length ?
- (stmt->dbc->mysql.charset ?
- field->length/stmt->dbc->mysql.charset->mbmaxlen:
field->length): INT_MAX32;
- return(field_is_binary) ? SQL_LONGVARBINARY : SQL_LONGVARCHAR;
+SQLLEN get_display_size(STMT *stmt __attribute__((unused)),MYSQL_FIELD *field)
+{
+ CHARSET_INFO *charset= get_charset(field->charsetnr, MYF(0));
+ unsigned int mbmaxlen= charset ? charset->mbmaxlen : 1;
- case MYSQL_TYPE_ENUM:
- if ( buff )
- strmov(buff,"enum");
- return SQL_CHAR;
+ switch (field->type) {
+ case MYSQL_TYPE_TINY:
+ return 3 + test(field->flags & UNSIGNED_FLAG);
- case MYSQL_TYPE_SET:
- if ( buff )
- strmov(buff,"set");
- return SQL_CHAR;
+ case MYSQL_TYPE_SHORT:
+ return 5 + test(field->flags & UNSIGNED_FLAG);
- case MYSQL_TYPE_GEOMETRY:
- if ( buff )
- strmov(buff,"blob");
- return SQL_LONGVARBINARY;
- }
- return 0; /* Impossible */
+ case MYSQL_TYPE_INT24:
+ return 8 + test(field->flags & UNSIGNED_FLAG);
+
+ case MYSQL_TYPE_LONG:
+ return 10 + test(field->flags & UNSIGNED_FLAG);
+
+ case MYSQL_TYPE_FLOAT:
+ return 14;
+
+ case MYSQL_TYPE_DOUBLE:
+ return 24;
+
+ case MYSQL_TYPE_NULL:
+ return 1;
+
+ case MYSQL_TYPE_LONGLONG:
+ return 20;
+
+ case MYSQL_TYPE_DATE:
+ return 10;
+
+ case MYSQL_TYPE_TIME:
+ return 8;
+
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_NEWDATE:
+ return 19;
+
+ case MYSQL_TYPE_YEAR:
+ return 4;
+
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ return field->length;
+
+ case MYSQL_TYPE_BIT:
+ /*
+ We treat a BIT(n) as a SQL_BIT if n == 1, otherwise we treat it
+ as a SQL_BINARY, so display length is (bits + 7) / 8 * 2.
+ field->length has the number of bits.
+ */
+ if (field->length == 1)
+ return 1;
+ return (field->length + 7) / 8 * 2;
+
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ if (field->charsetnr == 63)
+ return field->length * 2;
+ else
+ return field->length / mbmaxlen;
+ }
+
+ return SQL_NO_TOTAL;
}
@@ -640,7 +856,11 @@
default:
return SQL_C_CHAR;
case MYSQL_TYPE_BIT:
- return SQL_C_BIT;
+ /*
+ MySQL's BIT type can have more than one bit, in which case we
+ treat it as a BINARY field.
+ */
+ return (field->length > 1) ? SQL_C_BINARY : SQL_C_BIT;
case MYSQL_TYPE_TINY:
return SQL_C_TINYINT;
case MYSQL_TYPE_YEAR:
Modified: trunk/test/my_basics.c
===================================================================
--- trunk/test/my_basics.c 2007-08-02 00:48:34 UTC (rev 626)
+++ trunk/test/my_basics.c 2007-08-02 17:04:03 UTC (rev 627)
@@ -259,6 +259,15 @@
SQLCHAR conn[256], conn_out[256];
SQLSMALLINT conn_out_len;
+ /**
+ Bug #19345: Table column length multiplies on size session character set
+ */
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_bug19345");
+ ok_sql(hstmt, "CREATE TABLE t_bug19345 (a VARCHAR(10), b VARBINARY(10))");
+ ok_sql(hstmt, "INSERT INTO t_bug19345 VALUES ('abc','def')");
+
+ ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE));
+
sprintf((char *)conn, "DSN=%s;UID=%s;PASSWORD=%s;CHARSET=utf8",
mydsn, myuid, mypwd);
if (mysock != NULL)
@@ -282,6 +291,22 @@
expect_stmt(hstmt1, SQLFetch(hstmt1), SQL_NO_DATA);
+ ok_stmt(hstmt1, SQLFreeStmt(hstmt1, SQL_CLOSE));
+
+ ok_stmt(hstmt1, SQLColumns(hstmt1, (SQLCHAR *)"test", SQL_NTS, NULL, 0,
+ (SQLCHAR *)"t_bug19345", SQL_NTS,
+ (SQLCHAR *)"%", 1));
+
+ ok_stmt(hstmt1, SQLFetch(hstmt1));
+ is_num(my_fetch_int(hstmt1, 7), 10);
+ is_num(my_fetch_int(hstmt1, 8), 30);
+ is_num(my_fetch_int(hstmt1, 16), 30);
+
+ ok_stmt(hstmt1, SQLFetch(hstmt1));
+ is_num(my_fetch_int(hstmt1, 7), 20);
+ is_num(my_fetch_int(hstmt1, 8), 10);
+ is_num(my_fetch_int(hstmt1, 16), 10);
+
ok_stmt(hstmt1, SQLFreeStmt(hstmt1, SQL_DROP));
ok_con(hdbc1, SQLDisconnect(hdbc1));
ok_con(hdbc1, SQLFreeHandle(SQL_HANDLE_DBC, hdbc1));
Modified: trunk/test/my_catalog.c
===================================================================
--- trunk/test/my_catalog.c 2007-08-02 00:48:34 UTC (rev 626)
+++ trunk/test/my_catalog.c 2007-08-02 17:04:03 UTC (rev 627)
@@ -480,13 +480,13 @@
SQLCHAR ColumnName[MAX_NAME_LEN], DatabaseName[MAX_NAME_LEN];
SQLINTEGER Values[7][5][2]=
{
- { {5,2}, {6,4}, {0,2}, {10,2}, {1,2}},
+ { {5,2}, {5,4}, {0,2}, {10,2}, {1,2}},
{ {1,2}, {5,4}, {0,-1}, {10,-1}, {1,2}},
{ {12,2}, {20,4}, {0,-1}, {10,-1}, {0,2}},
{ {3,2}, {10,4}, {2,2}, {10,2}, {1,2}},
- { {-6,2}, {4,4}, {0,2}, {10,2}, {0,2}},
- { {4,2}, {11,4}, {0,2}, {10,2}, {0,2}},
- { {-6,2}, {4,4}, {0,2}, {10,2}, {0,2}}
+ { {-6,2}, {3,4}, {0,2}, {10,2}, {0,2}},
+ { {4,2}, {10,4}, {0,2}, {10,2}, {0,2}},
+ { {-6,2}, {3,4}, {0,2}, {10,2}, {0,2}}
};
ok_sql(hstmt, "DROP TABLE IF EXISTS t_columns");
@@ -512,6 +512,7 @@
for (i= 0; i < ColumnCount; i++)
{
sprintf((char *)ColumnName, "col%d", (int)i);
+ printMessage("checking column `%s`", (char *)ColumnName);
ok_stmt(hstmt, SQLColumns(hstmt,
DatabaseName, cbDatabaseName,
Modified: trunk/test/my_datetime.c
===================================================================
--- trunk/test/my_datetime.c 2007-08-02 00:48:34 UTC (rev 626)
+++ trunk/test/my_datetime.c 2007-08-02 17:04:03 UTC (rev 627)
@@ -741,6 +741,74 @@
return OK;
}
+
+
+/**
+ Verify that we get correct data for SQL_DATA_TYPE and SQL_DATETIME_SUB
+ from SQLColumns(). Also check SQL_DESC_TYPE from SQLColAttribute().
+*/
+DECLARE_TEST(t_datecolumns)
+{
+ SQLCHAR col[10];
+ SQLINTEGER type;
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_datecolumns");
+ ok_sql(hstmt,
+ "CREATE TABLE t_datecolumns(a TIMESTAMP, b DATETIME, c DATE, d TIME)");
+
+ ok_stmt(hstmt, SQLColumns(hstmt, NULL, 0, NULL, 0,
+ (SQLCHAR *)"t_datecolumns", SQL_NTS, NULL, 0));
+
+ ok_stmt(hstmt, SQLFetch(hstmt));
+
+ is_str(my_fetch_str(hstmt, col, 4), "a", 1);
+ is_num(my_fetch_int(hstmt, 14), SQL_DATETIME);
+ is_num(my_fetch_int(hstmt, 15), SQL_TYPE_TIMESTAMP);
+
+ ok_stmt(hstmt, SQLFetch(hstmt));
+
+ is_str(my_fetch_str(hstmt, col, 4), "b", 1);
+ is_num(my_fetch_int(hstmt, 14), SQL_DATETIME);
+ is_num(my_fetch_int(hstmt, 15), SQL_TYPE_TIMESTAMP);
+
+ ok_stmt(hstmt, SQLFetch(hstmt));
+
+ is_str(my_fetch_str(hstmt, col, 4), "c", 1);
+ is_num(my_fetch_int(hstmt, 14), SQL_DATETIME);
+ is_num(my_fetch_int(hstmt, 15), SQL_TYPE_DATE);
+
+ ok_stmt(hstmt, SQLFetch(hstmt));
+
+ is_str(my_fetch_str(hstmt, col, 4), "d", 1);
+ is_num(my_fetch_int(hstmt, 14), SQL_DATETIME);
+ is_num(my_fetch_int(hstmt, 15), SQL_TYPE_TIME);
+
+ expect_stmt(hstmt, SQLFetch(hstmt), SQL_NO_DATA_FOUND);
+
+ ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE));
+
+ ok_sql(hstmt, "SELECT * FROM t_datecolumns");
+
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 1, SQL_DESC_TYPE, NULL, 0, NULL,
+ &type));
+ is_num(type, SQL_DATETIME);
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 2, SQL_DESC_TYPE, NULL, 0, NULL,
+ &type));
+ is_num(type, SQL_DATETIME);
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 3, SQL_DESC_TYPE, NULL, 0, NULL,
+ &type));
+ is_num(type, SQL_DATETIME);
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 4, SQL_DESC_TYPE, NULL, 0, NULL,
+ &type));
+ is_num(type, SQL_DATETIME);
+
+ ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE));
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_datecolumns");
+ return OK;
+}
+
+
BEGIN_TESTS
ADD_TEST(my_ts)
ADD_TEST(t_tstotime)
@@ -752,6 +820,7 @@
ADD_TEST(t_bug15773)
ADD_TEST(t_bug9927)
ADD_TODO(t_bug30081)
+ ADD_TEST(t_datecolumns)
END_TESTS
Modified: trunk/test/my_result.c
===================================================================
--- trunk/test/my_result.c 2007-08-02 00:48:34 UTC (rev 626)
+++ trunk/test/my_result.c 2007-08-02 17:04:03 UTC (rev 627)
@@ -258,8 +258,8 @@
SQLUSMALLINT icol,
const char *name,
SQLSMALLINT sql_type,
- SQLUINTEGER col_def,
- SQLUINTEGER col_def1,
+ SQLULEN col_def,
+ SQLULEN col_def1,
SQLSMALLINT scale,
SQLSMALLINT nullable)
{
@@ -334,36 +334,31 @@
fprintf(stdout,"total columns: %d\n", ColumnCount);
my_assert(ColumnCount == 23);
- desc_col_check(hstmt, 1, "c1", SQL_INTEGER, 10, 11, 0, SQL_NULLABLE);
- desc_col_check(hstmt, 2, "c2", SQL_BINARY, 2, 2, 0, SQL_NO_NULLS);
+ desc_col_check(hstmt, 1, "c1", SQL_INTEGER, 10, 10, 0, SQL_NULLABLE);
+ desc_col_check(hstmt, 2, "c2", SQL_BINARY, 4, 2, 0, SQL_NO_NULLS);
desc_col_check(hstmt, 3, "c3", SQL_CHAR, 1, 1, 0, SQL_NULLABLE);
desc_col_check(hstmt, 4, "c4", SQL_VARCHAR, 5, 5, 0, SQL_NULLABLE);
desc_col_check(hstmt, 5, "c5", SQL_DECIMAL, 10, 10, 3, SQL_NO_NULLS);
desc_col_check(hstmt, 6, "c6", SQL_TINYINT, 3, 4, 0, SQL_NULLABLE);
desc_col_check(hstmt, 7, "c7", SQL_SMALLINT, 5, 6, 0, SQL_NULLABLE);
desc_col_check(hstmt, 8, "c8", SQL_DECIMAL, 4, 4, 2, SQL_NULLABLE);
- desc_col_check(hstmt, 9, "c9", SQL_DOUBLE, 22, 24, 31, SQL_NULLABLE);
- desc_col_check(hstmt, 10, "c10", SQL_REAL, 12, 24, 31, SQL_NULLABLE);
+ desc_col_check(hstmt, 9, "c9", SQL_DOUBLE, 15, 15, 0, SQL_NULLABLE);
+ desc_col_check(hstmt, 10, "c10", SQL_REAL, 7, 7, 0, SQL_NULLABLE);
desc_col_check(hstmt, 11, "c11", SQL_BIGINT, 19, 19, 0, SQL_NO_NULLS);
- /*
- SQL_VARBINARY is temporarily disabled due to the problems with metadata
- returned by the server.
+ desc_col_check(hstmt, 12, "c12", SQL_VARBINARY, 24, 24, 0, SQL_NULLABLE);
- desc_col_check(hstmt, 12, "c12", SQL_VARBINARY, 12, 12, 0, SQL_NULLABLE);
- */
-
desc_col_check(hstmt, 13, "c13", SQL_CHAR, 20, 20, 0, SQL_NO_NULLS);
- desc_col_check(hstmt, 14, "c14", SQL_REAL, 10, 24, 3, SQL_NULLABLE);
+ desc_col_check(hstmt, 14, "c14", SQL_REAL, 7, 7, 0, SQL_NULLABLE);
desc_col_check(hstmt, 15, "c15", SQL_LONGVARCHAR, 255, 255, 0, SQL_NULLABLE);
desc_col_check(hstmt, 16, "c16", SQL_LONGVARCHAR, 65535, 65535, 0, SQL_NULLABLE);
desc_col_check(hstmt, 17, "c17", SQL_LONGVARCHAR, 16777215, 16777215, 0,
SQL_NULLABLE);
desc_col_check(hstmt, 18, "c18", SQL_LONGVARCHAR, 4294967295 , 16777215 , 0,
SQL_NULLABLE);
- desc_col_check(hstmt, 19, "c19", SQL_LONGVARBINARY, 255, 255, 0, SQL_NULLABLE);
- desc_col_check(hstmt, 20, "c20", SQL_LONGVARBINARY, 65535, 65535, 0, SQL_NULLABLE);
- desc_col_check(hstmt, 21, "c21", SQL_LONGVARBINARY, 16777215, 16777215, 0,
SQL_NULLABLE);
- desc_col_check(hstmt, 22, "c22", SQL_LONGVARBINARY, 4294967295 , 16777215 , 0,
SQL_NULLABLE);
- desc_col_check(hstmt, 23, "c23", SQL_LONGVARBINARY, 255, 5, 0, SQL_NULLABLE);
+ desc_col_check(hstmt, 19, "c19", SQL_LONGVARBINARY, 255 * 2, 255, 0, SQL_NULLABLE);
+ desc_col_check(hstmt, 20, "c20", SQL_LONGVARBINARY, 65535 * 2, 65535, 0,
SQL_NULLABLE);
+ desc_col_check(hstmt, 21, "c21", SQL_LONGVARBINARY, 16777215 * 2, 16777215, 0,
SQL_NULLABLE);
+ desc_col_check(hstmt, 22, "c22", SQL_LONGVARBINARY, 4294967295 * 2 , 16777215 , 0,
SQL_NULLABLE);
+ desc_col_check(hstmt, 23, "c23", SQL_LONGVARBINARY, 255 * 2, 5, 0, SQL_NULLABLE);
SQLFreeStmt(hstmt,SQL_CLOSE);
@@ -1132,7 +1127,7 @@
void desccol(SQLHSTMT hstmt, SQLCHAR *cname, SQLSMALLINT clen,
- SQLSMALLINT sqltype,SQLUINTEGER size,
+ SQLSMALLINT sqltype,SQLULEN size,
SQLSMALLINT scale,SQLSMALLINT isNull)
{
SQLRETURN rc =0;
@@ -1246,19 +1241,19 @@
rc = SQLFreeStmt(hstmt,SQL_CLOSE);
mystmt(hstmt,rc);
- desccol(hstmt,"t1",2,SQL_TINYINT,4,0,SQL_NULLABLE);
- desccol(hstmt,"t2",2,SQL_TINYINT,10,0,SQL_NULLABLE);
+ desccol(hstmt,"t1",2,SQL_TINYINT,3,0,SQL_NULLABLE);
+ desccol(hstmt,"t2",2,SQL_TINYINT,3,0,SQL_NULLABLE);
desccol(hstmt,"t3",2,SQL_TINYINT,3,0,SQL_NULLABLE);
- desccol(hstmt,"s1",2,SQL_SMALLINT,6,0,SQL_NULLABLE);
- desccol(hstmt,"s2",2,SQL_SMALLINT,10,0,SQL_NULLABLE);
+ desccol(hstmt,"s1",2,SQL_SMALLINT,5,0,SQL_NULLABLE);
+ desccol(hstmt,"s2",2,SQL_SMALLINT,5,0,SQL_NULLABLE);
desccol(hstmt,"s3",2,SQL_SMALLINT,5,0,SQL_NULLABLE);
- desccol(hstmt,"m1",2,SQL_INTEGER,9,0,SQL_NULLABLE);
- desccol(hstmt,"m2",2,SQL_INTEGER,10,0,SQL_NULLABLE);
+ desccol(hstmt,"m1",2,SQL_INTEGER,8,0,SQL_NULLABLE);
+ desccol(hstmt,"m2",2,SQL_INTEGER,8,0,SQL_NULLABLE);
desccol(hstmt,"m3",2,SQL_INTEGER,8,0,SQL_NULLABLE);
- desccol(hstmt,"i1",2,SQL_INTEGER,11,0,SQL_NULLABLE);
+ desccol(hstmt,"i1",2,SQL_INTEGER,10,0,SQL_NULLABLE);
desccol(hstmt,"i2",2,SQL_INTEGER,10,0,SQL_NO_NULLS);
desccol(hstmt,"i3",2,SQL_INTEGER,10,0,SQL_NULLABLE);
desccol(hstmt,"i4",2,SQL_INTEGER,10,0,SQL_NULLABLE);
@@ -1267,15 +1262,15 @@
desccol(hstmt,"b2",2,SQL_BIGINT,19,0,SQL_NULLABLE);
desccol(hstmt,"b3",2,SQL_BIGINT,20,0,SQL_NULLABLE);
- desccol(hstmt,"f1",2,SQL_REAL,12,31,SQL_NULLABLE);
- desccol(hstmt,"f2",2,SQL_REAL,12,31,SQL_NULLABLE);
- desccol(hstmt,"f3",2,SQL_REAL,12,31,SQL_NULLABLE);
- desccol(hstmt,"f4",2,SQL_REAL,10,4,SQL_NULLABLE);
+ desccol(hstmt,"f1",2,SQL_REAL,7,0,SQL_NULLABLE);
+ desccol(hstmt,"f2",2,SQL_REAL,7,0,SQL_NULLABLE);
+ desccol(hstmt,"f3",2,SQL_REAL,7,0,SQL_NULLABLE);
+ desccol(hstmt,"f4",2,SQL_REAL,7,0,SQL_NULLABLE);
- desccol(hstmt,"d1",2,SQL_DOUBLE,22,31,SQL_NULLABLE);
- desccol(hstmt,"d2",2,SQL_DOUBLE,30,3,SQL_NULLABLE);
- desccol(hstmt,"d3",2,SQL_DOUBLE,22,31,SQL_NULLABLE);
- desccol(hstmt,"d4",2,SQL_DOUBLE,30,3,SQL_NULLABLE);
+ desccol(hstmt,"d1",2,SQL_DOUBLE,15,0,SQL_NULLABLE);
+ desccol(hstmt,"d2",2,SQL_DOUBLE,15,0,SQL_NULLABLE);
+ desccol(hstmt,"d3",2,SQL_DOUBLE,15,0,SQL_NULLABLE);
+ desccol(hstmt,"d4",2,SQL_DOUBLE,15,0,SQL_NULLABLE);
rc = SQLFreeStmt(hstmt,SQL_CLOSE);
mystmt(hstmt,rc);
Modified: trunk/test/my_types.c
===================================================================
--- trunk/test/my_types.c 2007-08-02 00:48:34 UTC (rev 626)
+++ trunk/test/my_types.c 2007-08-02 17:04:03 UTC (rev 627)
@@ -485,6 +485,205 @@
}
+/**
+ Bug #27862: Function return incorrect SQL_COLUMN_SIZE
+*/
+DECLARE_TEST(t_bug27862_1)
+{
+ SQLLEN len;
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_bug27862");
+ ok_sql(hstmt, "CREATE TABLE t_bug27862 (a VARCHAR(2), b VARCHAR(2))");
+ ok_sql(hstmt, "INSERT INTO t_bug27862 VALUES ('a','b')");
+
+ ok_sql(hstmt, "SELECT CONCAT(a,b) FROM t_bug27862");
+
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 1, SQL_DESC_DISPLAY_SIZE, NULL, 0,
+ NULL, &len));
+ is_num(len, 4);
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 1, SQL_DESC_LENGTH, NULL, 0,
+ NULL, &len));
+ is_num(len, 2);
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 1, SQL_DESC_OCTET_LENGTH, NULL, 0,
+ NULL, &len));
+ is_num(len, 5);
+
+ ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE));
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_bug27862");
+
+ return OK;
+}
+
+
+/**
+ Because integers are given the charset 63 (binary) when they are
+ used as strings, functions like CONCAT() return a binary string.
+ This is a server bug that we do not try to work around.
+*/
+DECLARE_TEST(t_bug27862_2)
+{
+ SQLLEN len;
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_bug27862");
+ ok_sql(hstmt, "CREATE TABLE t_bug27862 (c DATE, d INT)");
+ ok_sql(hstmt, "INSERT INTO t_bug27862 VALUES ('2007-01-13',5)");
+
+ ok_sql(hstmt, "SELECT CONCAT_WS(' - ', DATE_FORMAT(c, '%b-%d-%y'), d) "
+ "FROM t_bug27862");
+
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 1, SQL_DESC_DISPLAY_SIZE, NULL, 0,
+ NULL, &len));
+ is_num(len, 104);
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 1, SQL_DESC_LENGTH, NULL, 0,
+ NULL, &len));
+ is_num(len, 26);
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 1, SQL_DESC_OCTET_LENGTH, NULL, 0,
+ NULL, &len));
+ is_num(len, 27);
+
+ ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE));
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_bug27862");
+
+ return OK;
+}
+
+
+/**
+ SQL_DESC_FIXED_PREC_SCALE was wrong for new DECIMAL types.
+*/
+DECLARE_TEST(decimal_scale)
+{
+ SQLINTEGER fixed= SQL_FALSE;
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_decscale");
+ ok_sql(hstmt, "CREATE TABLE t_decscale (a DECIMAL(5,3))");
+
+ ok_sql(hstmt, "SELECT * FROM t_decscale");
+
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 1, SQL_DESC_FIXED_PREC_SCALE,
+ NULL, 0, NULL, &fixed));
+
+ is_num(fixed, SQL_TRUE);
+
+ ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE));
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_decscale");
+ return OK;
+}
+
+
+/**
+ Wrong value returned for SQL_DESC_LITERAL_SUFFIX for binary field.
+*/
+DECLARE_TEST(binary_suffix)
+{
+ SQLCHAR suffix[10];
+ SQLSMALLINT len;
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_binarysuffix");
+ ok_sql(hstmt, "CREATE TABLE t_binarysuffix (a BINARY(10))");
+
+ ok_sql(hstmt, "SELECT * FROM t_binarysuffix");
+
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 1, SQL_DESC_LITERAL_SUFFIX,
+ suffix, 10, &len, NULL));
+
+ is_num(len, 0);
+
+ ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE));
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_binarysuffix");
+ return OK;
+}
+
+
+/**
+ Wrong value returned for SQL_DESC_SCALE for float and double.
+*/
+DECLARE_TEST(float_scale)
+{
+ SQLINTEGER scale;
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_floatscale");
+ ok_sql(hstmt, "CREATE TABLE t_floatscale(a FLOAT, b DOUBLE, c DECIMAL(3,2))");
+
+ ok_sql(hstmt, "SELECT * FROM t_floatscale");
+
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 1, SQL_DESC_SCALE,
+ NULL, 0, NULL, &scale));
+
+ is_num(scale, 0);
+
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 2, SQL_DESC_SCALE,
+ NULL, 0, NULL, &scale));
+
+ is_num(scale, 0);
+
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 3, SQL_DESC_SCALE,
+ NULL, 0, NULL, &scale));
+
+ is_num(scale, 2);
+
+ ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE));
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_floatscale");
+ return OK;
+}
+
+
+/**
+ Test the BIT type, which has different behavior for BIT(1) and BIT(n > 1).
+*/
+DECLARE_TEST(bit)
+{
+ SQLCHAR col[10];
+ SQLINTEGER type;
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_bit");
+ ok_sql(hstmt, "CREATE TABLE t_bit (a BIT(1), b BIT(17))");
+
+ ok_stmt(hstmt, SQLColumns(hstmt, NULL, 0, NULL, 0,
+ (SQLCHAR *)"t_bit", SQL_NTS, NULL, 0));
+
+ ok_stmt(hstmt, SQLFetch(hstmt));
+
+ is_str(my_fetch_str(hstmt, col, 4), "a", 1);
+ is_num(my_fetch_int(hstmt, 5), SQL_BIT); /* DATA_TYPE */
+ is_num(my_fetch_int(hstmt, 7), 1); /* COLUMN_SIZE */
+ is_num(my_fetch_int(hstmt, 8), 1); /* BUFFER_LENGTH */
+ is_num(my_fetch_int(hstmt, 16), 1); /* CHAR_OCTET_LENGTH */
+
+ ok_stmt(hstmt, SQLFetch(hstmt));
+
+ is_str(my_fetch_str(hstmt, col, 4), "b", 1);
+ is_num(my_fetch_int(hstmt, 5), SQL_BINARY); /* DATA_TYPE */
+ is_num(my_fetch_int(hstmt, 7), 6); /* COLUMN_SIZE */
+ is_num(my_fetch_int(hstmt, 8), 3); /* BUFFER_LENGTH */
+ is_num(my_fetch_int(hstmt, 16), 3); /* CHAR_OCTET_LENGTH */
+
+ expect_stmt(hstmt, SQLFetch(hstmt), SQL_NO_DATA_FOUND);
+
+ ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE));
+
+ ok_sql(hstmt, "SELECT * FROM t_bit");
+
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 1, SQL_DESC_TYPE, NULL, 0, NULL,
+ &type));
+ is_num(type, SQL_BIT);
+
+ ok_stmt(hstmt, SQLColAttribute(hstmt, 2, SQL_DESC_TYPE, NULL, 0, NULL,
+ &type));
+ is_num(type, SQL_BINARY);
+
+ ok_stmt(hstmt, SQLFreeStmt(hstmt, SQL_CLOSE));
+
+ ok_sql(hstmt, "DROP TABLE IF EXISTS t_bit");
+ return OK;
+}
+
+
BEGIN_TESTS
ADD_TEST(t_longlong1)
ADD_TEST(t_numeric)
@@ -493,6 +692,12 @@
ADD_TEST(t_enumset)
ADD_TEST(t_bug16917)
ADD_TEST(t_bug16235)
+ ADD_TEST(t_bug27862_1)
+ ADD_TODO(t_bug27862_2)
+ ADD_TEST(decimal_scale)
+ ADD_TEST(binary_suffix)
+ ADD_TEST(float_scale)
+ ADD_TEST(bit)
END_TESTS
| Thread |
|---|
| • Connector/ODBC 3.51 commit: r627 - in trunk: . driver test | jwinstead | 2 Aug |