in storage/ndb/ndbapi-examples/ndbapi_recattr_vs_record/main.cpp [2435:2959]
static void do_interpreted_update(Ndb &myNdb, ApiType accessType)
{
NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
const NdbDictionary::Table *myTable= myDict->getTable("api_recattr_vs_record");
const NdbDictionary::Index *myPIndex= myDict->getIndex("PRIMARY", "api_recattr_vs_record");
std::cout << "Running do_interpreted_update\n";
if (myTable == NULL)
APIERROR(myDict->getNdbError());
if (myPIndex == NULL)
APIERROR(myDict->getNdbError());
std::cout << "ATTR1 ATTR2 ATTR3" << std::endl;
NdbTransaction *myTransaction=myNdb.startTransaction();
if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
NdbRecAttr *recAttrAttr1;
NdbRecAttr *recAttrAttr2;
NdbRecAttr *recAttrAttr3;
NdbRecAttr *recAttrAttr11;
NdbRecAttr *recAttrAttr12;
NdbRecAttr *recAttrAttr13;
RowData rowData;
RowData rowData2;
/* Register aliases */
const Uint32 R1=1, R2=2, R3=3, R4=4, R5=5, R6=6;
switch (accessType)
{
case api_attr :
{
NdbOperation *pop;
pop=myTransaction->getNdbOperation(myTable);
if (pop == NULL) APIERROR(myTransaction->getNdbError());
if (pop->interpretedUpdateTuple())
APIERROR (pop->getNdbError());
/* Interpreted update on row where ATTR1 == 4 */
if (pop->equal("ATTR1", 4) != 0)
APIERROR (pop->getNdbError());
/* First, read the values of all attributes in the normal way */
recAttrAttr1=pop->getValue("ATTR1");
recAttrAttr2=pop->getValue("ATTR2");
recAttrAttr3=pop->getValue("ATTR3");
/* Now define interpreted program which will run after the
* values have been read
* This program is rather tortuous and doesn't achieve much other
* than demonstrating control flow, register and some column
* operations
*/
// R5= 3
if (pop->load_const_u32(R5, 3) != 0)
APIERROR (pop->getNdbError());
// R1= *ATTR1; R2= *ATTR2; R3= *ATTR3
if (pop->read_attr("ATTR1", R1) != 0)
APIERROR (pop->getNdbError());
if (pop->read_attr("ATTR2", R2) != 0)
APIERROR (pop->getNdbError());
if (pop->read_attr("ATTR3", R3) != 0)
APIERROR (pop->getNdbError());
// R3= R3-R5
if (pop->sub_reg(R3, R5, R3) != 0)
APIERROR (pop->getNdbError());
// R2= R1+R2
if (pop->add_reg(R1, R2, R2) != 0)
APIERROR (pop->getNdbError());
// *ATTR2= R2
if (pop->write_attr("ATTR2", R2) != 0)
APIERROR (pop->getNdbError());
// *ATTR3= R3
if (pop->write_attr("ATTR3", R3) != 0)
APIERROR (pop->getNdbError());
// *ATTR3 = *ATTR3 - 30
if (pop->subValue("ATTR3", (Uint32)30) != 0)
APIERROR (pop->getNdbError());
Uint32 comparisonValue= 10;
// if *ATTR3 > comparisonValue, goto Label 0
if (pop->branch_col_lt(pattr3Col->getColumnNo(),
&comparisonValue,
sizeof(Uint32),
false,
0) != 0)
APIERROR (pop->getNdbError());
// assert(false)
// Fail the operation with error 627 if we get here.
if (pop->interpret_exit_nok(627) != 0)
APIERROR (pop->getNdbError());
// Label 0
if (pop->def_label(0) != 0)
APIERROR (pop->getNdbError());
Uint32 comparisonValue2= 344;
// if *ATTR2 == comparisonValue, goto Label 1
if (pop->branch_col_eq(pattr2Col->getColumnNo(),
&comparisonValue2,
sizeof(Uint32),
false,
1) != 0)
APIERROR (pop->getNdbError());
// assert(false)
// Fail the operation with error 628 if we get here
if (pop->interpret_exit_nok(628) != 0)
APIERROR (pop->getNdbError());
// Label 1
if (pop->def_label(1) != 1)
APIERROR (pop->getNdbError());
// Optional infinite loop
//if (pop->branch_label(0) != 0)
// APIERROR (pop->getNdbError());
// R1 = 10
if (pop->load_const_u32(R1, 10) != 0)
APIERROR (pop->getNdbError());
// R3 = 2
if (pop->load_const_u32(R3, 2) != 0)
APIERROR (pop->getNdbError());
// Now call subroutine 0
if (pop->call_sub(0) != 0)
APIERROR (pop->getNdbError());
// *ATTR2= R2
if (pop->write_attr("ATTR2", R2) != 0)
APIERROR (pop->getNdbError());
// Return ok, we'll move onto an update.
if (pop->interpret_exit_ok() != 0)
APIERROR (pop->getNdbError());
/* Define a final read of the columns after the update */
recAttrAttr11= pop->getValue("ATTR1");
recAttrAttr12= pop->getValue("ATTR2");
recAttrAttr13= pop->getValue("ATTR3");
// Define any subroutines called by the 'main' program
// Subroutine 0
if (pop->def_subroutine(0) != 0)
APIERROR (pop->getNdbError());
// R4= 1
if (pop->load_const_u32(R4, 1) != 0)
APIERROR (pop->getNdbError());
// Label 2
if (pop->def_label(2) != 2)
APIERROR (pop->getNdbError());
// R3= R3-R4
if (pop->sub_reg(R3, R4, R3) != 0)
APIERROR (pop->getNdbError());
// R2= R2 + R1
if (pop->add_reg(R2, R1, R2) != 0)
APIERROR (pop->getNdbError());
// Optional infinite loop
// if (pop->branch_label(2) != 0)
// APIERROR (pop->getNdbError());
// Loop, subtracting 1 from R4 until R4 < 1
if (pop->branch_ge(R4, R3, 2) != 0)
APIERROR (pop->getNdbError());
// Jump to label 3
if (pop->branch_label(3) != 0)
APIERROR (pop->getNdbError());
// assert(false)
// Fail operation with error 629
if (pop->interpret_exit_nok(629) != 0)
APIERROR (pop->getNdbError());
// Label 3
if (pop->def_label(3) != 3)
APIERROR (pop->getNdbError());
// Nested subroutine call to sub 2
if (pop->call_sub(2) != 0)
APIERROR (pop->getNdbError());
// Return from subroutine 0
if (pop->ret_sub() !=0)
APIERROR (pop->getNdbError());
// Subroutine 1
if (pop->def_subroutine(1) != 1)
APIERROR (pop->getNdbError());
// R6= R1+R2
if (pop->add_reg(R1, R2, R6) != 0)
APIERROR (pop->getNdbError());
// Return from subrouine 1
if (pop->ret_sub() !=0)
APIERROR (pop->getNdbError());
// Subroutine 2
if (pop->def_subroutine(2) != 2)
APIERROR (pop->getNdbError());
// Call backwards to subroutine 1
if (pop->call_sub(1) != 0)
APIERROR (pop->getNdbError());
// Return from subroutine 2
if (pop->ret_sub() !=0)
APIERROR (pop->getNdbError());
break;
}
case api_record :
{
const NdbOperation *pop;
rowData.attr1= 4;
/* NdbRecord does not support an updateTuple pre-read or post-read, so
* we use separate operations for these.
* Note that this assumes that a operations are executed in
* the order they are defined by NDBAPI, which is not guaranteed. To ensure
* execution order, the application should perform a NoCommit execute between
* operations.
*/
const NdbOperation *op0= myTransaction->readTuple(pkeyColumnRecord,
(char*) &rowData,
pallColsRecord,
(char*) &rowData);
if (op0 == NULL)
APIERROR (myTransaction->getNdbError());
/* Allocate some space to define an Interpreted program */
const Uint32 numWords= 64;
Uint32 space[numWords];
NdbInterpretedCode stackCode(myTable,
&space[0],
numWords);
NdbInterpretedCode *code= &stackCode;
/* Similar program as above, with tortuous control flow and little
* purpose. Note that for NdbInterpretedCode, some instruction
* arguments are in different orders
*/
// R5= 3
if (code->load_const_u32(R5, 3) != 0)
APIERROR(code->getNdbError());
// R1= *ATTR1; R2= *ATTR2; R3= *ATTR3
if (code->read_attr(R1, pattr1Col) != 0)
APIERROR (code->getNdbError());
if (code->read_attr(R2, pattr2Col) != 0)
APIERROR (code->getNdbError());
if (code->read_attr(R3, pattr3Col) != 0)
APIERROR (code->getNdbError());
// R3= R3-R5
if (code->sub_reg(R3, R3, R5) != 0)
APIERROR (code->getNdbError());
// R2= R1+R2
if (code->add_reg(R2, R1, R2) != 0)
APIERROR (code->getNdbError());
// *ATTR2= R2
if (code->write_attr(pattr2Col, R2) != 0)
APIERROR (code->getNdbError());
// *ATTR3= R3
if (code->write_attr(pattr3Col, R3) != 0)
APIERROR (code->getNdbError());
// *ATTR3 = *ATTR3 - 30
if (code->sub_val(pattr3Col->getColumnNo(), (Uint32)30) != 0)
APIERROR (code->getNdbError());
Uint32 comparisonValue= 10;
// if comparisonValue < *ATTR3, goto Label 0
if (code->branch_col_lt(&comparisonValue,
sizeof(Uint32),
pattr3Col->getColumnNo(),
0) != 0)
APIERROR (code->getNdbError());
// assert(false)
// Fail operation with error 627
if (code->interpret_exit_nok(627) != 0)
APIERROR (code->getNdbError());
// Label 0
if (code->def_label(0) != 0)
APIERROR (code->getNdbError());
Uint32 comparisonValue2= 344;
// if *ATTR2 == comparisonValue, goto Label 1
if (code->branch_col_eq(&comparisonValue2,
sizeof(Uint32),
pattr2Col->getColumnNo(),
1) != 0)
APIERROR (code->getNdbError());
// assert(false)
// Fail operation with error 628
if (code->interpret_exit_nok(628) != 0)
APIERROR (code->getNdbError());
// Label 1
if (code->def_label(1) != 0)
APIERROR (code->getNdbError());
// R1= 10
if (code->load_const_u32(R1, 10) != 0)
APIERROR (code->getNdbError());
// R3= 2
if (code->load_const_u32(R3, 2) != 0)
APIERROR (code->getNdbError());
// Call subroutine 0 to effect
// R2 = R2 + (R1*R3)
if (code->call_sub(0) != 0)
APIERROR (code->getNdbError());
// *ATTR2= R2
if (code->write_attr(pattr2Col, R2) != 0)
APIERROR (code->getNdbError());
// Return ok
if (code->interpret_exit_ok() != 0)
APIERROR (code->getNdbError());
// Subroutine 0
if (code->def_sub(0) != 0)
APIERROR (code->getNdbError());
// R4= 1
if (code->load_const_u32(R4, 1) != 0)
APIERROR (code->getNdbError());
// Label 2
if (code->def_label(2) != 0)
APIERROR (code->getNdbError());
// R3= R3-R4
if (code->sub_reg(R3, R3, R4) != 0)
APIERROR (code->getNdbError());
// R2= R2+R1
if (code->add_reg(R2, R2, R1) != 0)
APIERROR (code->getNdbError());
// Loop, subtracting 1 from R4 until R4>1
if (code->branch_ge(R3, R4, 2) != 0)
APIERROR (code->getNdbError());
// Jump to label 3
if (code->branch_label(3) != 0)
APIERROR (code->getNdbError());
// Fail operation with error 629
if (code->interpret_exit_nok(629) != 0)
APIERROR (code->getNdbError());
// Label 3
if (code->def_label(3) != 0)
APIERROR (code->getNdbError());
// Call sub 2
if (code->call_sub(2) != 0)
APIERROR (code->getNdbError());
// Return from sub 0
if (code->ret_sub() != 0)
APIERROR (code->getNdbError());
// Subroutine 1
if (code->def_sub(1) != 0)
APIERROR (code->getNdbError());
// R6= R1+R2
if (code->add_reg(R6, R1, R2) != 0)
APIERROR (code->getNdbError());
// Return from subroutine 1
if (code->ret_sub() !=0)
APIERROR (code->getNdbError());
// Subroutine 2
if (code->def_sub(2) != 0)
APIERROR (code->getNdbError());
// Call backwards to subroutine 1
if (code->call_sub(1) != 0)
APIERROR (code->getNdbError());
// Return from subroutine 2
if (code->ret_sub() !=0)
APIERROR (code->getNdbError());
/* Finalise code object
* This step is essential for NdbInterpretedCode objects
* and must be done before they can be used.
*/
if (code->finalise() !=0)
APIERROR (code->getNdbError());
/* Time to define the update operation to use the
* InterpretedCode object. The same finalised object
* could be used with multiple operations or even
* multiple threads
*/
NdbOperation::OperationOptions oo;
oo.optionsPresent=
NdbOperation::OperationOptions::OO_INTERPRETED;
oo.interpretedCode= code;
unsigned char mask= 0;
pop= myTransaction->updateTuple(pkeyColumnRecord,
(char*) &rowData,
pallColsRecord,
(char*) &rowData,
(const unsigned char *) &mask, // mask - update nothing
&oo,
sizeof(NdbOperation::OperationOptions));
if (pop == NULL)
APIERROR (myTransaction->getNdbError());
// NoCommit execute so we can read the 'after' data.
if (myTransaction->execute( NdbTransaction::NoCommit ) != 0)
APIERROR(myTransaction->getNdbError());
/* Second read op as we can't currently do a 'read after
* 'interpreted code' read as part of NdbRecord.
* We are assuming that the order of op definition == order
* of execution on a single row, which is not guaranteed.
*/
const NdbOperation *pop2=
myTransaction->readTuple(pkeyColumnRecord,
(char*) &rowData,
pallColsRecord,
(char*) &rowData2);
if (pop2 == NULL)
APIERROR (myTransaction->getNdbError());
break;
}
default :
{
std::cout << "Bad branch : " << accessType << "\n";
exit(-1);
}
}
if(myTransaction->execute( NdbTransaction::NoCommit ) != 0)
APIERROR(myTransaction->getNdbError());
// Check return code
if (myTransaction->getNdbError().status != NdbError::Success)
APIERROR(myTransaction->getNdbError());
switch (accessType)
{
case api_attr :
{
printf(" %2d %2d %2d Before\n"
" %2d %2d %2d After\n",
recAttrAttr1->u_32_value(),
recAttrAttr2->u_32_value(),
recAttrAttr3->u_32_value(),
recAttrAttr11->u_32_value(),
recAttrAttr12->u_32_value(),
recAttrAttr13->u_32_value());
break;
}
case api_record :
{
printf(" %2d %2d %2d Before\n"
" %2d %2d %2d After\n",
rowData.attr1,
rowData.attr2,
rowData.attr3,
rowData2.attr1,
rowData2.attr2,
rowData2.attr3);
break;
}
default :
{
std::cout << "Bad branch : " << accessType << "\n";
exit(-1);
}
}
if(myTransaction->execute( NdbTransaction::Commit ) !=0)
APIERROR(myTransaction->getNdbError());
myNdb.closeTransaction(myTransaction);
std::cout << "-------\n";
}