Description:
There is a problem in the MyODBC driver - it does not support the
use of SQL_COLUMN_IGNORE in the indicator variable for a field when using SQLBulkOperations. It is being interpreted as a large negative number, and therefore is causing memory allocation errors when I attempt to add rows to a table using SQLBulkOperations and bound fields.
The most common usage for SQL_COLUMN_IGNORE is to have a field that is
bound (using SQLBindCol) for READING, but which you don't want used for
WRITING (eg. an AUTO_INCREMENTING INTEGER or something similar). My own
software uses this feature quite often.
Having examined the source, I have found that there is simply NO code present to deal with SQL_COLUMN_IGNORE when inserting using SQLBulkOperations. I have provided a tentative fix, but I believe this can cause problems with unbound columns.
How to repeat:
This is most problematic when using SQLBulkOperations to add a field to a table that uses an AUTO_INCREMENT (IDENTITY) field. You bind all of the fields, set the indicator variable for the unique number to 'SQL_COLUMN_IGNORE' and then attempt to add. An error will result, as there is a massive memory allocation problem trying to allocate huge (negative) amounts of memory.
Suggested fix:
The following changes make MyODBC function correctly when using
SQL_COLUMN_IGNORE in SQLBulkOperations insert statements.
All line numbers are based on the production version.
FILE: Cursor.c
LOCATION: Line 1033 (just after validating that there is a bound indicator
variable in batch_insert)
CODE: Marked with '#'
# if (*bind->pcbValue == SQL_COLUMN_IGNORE) continue;
FILE: Cursor.c
LOCATION: Line 1218 (just inside the FOR loop that iterates through the
fields in my_SQLSetPos, in the SQL_ADD case)
CODE: Marked with '#'
# PARAM_BIND parm;
# BIND *bind = stmt->bind+ncol;
#
# parm.buffer = (gptr)bind->rgbValue+count*bind->cbValueMax;
#
# if (parm.buffer)
# {
# if (bind->pcbValue)
# {
# if (*bind->pcbValue == SQL_COLUMN_IGNORE)
# {
# ncol++;
# continue;
# };
# };
# };
Effect of code changes:
These changes alter the INSERT INTO statements generated by the
SQLBulkOperations call so that they do not include the field name or field
value for any bound field who has an Indicator variable equal to
SQL_COLUMN_IGNORE.
While it is tempting to simply just treat SQL_COLUMN_IGNORE as
SQL_NULL_DATA, this is an incorrect implementation as it will not allow
default column values to appear. This seems the most effective method of
getting ignored columns to work correctly. If possible, I would like this
to become part of the standard code, as I plan to try to eventually offer
an optional MySQL and MyODBC license with my product - but this is not
possible if I have to use an unofficial version of the ODBC driver.
I hope people have no trouble with this code change.
Thanks,
Steven Harding
Push-A-Button Software