in storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp [2677:3405]
int Dbtup::interpreterNextLab(Signal* signal,
KeyReqStruct* req_struct,
Uint32* logMemory,
Uint32* mainProgram,
Uint32 TmainProgLen,
Uint32* subroutineProg,
Uint32 TsubroutineLen,
Uint32 * tmpArea,
Uint32 tmpAreaSz)
{
register Uint32* TcurrentProgram= mainProgram;
register Uint32 TcurrentSize= TmainProgLen;
register Uint32 RnoOfInstructions= 0;
register Uint32 TprogramCounter= 0;
register Uint32 theInstruction;
register Uint32 theRegister;
Uint32 TdataWritten= 0;
Uint32 RstackPtr= 0;
union {
Uint32 TregMemBuffer[32];
Uint64 align[16];
};
(void)align; // kill warning
Uint32 TstackMemBuffer[32];
/* ---------------------------------------------------------------- */
// 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
ndbout_c("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:
jam();
/* ---------------------------------------------------------------- */
// 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,
false);
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) {
jam();
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.
/* ------------------------------------------------------------- */
ndbrequire(false);
}
break;
}
case Interpreter::WRITE_ATTR_FROM_REG:
jam();
{
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_struct.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:
jam();
TregMemBuffer[theRegister]= 0; /* NULL INDICATOR */
break;
case Interpreter::LOAD_CONST16:
jam();
TregMemBuffer[theRegister]= 0x50; /* 32 BIT UNSIGNED CONSTANT */
* (Int64*)(TregMemBuffer+theRegister+2)= theInstruction >> 16;
break;
case Interpreter::LOAD_CONST32:
jam();
TregMemBuffer[theRegister]= 0x50; /* 32 BIT UNSIGNED CONSTANT */
* (Int64*)(TregMemBuffer+theRegister+2)= *
(TcurrentProgram+TprogramCounter);
TprogramCounter++;
break;
case Interpreter::LOAD_CONST64:
jam();
TregMemBuffer[theRegister]= 0x60; /* 64 BIT UNSIGNED CONSTANT */
TregMemBuffer[theRegister + 2 ]= * (TcurrentProgram +
TprogramCounter++);
TregMemBuffer[theRegister + 3 ]= * (TcurrentProgram +
TprogramCounter++);
break;
case Interpreter::ADD_REG_REG:
jam();
{
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:
jam();
{
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) {
jam();
continue;
} else {
jam();
TprogramCounter= brancher(theInstruction, TprogramCounter);
}
break;
case Interpreter::BRANCH_REG_NE_NULL:
if (TregMemBuffer[theRegister] == 0) {
jam();
continue;
} else {
jam();
TprogramCounter= brancher(theInstruction, TprogramCounter);
}
break;
case Interpreter::BRANCH_EQ_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) {
jam();
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) {
jam();
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) {
jam();
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) {
jam();
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) {
jam();
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) {
jam();
if (Tleft0 >= Tright0){
TprogramCounter= brancher(theInstruction, TprogramCounter);
}
} else {
return TUPKEY_abort(req_struct, 28);
}
break;
}
case Interpreter::BRANCH_ATTR_OP_ARG_2:
case Interpreter::BRANCH_ATTR_OP_ARG:{
jam();
Uint32 cond = Interpreter::getBinaryCondition(theInstruction);
Uint32 ins2 = TcurrentProgram[TprogramCounter];
Uint32 attrId = Interpreter::getBranchCol_AttrId(ins2) << 16;
Uint32 argLen = Interpreter::getBranchCol_Len(ins2);
Uint32 step = argLen;
if(tmpHabitant != attrId){
Int32 TnoDataR = readAttributes(req_struct,
&attrId, 1,
tmpArea, tmpAreaSz,
false);
if (TnoDataR < 0) {
jam();
terrorCode = Uint32(-TnoDataR);
tupkeyErrorLab(req_struct);
return -1;
}
tmpHabitant= attrId;
}
// get type
attrId >>= 16;
Uint32 TattrDescrIndex = req_struct->tablePtrP->tabDescriptor +
(attrId << ZAD_LOG_SIZE);
Uint32 TattrDesc1 = tableDescriptor[TattrDescrIndex].tabDescr;
Uint32 TattrDesc2 = tableDescriptor[TattrDescrIndex+1].tabDescr;
Uint32 typeId = AttributeDescriptor::getType(TattrDesc1);
void * cs = 0;
if(AttributeOffset::getCharsetFlag(TattrDesc2))
{
Uint32 pos = AttributeOffset::getCharsetPos(TattrDesc2);
cs = req_struct->tablePtrP->charsetArray[pos];
}
const NdbSqlUtil::Type& sqlType = NdbSqlUtil::getType(typeId);
// get data
AttributeHeader ah(tmpArea[0]);
const char* s1 = (char*)&tmpArea[1];
const char* s2 = (char*)&TcurrentProgram[TprogramCounter+1];
// fixed length in 5.0
Uint32 attrLen = AttributeDescriptor::getSizeInBytes(TattrDesc1);
if (Interpreter::getOpCode(theInstruction) ==
Interpreter::BRANCH_ATTR_OP_ARG_2)
{
jam();
Uint32 paramNo = Interpreter::getBranchCol_ParamNo(ins2);
const Uint32 * paramptr = lookupInterpreterParameter(paramNo,
subroutineProg,
TsubroutineLen);
if (unlikely(paramptr == 0))
{
jam();
terrorCode = 99; // TODO
tupkeyErrorLab(req_struct);
return -1;
}
argLen = AttributeHeader::getByteSize(* paramptr);
step = 0;
s2 = (char*)(paramptr + 1);
}
if (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;
}
bool r1_null = ah.isNULL();
bool r2_null = argLen == 0;
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 {
jam();
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
ndbout_c("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:{
jam();
Uint32 ins2= TcurrentProgram[TprogramCounter];
Uint32 attrId= Interpreter::getBranchCol_AttrId(ins2) << 16;
if (tmpHabitant != attrId){
Int32 TnoDataR= readAttributes(req_struct,
&attrId, 1,
tmpArea, tmpAreaSz,
false);
if (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:{
jam();
Uint32 ins2= TcurrentProgram[TprogramCounter];
Uint32 attrId= Interpreter::getBranchCol_AttrId(ins2) << 16;
if (tmpHabitant != attrId){
Int32 TnoDataR= readAttributes(req_struct,
&attrId, 1,
tmpArea, tmpAreaSz,
false);
if (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:
jam();
#ifdef TRACE_INTERPRETER
ndbout_c(" - exit_ok");
#endif
return TdataWritten;
case Interpreter::EXIT_OK_LAST:
jam();
#ifdef TRACE_INTERPRETER
ndbout_c(" - exit_ok_last");
#endif
req_struct->last_row= true;
return TdataWritten;
case Interpreter::EXIT_REFUSE:
jam();
#ifdef TRACE_INTERPRETER
ndbout_c(" - exit_nok");
#endif
terrorCode= theInstruction >> 16;
return TUPKEY_abort(req_struct, 29);
case Interpreter::CALL:
jam();
#ifdef TRACE_INTERPRETER
ndbout_c(" - 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:
jam();
#ifdef TRACE_INTERPRETER
ndbout_c(" - return to %u from stack level %u",
TstackMemBuffer[RstackPtr],
RstackPtr);
#endif
if (RstackPtr > 0) {
TprogramCounter= TstackMemBuffer[RstackPtr];
RstackPtr--;
if (RstackPtr == 0) {
jam();
/* ------------------------------------------------------------- */
// 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);
}