in driver/cursor.cc [1353:1567]
static SQLRETURN batch_insert_std( STMT *stmt, SQLULEN irow, std::string &query )
{
MYSQL_RES *result= stmt->result; /* result set we are working with */
SQLULEN insert_count= 1; /* num rows to insert - will be real value when row is 0 (all) */
SQLULEN count= 0; /* current row */
SQLLEN length;
SQLUSMALLINT ncol;
long i;
size_t query_length= 0; /* our original query len so we can reset pos if break_insert */
my_bool break_insert= FALSE; /* true if we are to exceed max data size for transmission
but this seems to be misused */
DESCREC aprec_(DESC_PARAM, DESC_APP),
iprec_(DESC_PARAM, DESC_IMP);
DESCREC *aprec= &aprec_, *iprec= &iprec_;
SQLRETURN res;
stmt->stmt_options.bookmark_insert= FALSE;
/* determine the number of rows to insert when irow = 0 */
if ( !irow && stmt->ard->array_size > 1 ) /* batch wise */
{
insert_count= stmt->ard->array_size;
query_length= query.size();
}
do
{
/* Have we called exec_stmt_query() as a result of exceeding data size for transmission? If
so then we need to reset the pos. and start building a new statement. */
if ( break_insert )
{
query.erase(query_length);
}
/* For each row, build the value list from its columns */
while (count < insert_count)
{
/* Append values for each column. */
query.append("(");
for ( ncol= 0; ncol < result->field_count; ++ncol )
{
MYSQL_FIELD *field= stmt->dbc->connection_proxy->fetch_field_direct(result, ncol);
DESCREC *arrec;
SQLLEN ind_or_len= 0;
arrec= desc_get_rec(stmt->ard, ncol, FALSE);
/* if there's a separate APD for this (dae), use it */
if (stmt->setpos_apd)
aprec= desc_get_rec(stmt->setpos_apd.get(), ncol, FALSE);
else
aprec->reset_to_defaults();
if (arrec)
{
if (aprec->par.is_dae)
ind_or_len= aprec->par.val_length();
else if (arrec->octet_length_ptr)
ind_or_len= *(SQLLEN *)
ptr_offset_adjust(arrec->octet_length_ptr,
stmt->ard->bind_offset_ptr,
stmt->ard->bind_type,
sizeof(SQLLEN), count);
else
ind_or_len= arrec->octet_length;
iprec->concise_type= get_sql_data_type(stmt, field, NULL);
aprec->concise_type= arrec->concise_type;
aprec->type= get_type_from_concise_type(aprec->concise_type);
/* If column buffer type is interval - making sql type interval too. Making it for 2 supported interval types so far */
if (aprec->type == SQL_INTERVAL && (aprec->concise_type == SQL_C_INTERVAL_HOUR_TO_SECOND || aprec->concise_type == SQL_C_INTERVAL_HOUR_TO_MINUTE)
&& (iprec->concise_type == SQL_TYPE_TIME || iprec->concise_type == SQL_TIME))
{
iprec->type= aprec->type;
iprec->concise_type= aprec->concise_type;
}
/* copy prec and scale - needed for SQL_NUMERIC values */
iprec->precision= arrec->precision;
iprec->scale= arrec->scale;
if (stmt->dae_type && aprec->par.is_dae)
/* arrays or offsets are not supported for data-at-exec */
aprec->data_ptr= aprec->par.val();
else
aprec->data_ptr= ptr_offset_adjust(arrec->data_ptr,
stmt->ard->bind_offset_ptr,
stmt->ard->bind_type,
bind_length(arrec->concise_type,
(ulong)arrec->octet_length),
count);
}
switch (ind_or_len) {
case SQL_NTS:
if (aprec->data_ptr)
length= strlen((const char*)aprec->data_ptr);
break;
/*
We pass through SQL_COLUMN_IGNORE and SQL_NULL_DATA,
because the insert_data() that is eventually called knows
how to deal with them.
*/
case SQL_COLUMN_IGNORE:
case SQL_NULL_DATA:
default:
length= ind_or_len;
}
aprec->octet_length_ptr= &length;
aprec->indicator_ptr= &length;
if (copy_rowdata(stmt, aprec, iprec) != SQL_SUCCESS)
return SQL_ERROR;
} /* END OF for (ncol= 0; ncol < result->field_count; ++ncol) */
length = stmt->buf_pos();
query.append(stmt->buf(), length - 1);
stmt->buf_set_pos(0); // Buffer is used, can be reset
query.append("),");
++count;
/*
We have a limited capacity to shove data across the wire, but
we handle this by sending in multiple calls to exec_stmt_query()
*/
if (query.size() + length >= (SQLULEN) stmt->buf_len())
{
break_insert= TRUE;
break;
}
} /* END OF while(count < insert_count) */
query.erase(query.size() - 1);
if ( exec_stmt_query_std(stmt, query, false) !=
SQL_SUCCESS )
return(SQL_ERROR);
} while ( break_insert && count < insert_count );
if (stmt->stmt_options.bookmarks == SQL_UB_VARIABLE)
{
ulong copy_bytes= 0;
DESCREC *arrec;
long max_row;
arrec= desc_get_rec(stmt->ard, -1, FALSE);
max_row= (long) num_rows(stmt);
if (ARD_IS_BOUND(arrec))
{
SQLLEN *pcbValue= NULL;
SQLPOINTER TargetValuePtr= NULL;
for (i= max_row; i < (SQLINTEGER)insert_count; ++i)
{
pcbValue= NULL;
TargetValuePtr= NULL;
stmt->reset_getdata_position();
if (arrec->data_ptr)
{
TargetValuePtr= ptr_offset_adjust(arrec->data_ptr,
stmt->ard->bind_offset_ptr,
stmt->ard->bind_type,
(SQLINTEGER)arrec->octet_length,
i);
}
if (arrec->octet_length_ptr)
{
pcbValue= (SQLLEN*)ptr_offset_adjust(arrec->octet_length_ptr,
(SQLULEN*)stmt->ard->bind_offset_ptr,
stmt->ard->bind_type,
sizeof(SQLLEN), i);
}
std::string sval = std::to_string(i + 1);
res = sql_get_bookmark_data(stmt, arrec->concise_type, (uint)0,
TargetValuePtr, arrec->octet_length,
pcbValue, (char*)sval.data(),
(ulong)sval.length(), arrec);
if (!SQL_SUCCEEDED(res))
{
return SQL_ERROR;
}
}
stmt->ard->array_size= insert_count;
stmt->stmt_options.bookmark_insert= TRUE;
}
}
global_set_affected_rows(stmt, insert_count);
/* update row status pointer(s) */
if (stmt->ird->array_status_ptr)
{
for (count= insert_count; count--; )
stmt->ird->array_status_ptr[count]= SQL_ROW_ADDED;
}
if (stmt->stmt_options.rowStatusPtr_ex)
{
for (count= insert_count; count--; )
stmt->stmt_options.rowStatusPtr_ex[count]= SQL_ROW_ADDED;
}
return SQL_SUCCESS;
}