in storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp [3344:4127]
int Dbtup::interpreterNextLab(Signal *signal, KeyReqStruct *req_struct,
Uint32 *logMemory, Uint32 *mainProgram,
Uint32 TmainProgLen, Uint32 *subroutineProg,
Uint32 TsubroutineLen, Uint32 *tmpArea,
Uint32 tmpAreaSz) {
Uint32 theRegister;
Uint32 theInstruction;
Uint32 TprogramCounter = 0;
Uint32 *TcurrentProgram = mainProgram;
Uint32 TcurrentSize = TmainProgLen;
Uint32 TdataWritten = 0;
Uint32 RstackPtr = 0;
union {
Uint32 TregMemBuffer[32];
Uint64 align[16];
};
(void)align; // kill warning
Uint32 TstackMemBuffer[32];
Uint32 &RnoOfInstructions = req_struct->no_exec_instructions;
ndbassert(RnoOfInstructions == 0);
/* ---------------------------------------------------------------- */
// Initialise all 8 registers to contain the NULL value.
// In this version we can handle 32 and 64 bit unsigned integers.
// They are handled as 64 bit values. Thus the 32 most significant
// bits are zeroed for 32 bit values.
/* ---------------------------------------------------------------- */
TregMemBuffer[0] = 0;
TregMemBuffer[4] = 0;
TregMemBuffer[8] = 0;
TregMemBuffer[12] = 0;
TregMemBuffer[16] = 0;
TregMemBuffer[20] = 0;
TregMemBuffer[24] = 0;
TregMemBuffer[28] = 0;
Uint32 tmpHabitant = ~0;
while (RnoOfInstructions < 8000) {
/* ---------------------------------------------------------------- */
/* EXECUTE THE NEXT INTERPRETER INSTRUCTION. */
/* ---------------------------------------------------------------- */
RnoOfInstructions++;
theInstruction = TcurrentProgram[TprogramCounter];
theRegister = Interpreter::getReg1(theInstruction) << 2;
#ifdef TRACE_INTERPRETER
g_eventLogger->info(
"Interpreter :"
" RnoOfInstructions : %u. TprogramCounter : %u. Opcode : %u",
RnoOfInstructions, TprogramCounter,
Interpreter::getOpCode(theInstruction));
#endif
if (TprogramCounter < TcurrentSize) {
TprogramCounter++;
switch (Interpreter::getOpCode(theInstruction)) {
case Interpreter::READ_ATTR_INTO_REG:
jamDebug();
/* ---------------------------------------------------------------- */
// Read an attribute from the tuple into a register.
// While reading an attribute we allow the attribute to be an array
// as long as it fits in the 64 bits of the register.
/* ---------------------------------------------------------------- */
{
Uint32 theAttrinfo = theInstruction;
int TnoDataRW =
readAttributes(req_struct, &theAttrinfo, (Uint32)1,
&TregMemBuffer[theRegister], (Uint32)3);
if (TnoDataRW == 2) {
/* -------------------------------------------------------------
*/
// Two words read means that we get the instruction plus one 32
// word read. Thus we set the register to be a 32 bit register.
/* -------------------------------------------------------------
*/
TregMemBuffer[theRegister] = 0x50;
// arithmetic conversion if big-endian
*(Int64 *)(TregMemBuffer + theRegister + 2) =
TregMemBuffer[theRegister + 1];
} else if (TnoDataRW == 3) {
/* -------------------------------------------------------------
*/
// Three words read means that we get the instruction plus two
// 32 words read. Thus we set the register to be a 64 bit
// register.
/* -------------------------------------------------------------
*/
TregMemBuffer[theRegister] = 0x60;
TregMemBuffer[theRegister + 3] = TregMemBuffer[theRegister + 2];
TregMemBuffer[theRegister + 2] = TregMemBuffer[theRegister + 1];
} else if (TnoDataRW == 1) {
/* -------------------------------------------------------------
*/
// One word read means that we must have read a NULL value. We set
// the register to indicate a NULL value.
/* -------------------------------------------------------------
*/
TregMemBuffer[theRegister] = 0;
TregMemBuffer[theRegister + 2] = 0;
TregMemBuffer[theRegister + 3] = 0;
} else if (TnoDataRW < 0) {
jamDebug();
terrorCode = Uint32(-TnoDataRW);
tupkeyErrorLab(req_struct);
return -1;
} else {
/* -------------------------------------------------------------
*/
// Any other return value from the read attribute here is not
// allowed and will lead to a system crash.
/* -------------------------------------------------------------
*/
ndbabort();
}
break;
}
case Interpreter::WRITE_ATTR_FROM_REG: {
jamDebug();
Uint32 TattrId = theInstruction >> 16;
Uint32 TattrDescrIndex =
req_struct->tablePtrP->tabDescriptor + (TattrId << ZAD_LOG_SIZE);
Uint32 TattrDesc1 = tableDescriptor[TattrDescrIndex].tabDescr;
Uint32 TregType = TregMemBuffer[theRegister];
/* --------------------------------------------------------------- */
// Calculate the number of words of this attribute.
// We allow writes into arrays as long as they fit into the 64 bit
// register size.
/* --------------------------------------------------------------- */
Uint32 TattrNoOfWords =
AttributeDescriptor::getSizeInWords(TattrDesc1);
Uint32 Toptype = req_struct->operPtrP->op_type;
Uint32 TdataForUpdate[3];
Uint32 Tlen;
AttributeHeader ah(TattrId, TattrNoOfWords << 2);
TdataForUpdate[0] = ah.m_value;
TdataForUpdate[1] = TregMemBuffer[theRegister + 2];
TdataForUpdate[2] = TregMemBuffer[theRegister + 3];
Tlen = TattrNoOfWords + 1;
if (Toptype == ZUPDATE) {
if (TattrNoOfWords <= 2) {
if (TattrNoOfWords == 1) {
// arithmetic conversion if big-endian
Int64 *tmp = new (&TregMemBuffer[theRegister + 2]) Int64;
TdataForUpdate[1] = Uint32(*tmp);
TdataForUpdate[2] = 0;
}
if (TregType == 0) {
/* --------------------------------------------------------- */
// Write a NULL value into the attribute
/* --------------------------------------------------------- */
ah.setNULL();
TdataForUpdate[0] = ah.m_value;
Tlen = 1;
}
int TnoDataRW =
updateAttributes(req_struct, &TdataForUpdate[0], Tlen);
if (TnoDataRW >= 0) {
/* --------------------------------------------------------- */
// Write the written data also into the log buffer so that it
// will be logged.
/* --------------------------------------------------------- */
logMemory[TdataWritten + 0] = TdataForUpdate[0];
logMemory[TdataWritten + 1] = TdataForUpdate[1];
logMemory[TdataWritten + 2] = TdataForUpdate[2];
TdataWritten += Tlen;
} else {
terrorCode = Uint32(-TnoDataRW);
tupkeyErrorLab(req_struct);
return -1;
}
} else {
return TUPKEY_abort(req_struct, 15);
}
} else {
return TUPKEY_abort(req_struct, 16);
}
break;
}
case Interpreter::LOAD_CONST_NULL:
jamDebug();
TregMemBuffer[theRegister] = 0; /* NULL INDICATOR */
break;
case Interpreter::LOAD_CONST16:
jamDebug();
TregMemBuffer[theRegister] = 0x50; /* 32 BIT UNSIGNED CONSTANT */
*(Int64 *)(TregMemBuffer + theRegister + 2) = theInstruction >> 16;
break;
case Interpreter::LOAD_CONST32:
jamDebug();
TregMemBuffer[theRegister] = 0x50; /* 32 BIT UNSIGNED CONSTANT */
*(Int64 *)(TregMemBuffer + theRegister + 2) =
*(TcurrentProgram + TprogramCounter);
TprogramCounter++;
break;
case Interpreter::LOAD_CONST64:
jamDebug();
TregMemBuffer[theRegister] = 0x60; /* 64 BIT UNSIGNED CONSTANT */
TregMemBuffer[theRegister + 2] =
*(TcurrentProgram + TprogramCounter++);
TregMemBuffer[theRegister + 3] =
*(TcurrentProgram + TprogramCounter++);
break;
case Interpreter::ADD_REG_REG:
jamDebug();
{
Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
Uint32 TdestRegister = Interpreter::getReg3(theInstruction) << 2;
Uint32 TrightType = TregMemBuffer[TrightRegister];
Int64 Tright0 = *(Int64 *)(TregMemBuffer + TrightRegister + 2);
Uint32 TleftType = TregMemBuffer[theRegister];
Int64 Tleft0 = *(Int64 *)(TregMemBuffer + theRegister + 2);
if ((TleftType | TrightType) != 0) {
Uint64 Tdest0 = Tleft0 + Tright0;
*(Int64 *)(TregMemBuffer + TdestRegister + 2) = Tdest0;
TregMemBuffer[TdestRegister] = 0x60;
} else {
return TUPKEY_abort(req_struct, 20);
}
break;
}
case Interpreter::SUB_REG_REG:
jamDebug();
{
Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
Uint32 TdestRegister = Interpreter::getReg3(theInstruction) << 2;
Uint32 TrightType = TregMemBuffer[TrightRegister];
Int64 Tright0 = *(Int64 *)(TregMemBuffer + TrightRegister + 2);
Uint32 TleftType = TregMemBuffer[theRegister];
Int64 Tleft0 = *(Int64 *)(TregMemBuffer + theRegister + 2);
if ((TleftType | TrightType) != 0) {
Int64 Tdest0 = Tleft0 - Tright0;
*(Int64 *)(TregMemBuffer + TdestRegister + 2) = Tdest0;
TregMemBuffer[TdestRegister] = 0x60;
} else {
return TUPKEY_abort(req_struct, 20);
}
break;
}
case Interpreter::BRANCH:
TprogramCounter = brancher(theInstruction, TprogramCounter);
break;
case Interpreter::BRANCH_REG_EQ_NULL:
if (TregMemBuffer[theRegister] != 0) {
jamDebug();
continue;
} else {
jamDebug();
TprogramCounter = brancher(theInstruction, TprogramCounter);
}
break;
case Interpreter::BRANCH_REG_NE_NULL:
if (TregMemBuffer[theRegister] == 0) {
jamDebug();
continue;
} else {
jamDebug();
TprogramCounter = brancher(theInstruction, TprogramCounter);
}
break;
case Interpreter::BRANCH_EQ_REG_REG: {
jamDebug();
Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
Uint32 TleftType = TregMemBuffer[theRegister];
Uint32 Tleft0 = TregMemBuffer[theRegister + 2];
Uint32 Tleft1 = TregMemBuffer[theRegister + 3];
Uint32 TrightType = TregMemBuffer[TrightRegister];
Uint32 Tright0 = TregMemBuffer[TrightRegister + 2];
Uint32 Tright1 = TregMemBuffer[TrightRegister + 3];
if ((TrightType | TleftType) != 0) {
jamDebug();
if ((Tleft0 == Tright0) && (Tleft1 == Tright1)) {
TprogramCounter = brancher(theInstruction, TprogramCounter);
}
} else {
return TUPKEY_abort(req_struct, 23);
}
break;
}
case Interpreter::BRANCH_NE_REG_REG: {
Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
Uint32 TleftType = TregMemBuffer[theRegister];
Uint32 Tleft0 = TregMemBuffer[theRegister + 2];
Uint32 Tleft1 = TregMemBuffer[theRegister + 3];
Uint32 TrightType = TregMemBuffer[TrightRegister];
Uint32 Tright0 = TregMemBuffer[TrightRegister + 2];
Uint32 Tright1 = TregMemBuffer[TrightRegister + 3];
if ((TrightType | TleftType) != 0) {
jamDebug();
if ((Tleft0 != Tright0) || (Tleft1 != Tright1)) {
TprogramCounter = brancher(theInstruction, TprogramCounter);
}
} else {
return TUPKEY_abort(req_struct, 24);
}
break;
}
case Interpreter::BRANCH_LT_REG_REG: {
Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
Uint32 TrightType = TregMemBuffer[TrightRegister];
Int64 Tright0 = *(Int64 *)(TregMemBuffer + TrightRegister + 2);
Uint32 TleftType = TregMemBuffer[theRegister];
Int64 Tleft0 = *(Int64 *)(TregMemBuffer + theRegister + 2);
if ((TrightType | TleftType) != 0) {
jamDebug();
if (Tleft0 < Tright0) {
TprogramCounter = brancher(theInstruction, TprogramCounter);
}
} else {
return TUPKEY_abort(req_struct, 24);
}
break;
}
case Interpreter::BRANCH_LE_REG_REG: {
Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
Uint32 TrightType = TregMemBuffer[TrightRegister];
Int64 Tright0 = *(Int64 *)(TregMemBuffer + TrightRegister + 2);
Uint32 TleftType = TregMemBuffer[theRegister];
Int64 Tleft0 = *(Int64 *)(TregMemBuffer + theRegister + 2);
if ((TrightType | TleftType) != 0) {
jamDebug();
if (Tleft0 <= Tright0) {
TprogramCounter = brancher(theInstruction, TprogramCounter);
}
} else {
return TUPKEY_abort(req_struct, 26);
}
break;
}
case Interpreter::BRANCH_GT_REG_REG: {
Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
Uint32 TrightType = TregMemBuffer[TrightRegister];
Int64 Tright0 = *(Int64 *)(TregMemBuffer + TrightRegister + 2);
Uint32 TleftType = TregMemBuffer[theRegister];
Int64 Tleft0 = *(Int64 *)(TregMemBuffer + theRegister + 2);
if ((TrightType | TleftType) != 0) {
jamDebug();
if (Tleft0 > Tright0) {
TprogramCounter = brancher(theInstruction, TprogramCounter);
}
} else {
return TUPKEY_abort(req_struct, 27);
}
break;
}
case Interpreter::BRANCH_GE_REG_REG: {
Uint32 TrightRegister = Interpreter::getReg2(theInstruction) << 2;
Uint32 TrightType = TregMemBuffer[TrightRegister];
Int64 Tright0 = *(Int64 *)(TregMemBuffer + TrightRegister + 2);
Uint32 TleftType = TregMemBuffer[theRegister];
Int64 Tleft0 = *(Int64 *)(TregMemBuffer + theRegister + 2);
if ((TrightType | TleftType) != 0) {
jamDebug();
if (Tleft0 >= Tright0) {
TprogramCounter = brancher(theInstruction, TprogramCounter);
}
} else {
return TUPKEY_abort(req_struct, 28);
}
break;
}
case Interpreter::BRANCH_ATTR_OP_ATTR:
case Interpreter::BRANCH_ATTR_OP_PARAM:
case Interpreter::BRANCH_ATTR_OP_ARG: {
jamDebug();
const Uint32 ins2 = TcurrentProgram[TprogramCounter];
Uint32 attrId = Interpreter::getBranchCol_AttrId(ins2) << 16;
const Uint32 opCode = Interpreter::getOpCode(theInstruction);
if (tmpHabitant != attrId) {
Int32 TnoDataR =
readAttributes(req_struct, &attrId, 1, tmpArea, tmpAreaSz);
if (unlikely(TnoDataR < 0)) {
jam();
terrorCode = Uint32(-TnoDataR);
tupkeyErrorLab(req_struct);
return -1;
}
tmpHabitant = attrId;
}
// get type
attrId >>= 16;
const Uint32 TattrDescrIndex =
req_struct->tablePtrP->tabDescriptor + (attrId << ZAD_LOG_SIZE);
const Uint32 TattrDesc1 = tableDescriptor[TattrDescrIndex].tabDescr;
const Uint32 TattrDesc2 =
tableDescriptor[TattrDescrIndex + 1].tabDescr;
const Uint32 typeId = AttributeDescriptor::getType(TattrDesc1);
const CHARSET_INFO *cs = nullptr;
if (AttributeOffset::getCharsetFlag(TattrDesc2)) {
const Uint32 pos = AttributeOffset::getCharsetPos(TattrDesc2);
cs = req_struct->tablePtrP->charsetArray[pos];
}
const NdbSqlUtil::Type &sqlType = NdbSqlUtil::getType(typeId);
// get data for 1st argument, always an ATTR.
const AttributeHeader ah(tmpArea[0]);
const char *s1 = (char *)&tmpArea[1];
// fixed length in 5.0
Uint32 attrLen = AttributeDescriptor::getSizeInBytes(TattrDesc1);
if (unlikely(typeId == NDB_TYPE_BIT)) {
/* Size in bytes for bit fields can be incorrect due to
* rounding down
*/
Uint32 bitFieldAttrLen =
(AttributeDescriptor::getArraySize(TattrDesc1) + 7) / 8;
attrLen = bitFieldAttrLen;
}
// 2'nd argument, literal, parameter or another attribute
Uint32 argLen = 0;
Uint32 step = 0;
const char *s2 = nullptr;
if (likely(opCode == Interpreter::BRANCH_ATTR_OP_ARG)) {
// Compare ATTR with a literal value given by interpreter code
jamDebug();
argLen = Interpreter::getBranchCol_Len(ins2);
step = argLen;
s2 = (char *)&TcurrentProgram[TprogramCounter + 1];
} else if (opCode == Interpreter::BRANCH_ATTR_OP_PARAM) {
// Compare ATTR with a parameter
jamDebug();
ndbassert(req_struct != nullptr);
ndbassert(req_struct->operPtrP != nullptr);
const Uint32 paramNo = Interpreter::getBranchCol_ParamNo(ins2);
const Uint32 *paramPos = subroutineProg;
const Uint32 *paramptr =
lookupInterpreterParameter(paramNo, paramPos);
if (unlikely(paramptr == nullptr)) {
jam();
terrorCode = 99; // TODO
tupkeyErrorLab(req_struct);
return -1;
}
argLen = AttributeHeader::getByteSize(*paramptr);
step = 0;
s2 = (char *)(paramptr + 1);
} else if (opCode == Interpreter::BRANCH_ATTR_OP_ATTR) {
// Compare ATTR with another ATTR
jamDebug();
Uint32 attr2Id = Interpreter::getBranchCol_AttrId2(ins2) << 16;
// Attr2 to be read into tmpArea[] after Attr1.
const Uint32 firstAttrWords = attrLen + 1;
assert(tmpAreaSz >= 2 * firstAttrWords);
Int32 TnoDataR = readAttributes(req_struct, &attr2Id, 1,
&tmpArea[firstAttrWords],
tmpAreaSz - firstAttrWords);
if (unlikely(TnoDataR < 0)) {
jam();
terrorCode = Uint32(-TnoDataR);
tupkeyErrorLab(req_struct);
return -1;
}
const AttributeHeader ah2(tmpArea[firstAttrWords]);
if (!ah2.isNULL()) {
// Get type
attr2Id >>= 16;
const Uint32 Tattr2DescrIndex =
req_struct->tablePtrP->tabDescriptor +
(attr2Id << ZAD_LOG_SIZE);
const Uint32 Tattr2Desc1 =
tableDescriptor[Tattr2DescrIndex].tabDescr;
const Uint32 type2Id = AttributeDescriptor::getType(Tattr2Desc1);
argLen = AttributeDescriptor::getSizeInBytes(Tattr2Desc1);
if (unlikely(type2Id == NDB_TYPE_BIT)) {
/* Size in bytes for bit fields can be incorrect due to
* rounding down
*/
Uint32 bitFieldAttrLen =
(AttributeDescriptor::getArraySize(Tattr2Desc1) + 7) / 8;
argLen = bitFieldAttrLen;
}
s2 = (char *)&tmpArea[firstAttrWords + 1];
}
step = 0;
} //! ah2.isNULL()
// Evaluate
const bool r1_null = ah.isNULL();
const bool r2_null = argLen == 0;
if (r1_null || r2_null) {
// There are NULL-valued operands, check the NullSemantics
const Uint32 nullSemantics =
Interpreter::getNullSemantics(theInstruction);
if (nullSemantics == Interpreter::IF_NULL_BREAK_OUT) {
// Branch out of AND conjunction
TprogramCounter = brancher(theInstruction, TprogramCounter);
break;
}
if (nullSemantics == Interpreter::IF_NULL_CONTINUE) {
// Ignore NULL in OR conjunction, -> next instruction
const Uint32 tmp = ((step + 3) >> 2) + 1;
TprogramCounter += tmp;
break;
}
}
const Uint32 cond = Interpreter::getBinaryCondition(theInstruction);
int res1;
if (cond <= Interpreter::GE) {
/* Inequality - EQ, NE, LT, LE, GT, GE */
if (r1_null || r2_null) {
// NULL==NULL and NULL<not-NULL
res1 = r1_null && r2_null ? 0 : r1_null ? -1 : 1;
} else {
jamDebug();
if (unlikely(sqlType.m_cmp == 0)) {
return TUPKEY_abort(req_struct, 40);
}
res1 = (*sqlType.m_cmp)(cs, s1, attrLen, s2, argLen);
}
} else {
if ((cond == Interpreter::LIKE) ||
(cond == Interpreter::NOT_LIKE)) {
if (r1_null || r2_null) {
// NULL like NULL is true (has no practical use)
res1 = r1_null && r2_null ? 0 : -1;
} else {
jam();
if (unlikely(sqlType.m_like == 0)) {
return TUPKEY_abort(req_struct, 40);
}
res1 = (*sqlType.m_like)(cs, s1, attrLen, s2, argLen);
}
} else {
/* AND_XX_MASK condition */
ndbassert(cond <= Interpreter::AND_NE_ZERO);
if (unlikely(sqlType.m_mask == 0)) {
return TUPKEY_abort(req_struct, 40);
}
/* If either arg is NULL, we say COL AND MASK
* NE_ZERO and NE_MASK.
*/
if (r1_null || r2_null) {
res1 = 1;
} else {
bool cmpZero = (cond == Interpreter::AND_EQ_ZERO) ||
(cond == Interpreter::AND_NE_ZERO);
res1 = (*sqlType.m_mask)(s1, attrLen, s2, argLen, cmpZero);
}
}
}
int res = 0;
switch ((Interpreter::BinaryCondition)cond) {
case Interpreter::EQ:
res = (res1 == 0);
break;
case Interpreter::NE:
res = (res1 != 0);
break;
// note the condition is backwards
case Interpreter::LT:
res = (res1 > 0);
break;
case Interpreter::LE:
res = (res1 >= 0);
break;
case Interpreter::GT:
res = (res1 < 0);
break;
case Interpreter::GE:
res = (res1 <= 0);
break;
case Interpreter::LIKE:
res = (res1 == 0);
break;
case Interpreter::NOT_LIKE:
res = (res1 == 1);
break;
case Interpreter::AND_EQ_MASK:
res = (res1 == 0);
break;
case Interpreter::AND_NE_MASK:
res = (res1 != 0);
break;
case Interpreter::AND_EQ_ZERO:
res = (res1 == 0);
break;
case Interpreter::AND_NE_ZERO:
res = (res1 != 0);
break;
// XXX handle invalid value
}
#ifdef TRACE_INTERPRETER
g_eventLogger->info(
"cond=%u attr(%d)='%.*s'(%d) str='%.*s'(%d) res1=%d res=%d", cond,
attrId >> 16, attrLen, s1, attrLen, argLen, s2, argLen, res1,
res);
#endif
if (res)
TprogramCounter = brancher(theInstruction, TprogramCounter);
else {
Uint32 tmp = ((step + 3) >> 2) + 1;
TprogramCounter += tmp;
}
break;
}
case Interpreter::BRANCH_ATTR_EQ_NULL: {
jamDebug();
Uint32 ins2 = TcurrentProgram[TprogramCounter];
Uint32 attrId = Interpreter::getBranchCol_AttrId(ins2) << 16;
if (tmpHabitant != attrId) {
Int32 TnoDataR =
readAttributes(req_struct, &attrId, 1, tmpArea, tmpAreaSz);
if (unlikely(TnoDataR < 0)) {
jam();
terrorCode = Uint32(-TnoDataR);
tupkeyErrorLab(req_struct);
return -1;
}
tmpHabitant = attrId;
}
AttributeHeader ah(tmpArea[0]);
if (ah.isNULL()) {
TprogramCounter = brancher(theInstruction, TprogramCounter);
} else {
TprogramCounter++;
}
break;
}
case Interpreter::BRANCH_ATTR_NE_NULL: {
jamDebug();
Uint32 ins2 = TcurrentProgram[TprogramCounter];
Uint32 attrId = Interpreter::getBranchCol_AttrId(ins2) << 16;
if (tmpHabitant != attrId) {
Int32 TnoDataR =
readAttributes(req_struct, &attrId, 1, tmpArea, tmpAreaSz);
if (unlikely(TnoDataR < 0)) {
jam();
terrorCode = Uint32(-TnoDataR);
tupkeyErrorLab(req_struct);
return -1;
}
tmpHabitant = attrId;
}
AttributeHeader ah(tmpArea[0]);
if (ah.isNULL()) {
TprogramCounter++;
} else {
TprogramCounter = brancher(theInstruction, TprogramCounter);
}
break;
}
case Interpreter::EXIT_OK:
jamDebug();
#ifdef TRACE_INTERPRETER
g_eventLogger->info(" - exit_ok");
#endif
return TdataWritten;
case Interpreter::EXIT_OK_LAST:
jamDebug();
#ifdef TRACE_INTERPRETER
g_eventLogger->info(" - exit_ok_last");
#endif
req_struct->last_row = true;
return TdataWritten;
case Interpreter::EXIT_REFUSE: {
/**
* This is a very common exit path, particularly
* for scans. It simply means that the row didn't
* fulfil the search condition.
*/
jamDebug();
#ifdef TRACE_INTERPRETER
g_eventLogger->info(" - exit_nok");
#endif
terrorCode = theInstruction >> 16;
tupkeyErrorLab(req_struct);
return -1;
}
case Interpreter::CALL:
jamDebug();
#ifdef TRACE_INTERPRETER
g_eventLogger->info(" - call addr=%u, subroutine len=%u ret addr=%u",
theInstruction >> 16, TsubroutineLen,
TprogramCounter);
#endif
RstackPtr++;
if (RstackPtr < 32) {
TstackMemBuffer[RstackPtr] = TprogramCounter;
TprogramCounter = theInstruction >> 16;
if (TprogramCounter < TsubroutineLen) {
TcurrentProgram = subroutineProg;
TcurrentSize = TsubroutineLen;
} else {
return TUPKEY_abort(req_struct, 30);
}
} else {
return TUPKEY_abort(req_struct, 31);
}
break;
case Interpreter::RETURN:
jamDebug();
#ifdef TRACE_INTERPRETER
g_eventLogger->info(" - return to %u from stack level %u",
TstackMemBuffer[RstackPtr], RstackPtr);
#endif
if (RstackPtr > 0) {
TprogramCounter = TstackMemBuffer[RstackPtr];
RstackPtr--;
if (RstackPtr == 0) {
jamDebug();
/* -------------------------------------------------------------
*/
// We are back to the main program.
/* -------------------------------------------------------------
*/
TcurrentProgram = mainProgram;
TcurrentSize = TmainProgLen;
}
} else {
return TUPKEY_abort(req_struct, 32);
}
break;
default:
return TUPKEY_abort(req_struct, 33);
}
} else {
return TUPKEY_abort(req_struct, 34);
}
}
return TUPKEY_abort(req_struct, 35);
}