Skip to content

Commit

Permalink
[ODBC-90] Fix and the testcase. We inserted default values for ignored
Browse files Browse the repository at this point in the history
columns. In case of the timestamp that is a function, and that does not
work with prepared statements. The patch does not include ignored
columns in the query.
Also it fixes SQLCopyDesc - InternalBuffer pointers are not copied,
since that can cause them to be freed twice.
  • Loading branch information
lawrinn committed Mar 17, 2017
1 parent 939c888 commit d94541b
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 42 deletions.
19 changes: 16 additions & 3 deletions ma_desc.c
Expand Up @@ -1012,9 +1012,22 @@ SQLRETURN MADB_DescCopyDesc(MADB_Desc *SrcDesc, MADB_Desc *DestDesc)
memcpy(DestDesc->Records.buffer, SrcDesc->Records.buffer,
SrcDesc->Records.size_of_element * SrcDesc->Records.max_element);
DestDesc->Records.elements= SrcDesc->Records.elements;
/* todo: internal buffer needs to be clearead or we need to move it outside of
record structure
*/

/* internal buffer needs to be clearead or we will get it freed twice with all nice subsequences */
{
unsigned int i;

for (i= 0; i < DestDesc->Records.elements; ++i)
{
MADB_DescRecord *Rec= MADB_DescGetInternalRecord(DestDesc, i, MADB_DESC_READ);

if (Rec != NULL)
{
Rec->InternalBuffer= NULL;
}
}
}

return SQL_SUCCESS;
}
/* }}} */
Expand Down
27 changes: 26 additions & 1 deletion ma_helper.c
Expand Up @@ -404,6 +404,12 @@ MYSQL_RES *MADB_GetDefaultColumnValues(MADB_Stmt *Stmt, MYSQL_FIELD *fields)

for (i=0; i < mysql_stmt_field_count(Stmt->stmt); i++)
{
MADB_DescRecord *Rec= MADB_DescGetInternalRecord(Stmt->Ard, i, MADB_DESC_READ);

if (!Rec->inUse || MADB_ColumnIgnoredInAllRows(Stmt->Ard, Rec) == TRUE)
{
continue;
}
if (dynstr_append(&DynStr, i > 0 ? ",'" : "'") ||
dynstr_append(&DynStr, fields[i].org_name) ||
dynstr_append(&DynStr, "'"))
Expand All @@ -427,7 +433,7 @@ char *MADB_GetDefaultColumnValue(MYSQL_RES *res, const char *Column)
{
MYSQL_ROW row;

if (!res->row_count)
if (res == NULL || !res->row_count)
return NULL;
mysql_data_seek(res, 0);
while ((row= mysql_fetch_row(res)))
Expand Down Expand Up @@ -897,6 +903,25 @@ void *GetBindOffset(MADB_Desc *Desc, MADB_DescRecord *Record, void *Ptr, SQLULEN
return (char *)Ptr + BindOffset;
}

/* Checking if column ignored in all bound rows. Should hel*/
BOOL MADB_ColumnIgnoredInAllRows(MADB_Desc *Desc, MADB_DescRecord *Rec)
{
SQLULEN row;
SQLLEN *IndicatorPtr;

for (row= 0; row < Desc->Header.ArraySize; ++row)
{
IndicatorPtr= (SQLLEN *)GetBindOffset(Desc, Rec, Rec->IndicatorPtr, row, sizeof(SQLLEN));

if (IndicatorPtr == NULL || *IndicatorPtr != SQL_COLUMN_IGNORE)
{
return FALSE;
}
}

return TRUE;
}


void MADB_NumericInit(SQL_NUMERIC_STRUCT *number, MADB_DescRecord *Ard)
{
Expand Down
1 change: 1 addition & 0 deletions ma_helper.h
Expand Up @@ -49,6 +49,7 @@ char *MADB_GetTypeName(MYSQL_FIELD Field);
char *trim(char *Str);
my_bool MADB_CheckPtrLength(SQLINTEGER MaxLength, char *Ptr, SQLINTEGER NameLen);
void *GetBindOffset(MADB_Desc *Ard, MADB_DescRecord *ArdRecord, void *Ptr, SQLULEN RowNumber, size_t PtrSize);
BOOL MADB_ColumnIgnoredInAllRows(MADB_Desc *Desc, MADB_DescRecord *Rec);

SQLRETURN MADB_DaeStmt(MADB_Stmt *Stmt, SQLUSMALLINT Operation);
MYSQL_RES *MADB_GetDefaultColumnValues(MADB_Stmt *Stmt, MYSQL_FIELD *fields);
Expand Down
69 changes: 39 additions & 30 deletions ma_statement.c
Expand Up @@ -541,34 +541,31 @@ SQLRETURN MADB_StmtParamData(MADB_Stmt *Stmt, SQLPOINTER *ValuePtrPtr)
}
else
{
if (!Stmt->Ard || !(ParamCount= mysql_stmt_field_count(Stmt->stmt)))
if (!Stmt->Ard || !(ParamCount= Stmt->DaeStmt->ParamCount))
{
MADB_SetError(&Stmt->Error, MADB_ERR_HY010, NULL, 0);
return Stmt->Error.ReturnValue;
}
Desc= Stmt->Ard;
Desc= Stmt->DaeStmt->Apd;
}

/* for (RowNumber=0; RowNumber < MAX(1, Desc->Header.ArraySize); RowNumber ++) Do we need this?
We should use Stmt->DaeRowNumber to obtain correct offset */
/* If we have last DAE param(Stmt->PutParam), we are starting from the next one. Otherwise from first */
for (i= Stmt->PutParam > -1 ? Stmt->PutParam + 1 : 0; i < ParamCount; i++)
{
for (i= Stmt->PutParam > -1 ? Stmt->PutParam + 1 : 0; i < ParamCount; i++)
if ((Record= MADB_DescGetInternalRecord(Desc, i, MADB_DESC_READ)))
{
if ((Record= MADB_DescGetInternalRecord(Desc, i, MADB_DESC_READ)))
if (Record->OctetLengthPtr)
{
if (Record->OctetLengthPtr)
/* Stmt->DaeRowNumber is 1 based */
SQLLEN *OctetLength = (SQLLEN *)GetBindOffset(Desc, Record, Record->OctetLengthPtr, Stmt->DaeRowNumber > 1 ? Stmt->DaeRowNumber - 1 : 0, sizeof(SQLLEN));
if (PARAM_IS_DAE(OctetLength))
{
/* Stmt->DaeRowNumber is 1 based */
SQLLEN *OctetLength = (SQLLEN *)GetBindOffset(Desc, Record, Record->OctetLengthPtr, Stmt->DaeRowNumber > 1 ? Stmt->DaeRowNumber - 1 : 0, sizeof(SQLLEN));
if (PARAM_IS_DAE(OctetLength))
{
Stmt->PutDataRec= Record;
*ValuePtrPtr = GetBindOffset(Desc, Record, Record->DataPtr, MAX(0, Stmt->DaeRowNumber - 1), Record->OctetLength);
Stmt->PutParam= i;
Stmt->Status= SQL_NEED_DATA;
Stmt->PutDataRec= Record;
*ValuePtrPtr = GetBindOffset(Desc, Record, Record->DataPtr, MAX(0, Stmt->DaeRowNumber - 1), Record->OctetLength);
Stmt->PutParam= i;
Stmt->Status= SQL_NEED_DATA;

return SQL_NEED_DATA;
}
return SQL_NEED_DATA;
}
}
}
Expand Down Expand Up @@ -621,8 +618,9 @@ SQLRETURN MADB_StmtPutData(MADB_Stmt *Stmt, SQLPOINTER DataPtr, SQLLEN StrLen_or
}

if (Stmt->DataExecutionType != MADB_DAE_NORMAL)
{
MyStmt= Stmt->DaeStmt;

}
Record= MADB_DescGetInternalRecord(MyStmt->Apd, Stmt->PutParam, MADB_DESC_READ);
assert(Record);

Expand Down Expand Up @@ -4021,26 +4019,37 @@ SQLRETURN MADB_StmtSetPos(MADB_Stmt *Stmt, SQLSETPOSIROW RowNumber, SQLUSMALLINT
{
MADB_DescRecord *Rec= MADB_DescGetInternalRecord(Stmt->Ard, column, MADB_DESC_READ),
*ApdRec= NULL;
SQLLEN *IndicatorPtr= (SQLLEN *)GetBindOffset(Stmt->Ard, Rec, Rec->IndicatorPtr,
Stmt->DaeRowNumber > 1 ?Stmt->DaeRowNumber - 1 : 0, sizeof(SQLLEN)/*Rec->OctetLength*/);

if (Rec->inUse && MADB_ColumnIgnoredInAllRows(Stmt->Ard, Rec) == FALSE)
{
Stmt->DaeStmt->Methods->BindParam(Stmt->DaeStmt, param + 1, SQL_PARAM_INPUT, Rec->ConciseType, Rec->Type, Rec->DisplaySize, Rec->Scale,
Rec->DataPtr, Rec->OctetLength, Rec->OctetLengthPtr);
}
else
{
/*Stmt->DaeStmt->Methods->BindParam(Stmt->DaeStmt, param + 1, SQL_PARAM_INPUT, SQL_CHAR, SQL_C_CHAR, 0, 0,
ApdRec->DefaultValue, strlen(ApdRec->DefaultValue), NULL);*/
continue;
}

ApdRec= MADB_DescGetInternalRecord(Stmt->DaeStmt->Apd, param, MADB_DESC_READ);
ApdRec->DefaultValue= MADB_GetDefaultColumnValue(Stmt->DaeStmt->DefaultsResult,
Stmt->stmt->fields[column].org_name);
if (Rec->inUse)
Stmt->DaeStmt->Methods->BindParam(Stmt->DaeStmt, param + 1, SQL_PARAM_INPUT, Rec->ConciseType, Rec->Type, Rec->DisplaySize, Rec->Scale,
Rec->DataPtr, Rec->OctetLength, Rec->OctetLengthPtr);
else
Stmt->DaeStmt->Methods->BindParam(Stmt->DaeStmt, param + 1, SQL_PARAM_INPUT, SQL_CHAR, SQL_C_CHAR, 0, 0,
ApdRec->DefaultValue, strlen(ApdRec->DefaultValue), NULL);

Stmt->stmt->fields[column].org_name);

++param;
}

memcpy(&Stmt->DaeStmt->Apd->Header, &Stmt->Ard->Header, sizeof(MADB_Header));
//memcpy(&Stmt->DaeStmt->Apd->Header, &Stmt->Ard->Header, sizeof(MADB_Header));
Stmt->DaeStmt->Apd->Header.ArraySize= Stmt->Ard->Header.ArraySize;
Stmt->DaeStmt->Apd->Header.ArrayStatusPtr= Stmt->Ard->Header.ArrayStatusPtr;
Stmt->DaeStmt->Apd->Header.BindOffsetPtr= Stmt->Ard->Header.BindOffsetPtr;
Stmt->DaeStmt->Apd->Header.BindType= Stmt->Ard->Header.BindType;
Stmt->DaeStmt->Apd->Header.RowsProcessedPtr= Stmt->Ard->Header.RowsProcessedPtr;

ret= Stmt->Methods->Execute(Stmt->DaeStmt);
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
if (!SQL_SUCCEEDED(ret))
{
/* We can have SQL_NEED_DATA here, which would not set error (and its ReturnValue) */
MADB_CopyError(&Stmt->Error, &Stmt->DaeStmt->Error);
return ret;
}
Expand Down
10 changes: 3 additions & 7 deletions ma_string.c
Expand Up @@ -145,19 +145,15 @@ my_bool MADB_DynStrInsertSet(MADB_Stmt *Stmt, DYNAMIC_STRING *DynString)
return TRUE;
}

/* We use only columns, that have been bound, and are not IGNORED */
for (i= 0; i < MADB_STMT_COLUMN_COUNT(Stmt); i++)
{
SQLINTEGER *IndicatorPtr= NULL;
Record= MADB_DescGetInternalRecord(Stmt->Ard, i, MADB_DESC_READ);
if (Record->IndicatorPtr)
IndicatorPtr= (SQLINTEGER *)GetBindOffset(Stmt->Ard, Record, Record->IndicatorPtr, Stmt->DaeRowNumber > 1 ? Stmt->DaeRowNumber - 1 : 0,
sizeof(SQLLEN)/*Record->OctetLength*/);

/* We prepare query only once, different paramsets may have different SQL_COLUMN_IGNORE */
/*if (IndicatorPtr && *IndicatorPtr == SQL_COLUMN_IGNORE)
if (!Record->inUse || MADB_ColumnIgnoredInAllRows(Stmt->Ard, Record) == TRUE)
{
continue;
}*/
}

if ((NeedComma) &&
(dynstr_append(DynString, ",") || dynstr_append(&ColVals, ",")))
Expand Down
144 changes: 143 additions & 1 deletion test/bulk.c
Expand Up @@ -287,7 +287,6 @@ typedef struct {
SQLLEN ind;
} row;


/**
This is related to the fix for Bug #24306 -- handling of row-wise binding,
plus handling of SQL_ATTR_ROW_BIND_OFFSET_PTR, within the context of
Expand Down Expand Up @@ -373,6 +372,148 @@ ODBC_TEST(t_bulk_insert_rows)
return OK;
}

#define MAODBC_ROWS 2
ODBC_TEST(t_odbc90)
{
SQLHANDLE henv1;
SQLHANDLE Connection1;
SQLHANDLE Stmt1;
SQLCHAR conn[512], sval[MAODBC_ROWS][32]={"Record 1", "Record 21"};
SQLLEN ind1[MAODBC_ROWS]= {SQL_COLUMN_IGNORE, 0}, ind2[MAODBC_ROWS]= {sizeof(int), sizeof(int)},
ind3[MAODBC_ROWS]= {8, 9}, ind4[MAODBC_ROWS]={SQL_COLUMN_IGNORE, SQL_COLUMN_IGNORE};
SQLINTEGER nval[MAODBC_ROWS]={100, 500}, id[MAODBC_ROWS]={2, 7};

OK_SIMPLE_STMT(Stmt, "DROP TABLE IF EXISTS odbc90");
OK_SIMPLE_STMT(Stmt, "CREATE TABLE odbc90 (id int not null primary key auto_increment, \
nval int not null, sval varchar(32) not null, ts timestamp)");

/* odbc 3 */
/* This cursor closing is required, otherwise DM(on Windows) freaks out */
CHECK_STMT_RC(Stmt, SQLFreeStmt(Stmt, SQL_CLOSE));
CHECK_STMT_RC(Stmt, SQLSetStmtAttr(Stmt, SQL_ATTR_CURSOR_TYPE,
(SQLPOINTER)SQL_CURSOR_STATIC, 0));

CHECK_STMT_RC(Stmt,
SQLSetStmtAttr(Stmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)MAODBC_ROWS, 0));

CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 1, SQL_C_LONG, id, 0, ind1));
CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 2, SQL_C_LONG, nval, 0, ind2));
CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 3, SQL_C_CHAR, sval, sizeof(sval[0]), ind3));
CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 4, SQL_C_CHAR, NULL, 0, ind4));

OK_SIMPLE_STMT(Stmt, "SELECT id, nval, sval, ts FROM odbc90");

FAIL_IF(SQLFetchScroll(Stmt, SQL_FETCH_NEXT, 0)!=SQL_NO_DATA_FOUND, "SQL_NO_DATA_FOUND expected");

CHECK_STMT_RC(Stmt, SQLBulkOperations(Stmt, SQL_ADD));

CHECK_STMT_RC(Stmt, SQLFreeStmt(Stmt, SQL_UNBIND));
CHECK_STMT_RC(Stmt, SQLFreeStmt(Stmt, SQL_CLOSE));

CHECK_STMT_RC(Stmt, SQLSetStmtAttr(Stmt, SQL_ATTR_ROW_ARRAY_SIZE,
(SQLPOINTER)1, 0));

OK_SIMPLE_STMT(Stmt, "SELECT id, nval, sval, ts FROM odbc90");

ind4[0]= 0;
CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 1, SQL_C_LONG, id, 0, NULL));
CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 2, SQL_C_LONG, nval, 0, NULL));
CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 3, SQL_C_CHAR, sval[0], sizeof(sval[0]), NULL));
CHECK_STMT_RC(Stmt, SQLBindCol(Stmt, 4, SQL_C_CHAR, sval[1], sizeof(sval[0]), ind4));

CHECK_STMT_RC(Stmt, SQLFetchScroll(Stmt, SQL_FETCH_NEXT, 0));
is_num(id[0], 1);
is_num(nval[0], 100);
IS_STR(sval[0], "Record 1", ind3[0] + 1);
is_num(ind4[0], 19);

CHECK_STMT_RC(Stmt, SQLFetchScroll(Stmt, SQL_FETCH_NEXT, 0));
is_num(id[0], 7);
is_num(nval[0], 500);
IS_STR(sval[0], "Record 21", ind3[1] + 1);
is_num(ind4[0], 19);

FAIL_IF(SQLFetchScroll(Stmt, SQL_FETCH_NEXT, 0)!=SQL_NO_DATA_FOUND, "SQL_NO_DATA_FOUND expected");

/* odbc 2. Not sure if it's really needed internaly one call is mapped to another as well. But won't hurt. */
OK_SIMPLE_STMT(Stmt, "DROP TABLE IF EXISTS odbc90");
OK_SIMPLE_STMT(Stmt, "CREATE TABLE odbc90 (id int not null primary key auto_increment, \
nval int not null, sval varchar(32) not null, ts timestamp)");
id[0]= 2;
ind4[0]= SQL_COLUMN_IGNORE;
strcpy(sval[0], "Record 1");
strcpy(sval[1], "Record 21");
nval[0]= 100;

sprintf((char *)conn, "DRIVER=%s;SERVER=%s;UID=%s;PASSWORD=%s;DATABASE=%s%s;",
my_drivername, my_servername, my_uid, my_pwd, my_schema, ma_strport);

CHECK_ENV_RC(henv1, SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv1));
CHECK_ENV_RC(henv1, SQLSetEnvAttr(henv1, SQL_ATTR_ODBC_VERSION,
(SQLPOINTER)SQL_OV_ODBC2, SQL_IS_INTEGER));
CHECK_ENV_RC(henv1, SQLAllocHandle(SQL_HANDLE_DBC, henv1, &Connection1));
CHECK_DBC_RC(Connection1, SQLDriverConnect(Connection1, NULL, conn, (SQLSMALLINT)strlen(conn), NULL, 0,
NULL, SQL_DRIVER_NOPROMPT));
CHECK_DBC_RC(Connection1, SQLAllocHandle(SQL_HANDLE_STMT, Connection1, &Stmt1));

/* This cursor closing is required, otherwise DM(on Windows) freaks out */
CHECK_STMT_RC(Stmt1, SQLFreeStmt(Stmt1, SQL_CLOSE));
CHECK_STMT_RC(Stmt1, SQLSetStmtAttr(Stmt1, SQL_ATTR_CURSOR_TYPE,
(SQLPOINTER)SQL_CURSOR_STATIC, 0));

CHECK_STMT_RC(Stmt1,
SQLSetStmtAttr(Stmt1, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)MAODBC_ROWS, 0));

CHECK_STMT_RC(Stmt1, SQLBindCol(Stmt1, 1, SQL_C_LONG, id, 0, ind1));
CHECK_STMT_RC(Stmt1, SQLBindCol(Stmt1, 2, SQL_C_LONG, nval, 0, ind2));
CHECK_STMT_RC(Stmt1, SQLBindCol(Stmt1, 3, SQL_C_CHAR, sval, sizeof(sval[0]), ind3));
CHECK_STMT_RC(Stmt1, SQLBindCol(Stmt1, 4, SQL_C_CHAR, NULL, 0, ind4));

OK_SIMPLE_STMT(Stmt1, "SELECT id, nval, sval, ts FROM odbc90");

FAIL_IF(SQLExtendedFetch(Stmt1, SQL_FETCH_FIRST, 2, NULL, NULL)!=SQL_NO_DATA_FOUND, "SQL_NO_DATA_FOUND expected");

CHECK_STMT_RC(Stmt1, SQLSetPos(Stmt1, 0, SQL_ADD, SQL_LOCK_NO_CHANGE));

CHECK_STMT_RC(Stmt1, SQLFreeStmt(Stmt1, SQL_UNBIND));
CHECK_STMT_RC(Stmt1, SQLFreeStmt(Stmt1, SQL_CLOSE));

CHECK_STMT_RC(Stmt1, SQLSetStmtAttr(Stmt1, SQL_ATTR_ROW_ARRAY_SIZE,
(SQLPOINTER)1, 0));

OK_SIMPLE_STMT(Stmt1, "SELECT id, nval, sval, ts FROM odbc90");

ind4[0]= 0;
CHECK_STMT_RC(Stmt1, SQLBindCol(Stmt1, 1, SQL_C_LONG, id, 0, NULL));
CHECK_STMT_RC(Stmt1, SQLBindCol(Stmt1, 2, SQL_C_LONG, nval, 0, NULL));
CHECK_STMT_RC(Stmt1, SQLBindCol(Stmt1, 3, SQL_C_CHAR, sval[0], sizeof(sval[0]), NULL));
CHECK_STMT_RC(Stmt1, SQLBindCol(Stmt1, 4, SQL_C_CHAR, sval[1], sizeof(sval[0]), ind4));

CHECK_STMT_RC(Stmt1, SQLFetch(Stmt1));
is_num(id[0], 1);
is_num(nval[0], 100);
IS_STR(sval[0], "Record 1", ind3[0] + 1);
is_num(ind4[0], 19);

CHECK_STMT_RC(Stmt1, SQLFetch(Stmt1));
is_num(id[0], 7);
is_num(nval[0], 500);
IS_STR(sval[0], "Record 21", ind3[1] + 1);
is_num(ind4[0], 19);

FAIL_IF(SQLFetch(Stmt1)!=SQL_NO_DATA_FOUND, "SQL_NO_DATA_FOUND expected");

CHECK_STMT_RC(Stmt1, SQLFreeHandle(SQL_HANDLE_STMT, Stmt1));
CHECK_DBC_RC(Connection1, SQLDisconnect(Connection1));
CHECK_DBC_RC(Connection1, SQLFreeHandle(SQL_HANDLE_DBC, Connection1));
CHECK_ENV_RC(henv1, SQLFreeHandle(SQL_HANDLE_ENV, henv1));

OK_SIMPLE_STMT(Stmt, "DROP TABLE odbc90");

return OK;
}
#undef MAODBC_ROWS


MA_ODBC_TESTS my_tests[]=
{
Expand All @@ -382,6 +523,7 @@ MA_ODBC_TESTS my_tests[]=
{t_mul_pkdel, "t_mul_pkdel"},
{t_bulk_insert_indicator, "t_bulk_insert_indicator"},
{t_bulk_insert_rows, "t_bulk_insert_rows"},
{t_odbc90, "odbc90_insert_with_ts_col"},
{NULL, NULL}
};

Expand Down

0 comments on commit d94541b

Please sign in to comment.