Skip to content

Commit 62010b2

Browse files
committed
Fix of how parameter codec process insdicator values.
Now it's processed by single coded set for the whole row as it is not individual for different column/codec types. It checks and sets inddicator values, e.g. in case of NULL value indicator. This row-level codec is now set always. Slightly optimized how descriptor values are read in codecs.
1 parent 626ea9a commit 62010b2

File tree

8 files changed

+86
-61
lines changed

8 files changed

+86
-61
lines changed

driver/class/ServerSidePreparedStatement.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -326,22 +326,31 @@ namespace mariadb
326326

327327
my_bool* defaultParamCallback(void* data, MYSQL_BIND* bind, uint32_t row_nr)
328328
{
329+
// Assuming paramset skip is set in the indicator of 1st column
330+
if (bind->u.indicator && *bind->u.indicator == STMT_INDICATOR_IGNORE_ROW) {
331+
return '\0';
332+
}
329333
// We can't let the callback to throw - we have to intercept, as otherwise we are guaranteed to have
330334
// the protocol broken
331335
try
332336
{
333337
ServerSidePreparedStatement *stmt= reinterpret_cast<ServerSidePreparedStatement*>(data);
334338

335339
for (uint32_t i= 0; i < stmt->getParamCount(); ++i) {
340+
auto current= bind + i;
341+
if (current->u.indicator && *current->u.indicator == STMT_INDICATOR_NULL) {
342+
continue;
343+
}
336344
const auto& it= stmt->parColCodec.find(i);
337-
/* Let's assume for now, that each column has to have a codec. But still we don't use vector and don't throw exception if not all of them have
338-
* For such columns we could assume, that we have normal arrays that we need to pass, and this function could do that simple job instead of callback.
339-
* But indicator arrow would still be needed. Thus maybe callback is still better. Another option could be - using default value(indicator for that)
340-
* But here there is another problem - the common "row" callback could take care of such columns
341-
* More likely that app will need to use array
342-
*/
345+
/* Let's assume for now, that each column has to have a codec. But still we don't use vector and don't throw exception
346+
* if not all of them have. For such columns we could assume, that we have normal arrays that we need to pass, and this
347+
* function could do that simple job instead of callback. But indicator array would still be needed. Thus maybe callback
348+
* is still better. Another option could be - using default value(indicator for that)
349+
* But here there is another problem - the common "row" callback could take care of such columns
350+
* More likely that app will need to use array
351+
*/
343352
if (it != stmt->parColCodec.end()) {
344-
if ((*it->second)(stmt->callbackData, bind + i, i, row_nr)) {
353+
if ((*it->second)(stmt->callbackData, current, i, row_nr)) {
345354
return (my_bool*)&error;
346355
}
347356
}
@@ -351,7 +360,7 @@ namespace mariadb
351360
{
352361
return (my_bool*)&error;
353362
}
354-
return NULL;
363+
return '\0';
355364
}
356365

357366

driver/interface/PreparedStatement.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@
2626

2727
namespace mariadb
2828
{
29-
/*const*/ char paramIndicatorNone= '\0', paramIndicatorNull= STMT_INDICATOR_NULL, paramIndicatorNts= STMT_INDICATOR_NTS, paramIndicatorIgnore= STMT_INDICATOR_IGNORE,
30-
paramIndicatorIgnoreRow= STMT_INDICATOR_IGNORE_ROW;
29+
/*const*/ char paramIndicatorNone= '\0',
30+
paramIndicatorNull= STMT_INDICATOR_NULL,
31+
paramIndicatorDef= STMT_INDICATOR_DEFAULT,
32+
paramIndicatorNts= STMT_INDICATOR_NTS,
33+
paramIndicatorIgnore= STMT_INDICATOR_IGNORE,
34+
paramIndicatorIgnoreRow= STMT_INDICATOR_IGNORE_ROW;
3135
/**
3236
* Constructor. Base class that permits setting parameters for client and server PrepareStatement.
3337
*

driver/interface/PreparedStatement.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
#include "class/ResultSetMetaData.h"
2929
namespace mariadb
3030
{
31-
extern char paramIndicatorNone, paramIndicatorNull, paramIndicatorNts, paramIndicatorIgnore,
31+
extern char paramIndicatorNone, paramIndicatorNull, paramIndicatorDef, paramIndicatorNts, paramIndicatorIgnore,
3232
paramIndicatorNull, paramIndicatorIgnoreRow;
3333
// The functor returns bool only to fit the need to check if to skip paramset, and I don't really need to introduce 2 diff callbacks for that, so one "universal"
3434
class ParamCodec
@@ -43,7 +43,10 @@ class PCodecCallable : public ParamCodec
4343
{
4444
public:
4545
virtual ~PCodecCallable() {}
46-
virtual bool operator()(void *data, MYSQL_BIND *bind, uint32_t col_nr, uint32_t row_nr) { return T(data, bind, col_nr, row_nr); }
46+
virtual bool operator()(void *data, MYSQL_BIND *bind, uint32_t col_nr, uint32_t row_nr)
47+
{
48+
return T(data, bind, col_nr, row_nr);
49+
}
4750
};
4851

4952

driver/ma_bulk.cpp

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,13 @@ void MADB_SetBulkOperLengthArr(MADB_Stmt *Stmt, MADB_DescRecord *CRec, SQLLEN *O
173173
}
174174

175175
if ((OctetLengthPtr != nullptr && OctetLengthPtr[row] == SQL_NULL_DATA)
176-
|| (IndicatorPtr != nullptr && IndicatorPtr[row] != SQL_NULL_DATA))
176+
|| (IndicatorPtr != nullptr && IndicatorPtr[row] == SQL_NULL_DATA))
177177
{
178178
MADB_SetIndicatorValue(Stmt, MaBind, row, SQL_NULL_DATA);
179179
continue;
180180
}
181181
if ((OctetLengthPtr != nullptr && OctetLengthPtr[row] == SQL_COLUMN_IGNORE)
182-
|| (IndicatorPtr != nullptr && IndicatorPtr[row] != SQL_COLUMN_IGNORE))
182+
|| (IndicatorPtr != nullptr && IndicatorPtr[row] == SQL_COLUMN_IGNORE))
183183
{
184184
MADB_SetIndicatorValue(Stmt, MaBind, row, SQL_COLUMN_IGNORE);
185185
continue;
@@ -270,9 +270,8 @@ void MADB_SetIndicatorValue(MADB_Stmt *Stmt, MYSQL_BIND *MaBind, unsigned int ro
270270
/* }}} */
271271

272272
/* {{{ */
273-
bool MADB_Stmt::setParamRowCallback(ParamCodec * callback)
273+
bool MADB_Stmt::setParamRowCallback(ParamCodec* callback)
274274
{
275-
//TODO should do all param codecs. and the operation below should be done once when 1st param codec is added, and not "row callback"
276275
if (paramCodec.capacity() < stmt->getParamCount()) {
277276
paramCodec.reserve(stmt->getParamCount());
278277
}
@@ -368,14 +367,7 @@ void MADB_Stmt::setupBulkCallbacks(uint32_t parNr, MADB_DescRecord* CRec, MADB_D
368367
auto parIt= paramCodec.begin() + parNr;
369368
paramCodec.insert(parIt, Unique::ParamCodec(nullptr));
370369
std::size_t dataArrStep= getArrayStep(Apd->Header, CRec->OctetLength);
371-
/*if (Apd->Header.ArrayStatusPtr != nullptr && Apd->Header.ArrayStatusPtr[row] == SQL_PARAM_IGNORE)
372-
{
373-
continue;
374-
}
375-
if (MaBind->u.indicator && MaBind->u.indicator[row] > STMT_INDICATOR_NONE)
376-
{
377-
continue;
378-
}*/
370+
379371
if (MADB_AppBufferCanBeUsed(CRec->ConciseType, SqlRec->ConciseType)) {
380372
paramCodec[parNr].reset(new FixedSizeCopyCodec(it));
381373
}
@@ -519,15 +511,14 @@ SQLRETURN MADB_ExecuteBulk(MADB_Stmt *Stmt, unsigned int ParamOffset)
519511
}
520512
}
521513
}
522-
514+
if (useCallbacks)
515+
{
516+
Stmt->stmt->setParamCallback(new IndicatorMapper(Stmt));
517+
}
523518
/* just to do this once, and to use already allocated indicator array */
524519
if (Stmt->Bulk.HasRowsToSkip)
525520
{
526-
if (useCallbacks)
527-
{
528-
Stmt->stmt->setParamCallback(new IgnoreRow(Stmt->Apd->Header.ArrayStatusPtr, Stmt->ArrayOffset));
529-
}
530-
else
521+
if (!useCallbacks)
531522
{
532523
SQLULEN row, Start= Stmt->ArrayOffset;
533524
if (IndIdx == (unsigned int)-1)

driver/ma_codec.cpp

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,44 @@ namespace mariadb
3434
}
3535
}
3636

37+
IndicatorMapper::IndicatorMapper(MADB_Stmt *Stmt) :
38+
statusArr(Stmt->Apd->Header.ArrayStatusPtr + Stmt->ArrayOffset),
39+
indPtr(Stmt->Ipd->Header.Count, nullptr), // For all statement parameters, not only for bound by the application
40+
// (Ipd vs Apd)
41+
arrStep(getArrayStep(Stmt->Apd->Header, sizeof(SQLLEN)))
42+
{
43+
for (auto i= 0; i < Stmt->Ipd->Header.Count; ++i) {
44+
auto CRec= MADB_DescGetInternalRecord(Stmt->Apd, i, MADB_DESC_READ);
45+
if (CRec->inUse) {
46+
indPtr[i]= static_cast<SQLLEN*>(GetBindOffset(Stmt->Ipd->Header, CRec->IndicatorPtr, 0, sizeof(SQLLEN)));
47+
}
48+
}
49+
}
50+
51+
bool IndicatorMapper::operator()(void *data, MYSQL_BIND *bind, uint32_t col_nr, uint32_t row_nr) {
52+
if (statusArr && statusArr[row_nr] == SQL_PARAM_IGNORE) {
53+
bind->u.indicator= &paramIndicatorIgnoreRow;
54+
return false;
55+
}
56+
else {
57+
bind->u.indicator= &paramIndicatorNone;
58+
}
59+
MADB_Stmt *stmt= static_cast<MADB_Stmt*>(data);
60+
for (auto i= 0; i < MADB_STMT_PARAM_COUNT(stmt); ++i) {
61+
auto indicator= indPtr[i];
62+
if (indicator == nullptr) {
63+
//(bind + i)->u.indicator= &paramIndicatorDef;
64+
}
65+
else {
66+
if (*indicator == SQL_NULL_DATA) {
67+
(bind + i)->u.indicator= &paramIndicatorNull;
68+
}
69+
indPtr[i]= indicator + arrStep;
70+
}
71+
}
72+
return false;
73+
}
74+
3775

3876
bool FixedSizeCopyCodec::operator()(void * data, MYSQL_BIND * bind, uint32_t col_nr, uint32_t row_nr)
3977
{
@@ -393,12 +431,7 @@ namespace mariadb
393431
SQLLEN buffCharLen= it.getDescRec()->OctetLength/sizeof(SQLWCHAR), charLen;
394432

395433
if (length == NULL_LENGTH) {
396-
if (it.indicator() != nullptr) {
397-
*it.indicator()= SQL_NULL_DATA;
398-
}
399-
else {
400-
*it.length()= SQL_NULL_DATA;
401-
}
434+
*it.indicator()= SQL_NULL_DATA;
402435
return;
403436
}
404437
if (MADB_ConvertAnsi2Unicode(&Stmt->Connection->Charset, (char *)row, (SQLLEN)length, (SQLWCHAR *)it.value(),
@@ -438,12 +471,7 @@ namespace mariadb
438471
MADB_Stmt *Stmt= reinterpret_cast<MADB_Stmt*>(data);
439472

440473
if (length == NULL_LENGTH) {
441-
if (it.indicator() != nullptr) {
442-
*it.indicator()= SQL_NULL_DATA;
443-
}
444-
else {
445-
*it.length()= SQL_NULL_DATA;
446-
}
474+
*it.indicator()= SQL_NULL_DATA;
447475
return;
448476
}
449477

driver/ma_codec.h

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,14 @@ namespace mariadb
2929

3030
// {'\0', STMT_INDICATOR_NULL, STMT_INDICATOR_NTS, STMT_INDICATOR_IGNORE, STMT_INDICATOR_NULL, STMT_INDICATOR_IGNORE_ROW};
3131

32-
class IgnoreRow : public ParamCodec
32+
class IndicatorMapper : public ParamCodec
3333
{
3434
SQLUSMALLINT *statusArr;
35+
std::vector<SQLLEN*> indPtr;
36+
std::size_t arrStep;
3537
public:
36-
IgnoreRow(SQLUSMALLINT* ArrStatusPtr, std::size_t initialOffset= 0) : statusArr(ArrStatusPtr + initialOffset) {}
37-
bool operator()(void *data, MYSQL_BIND *bind, uint32_t col_nr, uint32_t row_nr) override {
38-
if (statusArr[row_nr] == SQL_PARAM_IGNORE) {
39-
bind->u.indicator= &paramIndicatorIgnoreRow;
40-
return false;
41-
}
42-
else {
43-
bind->u.indicator= &paramIndicatorNone;
44-
}
45-
return true;
46-
}
38+
IndicatorMapper(MADB_Stmt *Stmt);
39+
bool operator()(void *data, MYSQL_BIND *bind, uint32_t col_nr, uint32_t row_nr) override;
4740
};
4841

4942

driver/ma_desc.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,10 +1085,6 @@ DescArrayIterator::DescArrayIterator(MADB_Header& header, MADB_DescRecord& rec,
10851085
, indicatorPtr(reinterpret_cast<SQLLEN*>(GetBindOffset(header, rec.IndicatorPtr, 0, sizeof(SQLLEN))))
10861086
, lengthOffset(getArrayStep(header, sizeof(SQLLEN)))
10871087
{
1088-
// Somewhere code depends on that. Maybe makes sense - less "noise"
1089-
if (indicatorPtr == octetLengthPtr) {
1090-
indicatorPtr= nullptr;
1091-
}
10921088
}
10931089

10941090

@@ -1098,7 +1094,7 @@ DescArrayIterator::DescArrayIterator(MADB_DescRecord& rec, void * val, std::size
10981094
, valueOffset(valOffset)
10991095
, endPtr(reinterpret_cast<void*>(reinterpret_cast<char*>(valuePtr) + valueOffset*arrSize))
11001096
, octetLengthPtr(len)
1101-
, indicatorPtr(ind != len ? ind : nullptr)
1097+
, indicatorPtr(ind)
11021098
, lengthOffset(lenOffset)
11031099
{
11041100
}

driver/ma_desc.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,11 @@ class DescArrayIterator
7878
DescArrayIterator(MADB_Header& header, MADB_DescRecord& rec, SQLSMALLINT i);
7979
DescArrayIterator(MADB_DescRecord& rec, void* val, std::size_t valOffset, SQLLEN* len, SQLLEN* ind, std::size_t lenOffset, std::size_t arrSize);
8080
inline void* next() {
81-
octetLengthPtr= reinterpret_cast<SQLLEN*>(reinterpret_cast<char*>(octetLengthPtr) + lengthOffset);
82-
if (indicatorPtr) {
81+
// The following condition has to be checked before octetLengthPtr is moved to the next value
82+
if (indicatorPtr != octetLengthPtr) {
8383
indicatorPtr= reinterpret_cast<SQLLEN*>(reinterpret_cast<char*>(indicatorPtr) + lengthOffset);
8484
}
85+
octetLengthPtr= reinterpret_cast<SQLLEN*>(reinterpret_cast<char*>(octetLengthPtr) + lengthOffset);
8586
return (valuePtr= (void*)((char*)valuePtr + valueOffset));
8687
}
8788
inline void* value() { return valuePtr; }

0 commit comments

Comments
 (0)