Skip to content

Commit dc10240

Browse files
committed
Bug#36989337 NDB Varbinary like columns fail with OO_SETVALUE
Problem: When writing values to varbinary columns using NdbRecord and OO_SETVALUE in the NDBAPI the write will fail with error 829 "Corrupt data received for insert/update". This since the value when sent to NDB cluster will be wrapped within a too small attribute which is checked in DBTUP in data nodes. The bug affects columns that uses the NDB Varchar, Varbinary, Longvarchar, and, Longvarbinary types. Fix: Make sure that the attribute will have room for both the bare value and the extra length bytes. Test: A new test is added to demonstrate failure: testNdbApi -n SetVarbinaryWithSetValue WIDE_COL Change-Id: I1dc2885457c59e7f19ea71637240504d57fd69a1
1 parent c8bdd7d commit dc10240

File tree

3 files changed

+93
-1
lines changed

3 files changed

+93
-1
lines changed

storage/ndb/src/ndbapi/NdbOperationExec.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2003, 2021, Oracle and/or its affiliates.
2+
Copyright (c) 2003, 2024, Oracle and/or its affiliates.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License, version 2.0,
@@ -1335,6 +1335,7 @@ NdbOperation::buildSignalsNdbRecord(Uint32 aTC_ConnectPtr,
13351335
setErrorCodeAbort(4209);
13361336
return -1;
13371337
}
1338+
length += lengthInfoBytes;
13381339
}
13391340
}
13401341

storage/ndb/test/ndbapi/testNdbApi.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8084,6 +8084,89 @@ testSlowConnectEnable(NDBT_Context* ctx, NDBT_Step* step)
80848084
return result;
80858085
}
80868086

8087+
int testSetVarbinaryWithSetValue(NDBT_Context *ctx, NDBT_Step *step)
8088+
{
8089+
// Test for bug#36989337 NDB Varbinary like columns fail with OO_SETVALUE
8090+
Ndb *pNdb = GETNDB(step);
8091+
const NdbDictionary::Table *pTab = ctx->getTab();
8092+
8093+
// Run as a 'WIDE_2COL' testcase - do nothing for other tables
8094+
if (strcmp(pTab->getName(), "WIDE_2COL") != 0) return NDBT_SKIPPED;
8095+
8096+
NdbTransaction *pTrans;
8097+
NdbOperation *pOp;
8098+
NdbDictionary::Dictionary *dict = pNdb->getDictionary();
8099+
char readbuf[NDB_MAX_TUPLE_SIZE_IN_WORDS << 2];
8100+
8101+
// Insert the test tuple ['xyz','abc']
8102+
CHECKE(pTrans = pNdb->startTransaction(), (*pNdb));
8103+
CHECKE(pOp = pTrans->getNdbOperation(pTab->getName()), (*pTrans));
8104+
CHECKE(pOp->insertTuple() == 0, (*pOp));
8105+
CHECKE(pOp->setValue("KEY", "\003\000xyz") == 0, (*pOp));
8106+
CHECKE(pOp->setValue("ATTR", "\003\000abc") == 0, (*pOp));
8107+
CHECKE(pTrans->execute(Commit) == 0, (*pTrans));
8108+
pTrans->close();
8109+
8110+
// Read and verify ATTR value
8111+
CHECKE(pTrans = pNdb->startTransaction(), (*pNdb));
8112+
CHECKE(pOp = pTrans->getNdbOperation(pTab->getName()), (*pTrans));
8113+
CHECKE(pOp->readTuple() == 0, (*pOp));
8114+
CHECKE(pOp->equal("KEY", "\003\000xyz") == 0, (*pOp));
8115+
CHECKE(pOp->getValue("ATTR", readbuf) != NULL, (*pOp));
8116+
CHECKE(pTrans->execute(NoCommit) == 0, (*pTrans));
8117+
CHECK(memcmp(readbuf, "\003\000abc", 5) == 0);
8118+
CHECKE(pTrans->getNdbError().code == 0, (*pTrans));
8119+
CHECKE(pTrans->execute(Rollback) == 0, (*pTrans));
8120+
pTrans->close();
8121+
8122+
// Insert the test tuple ['XYZ','ABC'] using NdbRecord and OO_SETVALUE
8123+
// Whole key must be in record for writeTuple
8124+
const NdbRecord *tabRec;
8125+
NdbDictionary::RecordSpecification spec[1];
8126+
spec->column =
8127+
pTab->getColumn("KEY"); // Whole key must be in record for writeTuple
8128+
spec->offset = 0;
8129+
spec->nullbit_byte_offset = 0;
8130+
spec->nullbit_bit_in_byte = 0;
8131+
spec->column_flags = 0;
8132+
tabRec = dict->createRecord(
8133+
pTab, spec, 1, sizeof(NdbDictionary::RecordSpecification),
8134+
NdbDictionary::RecMysqldBitfield | NdbDictionary::RecPerColumnFlags);
8135+
CHECKE(tabRec != NULL, (*dict));
8136+
8137+
const Uint32 rowLen = NDB_MAX_TUPLE_SIZE_IN_WORDS << 2;
8138+
char rowBuf[rowLen] = "\003\000XYZ";
8139+
unsigned char mask[1] = {(1 << 0) | (1 << 1)};
8140+
8141+
NdbOperation::SetValueSpec setValueSpec[1];
8142+
setValueSpec[0].column = pTab->getColumn("ATTR");
8143+
setValueSpec[0].value = "\003\000ABC";
8144+
8145+
NdbOperation::OperationOptions opts;
8146+
opts.optionsPresent = NdbOperation::OperationOptions::OO_SETVALUE;
8147+
opts.extraSetValues = setValueSpec;
8148+
opts.numExtraSetValues = 1;
8149+
8150+
CHECKE(pTrans = pNdb->startTransaction(), (*pNdb));
8151+
const NdbOperation * writeOp = pTrans->writeTuple(
8152+
tabRec, rowBuf, tabRec, NULL, mask, &opts, sizeof(opts));
8153+
CHECKE(writeOp != NULL, (*pTrans));
8154+
CHECKE(pTrans->execute(Commit) == 0, (*pTrans)); // Failed by bug#xyz
8155+
pTrans->close();
8156+
8157+
// Read and verify ATTR value
8158+
CHECKE(pTrans = pNdb->startTransaction(), (*pNdb));
8159+
CHECKE(pOp = pTrans->getNdbOperation(pTab->getName()), (*pTrans));
8160+
CHECKE(pOp->readTuple() == 0, (*pOp));
8161+
CHECKE(pOp->equal("KEY", "\003\000XYZ") == 0, (*pOp));
8162+
CHECKE(pOp->getValue("ATTR", readbuf) != NULL, (*pOp));
8163+
CHECKE(pTrans->execute(NoCommit) == 0, (*pTrans));
8164+
CHECK(memcmp(readbuf, "\003\000ABC", 5) == 0);
8165+
CHECKE(pTrans->execute(Rollback) == 0, (*pTrans));
8166+
pTrans->close();
8167+
8168+
return NDBT_OK;
8169+
}
80878170

80888171
NDBT_TESTSUITE(testNdbApi);
80898172
TESTCASE("MaxNdb",
@@ -8508,6 +8591,10 @@ TESTCASE("TestSlowConnectEnable",
85088591
{
85098592
STEP(testSlowConnectEnable);
85108593
}
8594+
TESTCASE("SetVarbinaryWithSetValue", "Check OO_SETVALUE works with Varbinary")
8595+
{
8596+
STEP(testSetVarbinaryWithSetValue);
8597+
}
85118598

85128599
NDBT_TESTSUITE_END(testNdbApi);
85138600

storage/ndb/test/run-test/daily-devel--07-tests.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,7 @@ cmd: testDict
293293
args: -n IndexStatNodeFailures T1
294294
max-time: 360
295295

296+
cmd: testNdbApi
297+
args: -n SetVarbinaryWithSetValue WIDE_COL
298+
max-time: 180
299+

0 commit comments

Comments
 (0)