1. Added envelopeType in Column and CommonColumnMetadata (required for JIT)

2. Minor MOT JIT fixes
This commit is contained in:
Vinoth Veeraraghavan 2021-03-11 19:10:52 +08:00
parent 9a762552be
commit 8bb58f27da
12 changed files with 177 additions and 106 deletions

View File

@ -251,6 +251,9 @@ static int errdetail_recovery_conflict(void);
static bool IsTransactionExitStmt(Node* parsetree);
static bool IsTransactionExitStmtList(List* parseTrees);
static bool IsTransactionStmtList(List* parseTrees);
#ifdef ENABLE_MOT
static bool IsTransactionPrepareStmt(const Node* parsetree);
#endif
static void drop_unnamed_stmt(void);
static void SigHupHandler(SIGNAL_ARGS);
static void ForceModifyInitialPwd(const char* query_string, List* parsetree_list);
@ -2420,6 +2423,12 @@ static void exec_simple_query(const char* query_string, MessageType messageType,
errmsg("SubTransaction is not supported for memory table")));
}
if (IsTransactionPrepareStmt(parsetree) && (IsMOTEngineUsed() || IsMixedEngineUsed())) {
/* Explicit prepare transaction is not supported for memory table */
ereport(ERROR, (errcode(ERRCODE_FDW_OPERATION_NOT_SUPPORTED), errmodule(MOD_MOT),
errmsg("Explicit prepare transaction is not supported for memory table")));
}
/* check for MOT update of indexed field. Can check only the querytree head, no need for drill down */
if (!IsTransactionExitStmt(parsetree) &&
(querytree_list != NULL && CheckMotIndexedColumnUpdate((Query*)linitial(querytree_list)))) {
@ -4100,14 +4109,22 @@ static void exec_bind_message(StringInfo input_message)
#ifdef ENABLE_MOT
/* set transaction storage engine and check for cross transaction violation */
SetCurrentTransactionStorageEngine(psrc->storageEngineType);
if (!IsTransactionExitStmt(psrc->raw_parse_tree) && IsMixedEngineUsed())
if (!IsTransactionExitStmt(psrc->raw_parse_tree) && IsMixedEngineUsed()) {
ereport(ERROR, (errcode(ERRCODE_FDW_CROSS_STORAGE_ENGINE_TRANSACTION_NOT_SUPPORTED), errmodule(MOD_MOT),
errmsg("Cross storage engine transaction is not supported")));
errmsg("Cross storage engine transaction is not supported")));
}
/* block MOT engine queries in sub-transactions */
if (!IsTransactionExitStmt(psrc->raw_parse_tree) && IsMOTEngineUsedInParentTransaction() && IsMOTEngineUsed())
if (!IsTransactionExitStmt(psrc->raw_parse_tree) && IsMOTEngineUsedInParentTransaction() && IsMOTEngineUsed()) {
ereport(ERROR, (errcode(ERRCODE_FDW_OPERATION_NOT_SUPPORTED), errmodule(MOD_MOT),
errmsg("SubTransaction is not supported for memory table")));
errmsg("SubTransaction is not supported for memory table")));
}
if (IsTransactionPrepareStmt(psrc->raw_parse_tree) && (IsMOTEngineUsed() || IsMixedEngineUsed())) {
/* Explicit prepare transaction is not supported for memory table */
ereport(ERROR, (errcode(ERRCODE_FDW_OPERATION_NOT_SUPPORTED), errmodule(MOD_MOT),
errmsg("Explicit prepare transaction is not supported for memory table")));
}
/*
* MOT JIT Execution:
@ -5360,6 +5377,19 @@ static bool IsTransactionStmtList(List* parseTrees)
return false;
}
#ifdef ENABLE_MOT
static bool IsTransactionPrepareStmt(const Node* parsetree)
{
if (parsetree && IsA(parsetree, TransactionStmt)) {
TransactionStmt* stmt = (TransactionStmt*)parsetree;
if (stmt->kind == TRANS_STMT_PREPARE) {
return true;
}
}
return false;
}
#endif
/* Release any existing unnamed prepared statement */
static void drop_unnamed_stmt(void)
{

View File

@ -7807,7 +7807,7 @@ bool IsPGEngineUsed()
}
/*
* Check if we are using PG storage engine in parent transaction.
* Check if we are using MOT storage engine in parent transaction.
*/
bool IsMOTEngineUsedInParentTransaction()
{

View File

@ -384,7 +384,7 @@ bool ConfigManager::ReloadConfig(bool ignoreErrors /* = true */)
// print loaded configuration
LogLevel logLevel = LogLevel::LL_TRACE;
GetLayeredConfigTree()->GetUserConfigValue("Log/cfg_startup_log_level", logLevel, false);
GetLayeredConfigTree()->GetUserConfigValue("Log.cfg_startup_log_level", logLevel, false);
if (MOT_CHECK_LOG_LEVEL(logLevel)) {
GetLayeredConfigTree()->Print(logLevel);
}

View File

@ -127,6 +127,7 @@ Column::Column()
securec_check(erc, "\0", "\0");
erc = memset_s(&(this->m_type), sizeof(this->m_type), 0, sizeof(this->m_type));
securec_check(erc, "\0", "\0");
this->m_envelopeType = 0;
}
Column::~Column()

View File

@ -162,6 +162,9 @@ public:
/** @var Column does not allow null values. */
bool m_isNotNull;
/** @var Envelope column type. */
unsigned int m_envelopeType;
};
// derived column classes

View File

@ -652,7 +652,8 @@ bool Table::CreateMultipleRows(size_t numRows, Row* rows[])
return res;
}
RC Table::AddColumn(const char* colName, uint64_t size, MOT_CATALOG_FIELD_TYPES type, bool isNotNull)
RC Table::AddColumn(
const char* colName, uint64_t size, MOT_CATALOG_FIELD_TYPES type, bool isNotNull, unsigned int envelopeType)
{
// validate input parameters
if (!colName || type >= MOT_CATALOG_FIELD_TYPES::MOT_TYPE_UNKNOWN)
@ -695,6 +696,7 @@ RC Table::AddColumn(const char* colName, uint64_t size, MOT_CATALOG_FIELD_TYPES
m_columns[m_fieldCnt]->m_id = m_fieldCnt;
m_columns[m_fieldCnt]->m_offset = m_tupleSize;
m_columns[m_fieldCnt]->m_isNotNull = isNotNull;
m_columns[m_fieldCnt]->m_envelopeType = envelopeType;
m_columns[m_fieldCnt]->SetKeySize();
m_tupleSize += size;
@ -817,7 +819,8 @@ size_t Table::SerializeItemSize(Column* column)
size_t ret = SerializableARR<char, Column::MAX_COLUMN_NAME_LEN>::SerializeSize(column->m_name) +
SerializablePOD<uint64_t>::SerializeSize(column->m_size) +
SerializablePOD<MOT_CATALOG_FIELD_TYPES>::SerializeSize(column->m_type) +
SerializablePOD<bool>::SerializeSize(column->m_isNotNull);
SerializablePOD<bool>::SerializeSize(column->m_isNotNull) +
SerializablePOD<unsigned int>::SerializeSize(column->m_envelopeType); // required for MOT JIT
return ret;
}
@ -830,6 +833,7 @@ char* Table::SerializeItem(char* dataOut, Column* column)
dataOut = SerializablePOD<uint64_t>::Serialize(dataOut, column->m_size);
dataOut = SerializablePOD<MOT_CATALOG_FIELD_TYPES>::Serialize(dataOut, column->m_type);
dataOut = SerializablePOD<bool>::Serialize(dataOut, column->m_isNotNull);
dataOut = SerializablePOD<unsigned int>::Serialize(dataOut, column->m_envelopeType); // required for MOT JIT
return dataOut;
}
@ -839,6 +843,7 @@ char* Table::DeserializeMeta(char* dataIn, CommonColumnMeta& meta)
dataIn = SerializablePOD<uint64_t>::Deserialize(dataIn, meta.m_size);
dataIn = SerializablePOD<MOT_CATALOG_FIELD_TYPES>::Deserialize(dataIn, meta.m_type);
dataIn = SerializablePOD<bool>::Deserialize(dataIn, meta.m_isNotNull);
dataIn = SerializablePOD<unsigned int>::Deserialize(dataIn, meta.m_envelopeType); // required for MOT JIT
return dataIn;
}
@ -1110,7 +1115,7 @@ void Table::Deserialize(const char* in)
CommonColumnMeta col;
for (uint32_t i = 0; i < saveFieldCount; i++) {
dataIn = DeserializeMeta(dataIn, col);
if (AddColumn(col.m_name, col.m_size, col.m_type, col.m_isNotNull) != RC_OK) {
if (AddColumn(col.m_name, col.m_size, col.m_type, col.m_isNotNull, col.m_envelopeType) != RC_OK) {
MOT_LOG_ERROR("Table::deserialize - failed to add column %u", i);
return;
}

View File

@ -634,7 +634,8 @@ public:
* @param type The type name of the column.
* @return RC error code.
*/
RC AddColumn(const char* col_name, uint64_t size, MOT_CATALOG_FIELD_TYPES type, bool isNotNull = false);
RC AddColumn(const char* col_name, uint64_t size, MOT_CATALOG_FIELD_TYPES type, bool isNotNull = false,
unsigned int envelopeType = 0);
/**
* @brief Modifies the size of a column. This may be required for supporting ALTER TABLE.
@ -952,6 +953,8 @@ public:
MOT_CATALOG_FIELD_TYPES m_type;
bool m_isNotNull;
unsigned int m_envelopeType; // required for MOT JIT
};
/**

View File

@ -935,10 +935,10 @@ static void VarLenFieldType(
}
}
static MOT::RC TableFieldType(const ColumnDef* colDef, MOT::MOT_CATALOG_FIELD_TYPES& type, int16* typeLen, bool& isBlob)
static MOT::RC TableFieldType(
const ColumnDef* colDef, MOT::MOT_CATALOG_FIELD_TYPES& type, int16* typeLen, Oid& typoid, bool& isBlob)
{
MOT::RC res = MOT::RC_OK;
Oid typoid;
Type tup;
Form_pg_type typeDesc;
int32_t colLen;
@ -1210,7 +1210,8 @@ void MOTAdaptor::AddTableColumns(MOT::Table* table, List *tableElts, bool& hasBl
break;
}
MOT::RC res = TableFieldType(colDef, colType, &typeLen, isBlob);
Oid typoid = InvalidOid;
MOT::RC res = TableFieldType(colDef, colType, &typeLen, typoid, isBlob);
if (res != MOT::RC_OK) {
delete table;
table = nullptr;
@ -1264,7 +1265,8 @@ void MOTAdaptor::AddTableColumns(MOT::Table* table, List *tableElts, bool& hasBl
}
}
}
res = table->AddColumn(colDef->colname, typeLen, colType, colDef->is_not_null);
res = table->AddColumn(colDef->colname, typeLen, colType, colDef->is_not_null, typoid);
if (res != MOT::RC_OK) {
delete table;
table = nullptr;
@ -1724,7 +1726,7 @@ void MOTAdaptor::CreateKeyBuffer(Relation rel, MOTFdwStateSt* festate, int start
}
DatumToMOTKey(col,
expr,
expr->resultType,
val,
desc->attrs[orgCols[i] - 1]->atttypid,
buf + offset,
@ -1948,26 +1950,25 @@ void MOTAdaptor::DatumToMOT(MOT::Column* col, Datum datum, Oid type, uint8_t* da
}
inline void MOTAdaptor::VarcharToMOTKey(
MOT::Column* col, ExprState* expr, Datum datum, Oid type, uint8_t* data, size_t len, KEY_OPER oper, uint8_t fill)
MOT::Column* col, Oid datumType, Datum datum, Oid colType, uint8_t* data, size_t len, KEY_OPER oper, uint8_t fill)
{
if (expr != nullptr) { // LLVM passes nullptr for expr parameter
bool noValue = false;
switch (expr->resultType) {
case BYTEAOID:
case TEXTOID:
case VARCHAROID:
case CLOBOID:
case BPCHAROID:
break;
default:
noValue = true;
errno_t erc = memset_s(data, len, 0x00, len);
securec_check(erc, "\0", "\0");
break;
}
if (noValue) {
return;
}
bool noValue = false;
switch (datumType) {
case BYTEAOID:
case TEXTOID:
case VARCHAROID:
case CLOBOID:
case BPCHAROID:
break;
default:
noValue = true;
errno_t erc = memset_s(data, len, 0x00, len);
securec_check(erc, "\0", "\0");
break;
}
if (noValue) {
return;
}
bytea* txt = DatumGetByteaP(datum);
@ -1984,13 +1985,13 @@ inline void MOTAdaptor::VarcharToMOTKey(
size -= 1;
} else {
// switch to equal
if (type == BPCHAROID) {
if (colType == BPCHAROID) {
fill = 0x20; // space ' ' == 0x20
} else {
fill = 0x00;
}
}
} else if (type == BPCHAROID) { // handle padding for blank-padded type
} else if (colType == BPCHAROID) { // handle padding for blank-padded type
fill = 0x20;
}
col->PackKey(data, (uintptr_t)src, size, fill);
@ -2000,25 +2001,21 @@ inline void MOTAdaptor::VarcharToMOTKey(
}
}
inline void MOTAdaptor::FloatToMOTKey(MOT::Column* col, ExprState* expr, Datum datum, uint8_t* data)
inline void MOTAdaptor::FloatToMOTKey(MOT::Column* col, Oid datumType, Datum datum, uint8_t* data)
{
if (expr != nullptr) { // LLVM passes nullptr for expr parameter
if (expr->resultType == FLOAT8OID) {
MOT::DoubleConvT dc;
MOT::FloatConvT fc;
dc.m_r = (uint64_t)datum;
fc.m_v = (float)dc.m_v;
uint64_t u = (uint64_t)fc.m_r;
col->PackKey(data, u, col->m_size);
} else {
col->PackKey(data, datum, col->m_size);
}
if (datumType == FLOAT8OID) {
MOT::DoubleConvT dc;
MOT::FloatConvT fc;
dc.m_r = (uint64_t)datum;
fc.m_v = (float)dc.m_v;
uint64_t u = (uint64_t)fc.m_r;
col->PackKey(data, u, col->m_size);
} else {
col->PackKey(data, datum, col->m_size);
}
}
inline void MOTAdaptor::NumericToMOTKey(MOT::Column* col, ExprState* expr, Datum datum, uint8_t* data)
inline void MOTAdaptor::NumericToMOTKey(MOT::Column* col, Oid datumType, Datum datum, uint8_t* data)
{
Numeric n = DatumGetNumeric(datum);
char buf[DECIMAL_MAX_SIZE];
@ -2027,83 +2024,71 @@ inline void MOTAdaptor::NumericToMOTKey(MOT::Column* col, ExprState* expr, Datum
col->PackKey(data, (uintptr_t)d, DECIMAL_SIZE(d));
}
inline void MOTAdaptor::TimestampToMOTKey(MOT::Column* col, ExprState* expr, Datum datum, uint8_t* data)
inline void MOTAdaptor::TimestampToMOTKey(MOT::Column* col, Oid datumType, Datum datum, uint8_t* data)
{
if (expr != nullptr) {
if (expr->resultType == TIMESTAMPTZOID) {
Timestamp result = DatumGetTimestamp(DirectFunctionCall1(timestamptz_timestamp, datum));
col->PackKey(data, result, col->m_size);
} else if (expr->resultType == DATEOID) {
Timestamp result = DatumGetTimestamp(DirectFunctionCall1(date_timestamp, datum));
col->PackKey(data, result, col->m_size);
} else {
col->PackKey(data, datum, col->m_size);
}
if (datumType == TIMESTAMPTZOID) {
Timestamp result = DatumGetTimestamp(DirectFunctionCall1(timestamptz_timestamp, datum));
col->PackKey(data, result, col->m_size);
} else if (datumType == DATEOID) {
Timestamp result = DatumGetTimestamp(DirectFunctionCall1(date_timestamp, datum));
col->PackKey(data, result, col->m_size);
} else {
col->PackKey(data, datum, col->m_size);
}
}
inline void MOTAdaptor::TimestampTzToMOTKey(MOT::Column* col, ExprState* expr, Datum datum, uint8_t* data)
inline void MOTAdaptor::TimestampTzToMOTKey(MOT::Column* col, Oid datumType, Datum datum, uint8_t* data)
{
if (expr != nullptr) {
if (expr->resultType == TIMESTAMPOID) {
TimestampTz result = DatumGetTimestampTz(DirectFunctionCall1(timestamp_timestamptz, datum));
col->PackKey(data, result, col->m_size);
} else if (expr->resultType == DATEOID) {
TimestampTz result = DatumGetTimestampTz(DirectFunctionCall1(date_timestamptz, datum));
col->PackKey(data, result, col->m_size);
} else {
col->PackKey(data, datum, col->m_size);
}
if (datumType == TIMESTAMPOID) {
TimestampTz result = DatumGetTimestampTz(DirectFunctionCall1(timestamp_timestamptz, datum));
col->PackKey(data, result, col->m_size);
} else if (datumType == DATEOID) {
TimestampTz result = DatumGetTimestampTz(DirectFunctionCall1(date_timestamptz, datum));
col->PackKey(data, result, col->m_size);
} else {
col->PackKey(data, datum, col->m_size);
}
}
inline void MOTAdaptor::DateToMOTKey(MOT::Column* col, ExprState* expr, Datum datum, uint8_t* data)
inline void MOTAdaptor::DateToMOTKey(MOT::Column* col, Oid datumType, Datum datum, uint8_t* data)
{
if (expr != nullptr) {
if (expr->resultType == TIMESTAMPOID) {
DateADT result = DatumGetDateADT(DirectFunctionCall1(timestamp_date, datum));
col->PackKey(data, result, col->m_size);
} else if (expr->resultType == TIMESTAMPTZOID) {
DateADT result = DatumGetDateADT(DirectFunctionCall1(timestamptz_date, datum));
col->PackKey(data, result, col->m_size);
} else {
col->PackKey(data, datum, col->m_size);
}
if (datumType == TIMESTAMPOID) {
DateADT result = DatumGetDateADT(DirectFunctionCall1(timestamp_date, datum));
col->PackKey(data, result, col->m_size);
} else if (datumType == TIMESTAMPTZOID) {
DateADT result = DatumGetDateADT(DirectFunctionCall1(timestamptz_date, datum));
col->PackKey(data, result, col->m_size);
} else {
col->PackKey(data, datum, col->m_size);
}
}
void MOTAdaptor::DatumToMOTKey(
MOT::Column* col, ExprState* expr, Datum datum, Oid type, uint8_t* data, size_t len, KEY_OPER oper, uint8_t fill)
MOT::Column* col, Oid datumType, Datum datum, Oid colType, uint8_t* data, size_t len, KEY_OPER oper, uint8_t fill)
{
EnsureSafeThreadAccessInline();
switch (type) {
switch (colType) {
case BYTEAOID:
case TEXTOID:
case VARCHAROID:
case CLOBOID:
case BPCHAROID:
VarcharToMOTKey(col, expr, datum, type, data, len, oper, fill);
VarcharToMOTKey(col, datumType, datum, colType, data, len, oper, fill);
break;
case FLOAT4OID:
FloatToMOTKey(col, expr, datum, data);
FloatToMOTKey(col, datumType, datum, data);
break;
case NUMERICOID:
NumericToMOTKey(col, expr, datum, data);
NumericToMOTKey(col, datumType, datum, data);
break;
case TIMESTAMPOID:
TimestampToMOTKey(col, expr, datum, data);
TimestampToMOTKey(col, datumType, datum, data);
break;
case TIMESTAMPTZOID:
TimestampTzToMOTKey(col, expr, datum, data);
TimestampTzToMOTKey(col, datumType, datum, data);
break;
case DATEOID:
DateToMOTKey(col, expr, datum, data);
DateToMOTKey(col, datumType, datum, data);
break;
default:
col->PackKey(data, datum, col->m_size);

View File

@ -261,7 +261,7 @@ public:
// data conversion
static void DatumToMOT(MOT::Column* col, Datum datum, Oid type, uint8_t* data);
static void DatumToMOTKey(MOT::Column* col, ExprState* expr, Datum datum, Oid type, uint8_t* data, size_t len,
static void DatumToMOTKey(MOT::Column* col, Oid datumType, Datum datum, Oid colType, uint8_t* data, size_t len,
KEY_OPER oper, uint8_t fill = 0x00);
static void MOTToDatum(MOT::Table* table, const Form_pg_attribute attr, uint8_t* data, Datum* value, bool* is_null);
@ -315,13 +315,13 @@ private:
static void ValidateCreateIndex(IndexStmt* index, MOT::Table* table, MOT::TxnManager* txn);
static void VarcharToMOTKey(MOT::Column* col, ExprState* expr, Datum datum, Oid type, uint8_t* data, size_t len,
static void VarcharToMOTKey(MOT::Column* col, Oid datumType, Datum datum, Oid colType, uint8_t* data, size_t len,
KEY_OPER oper, uint8_t fill);
static void FloatToMOTKey(MOT::Column* col, ExprState* expr, Datum datum, uint8_t* data);
static void NumericToMOTKey(MOT::Column* col, ExprState* expr, Datum datum, uint8_t* data);
static void TimestampToMOTKey(MOT::Column* col, ExprState* expr, Datum datum, uint8_t* data);
static void TimestampTzToMOTKey(MOT::Column* col, ExprState* expr, Datum datum, uint8_t* data);
static void DateToMOTKey(MOT::Column* col, ExprState* expr, Datum datum, uint8_t* data);
static void FloatToMOTKey(MOT::Column* col, Oid datumType, Datum datum, uint8_t* data);
static void NumericToMOTKey(MOT::Column* col, Oid datumType, Datum datum, uint8_t* data);
static void TimestampToMOTKey(MOT::Column* col, Oid datumType, Datum datum, uint8_t* data);
static void TimestampTzToMOTKey(MOT::Column* col, Oid datumType, Datum datum, uint8_t* data);
static void DateToMOTKey(MOT::Column* col, Oid datumType, Datum datum, uint8_t* data);
};
inline MOT::TxnManager* GetSafeTxn(const char* callerSrc, ::TransactionId txn_id = 0)

View File

@ -612,6 +612,17 @@ static void CleanupJitContextPrimary(JitContext* jitContext)
jitContext->m_index->DestroyKey(jitContext->m_endIteratorKey);
jitContext->m_endIteratorKey = nullptr;
}
if (jitContext->m_beginIterator != nullptr) {
destroyIterator(jitContext->m_beginIterator);
jitContext->m_beginIterator = nullptr;
}
if (jitContext->m_endIterator != nullptr) {
destroyIterator(jitContext->m_endIterator);
jitContext->m_endIterator = nullptr;
}
jitContext->m_index = nullptr;
}
@ -636,6 +647,17 @@ static void CleanupJitContextInner(JitContext* jitContext)
jitContext->m_innerIndex->DestroyKey(jitContext->m_innerEndIteratorKey);
jitContext->m_innerEndIteratorKey = nullptr;
}
if (jitContext->m_innerBeginIterator != nullptr) {
destroyIterator(jitContext->m_innerBeginIterator);
jitContext->m_innerBeginIterator = nullptr;
}
if (jitContext->m_innerEndIterator != nullptr) {
destroyIterator(jitContext->m_innerEndIterator);
jitContext->m_innerEndIterator = nullptr;
}
jitContext->m_innerIndex = nullptr;
}
}

View File

@ -449,9 +449,9 @@ void buildDatumKey(
securec_check(erc, "\0", "\0");
} else {
MOTAdaptor::DatumToMOTKey(column,
NULL,
value,
(Oid)value_type,
value,
column->m_envelopeType,
key->GetKeyBuf() + offset,
column->m_size,
KEY_OPER::READ_KEY_EXACT,

View File

@ -156,7 +156,8 @@ void RangeScanExpressionCollector::EvaluateScanType()
// first step: sort in-place all collected operators
if (_index_op_count > 1) {
std::sort(&_index_ops[0], &_index_ops[_index_op_count - 1], IndexOpCmp);
MOT_LOG_TRACE("Sorting index ops")
std::stable_sort(&_index_ops[0], &_index_ops[_index_op_count], IndexOpCmp);
}
// now verify all but last two are equals operator
@ -227,7 +228,9 @@ bool RangeScanExpressionCollector::DetermineScanType(JitIndexScanType& scanType,
void RangeScanExpressionCollector::Cleanup()
{
for (int i = 0; i < _index_op_count; ++i) {
freeExpr(_index_scan->_search_exprs._exprs[i]._expr);
if (_index_scan->_search_exprs._exprs[i]._expr != nullptr) {
freeExpr(_index_scan->_search_exprs._exprs[i]._expr);
}
}
_index_scan->_search_exprs._count = 0;
_index_op_count = 0;
@ -255,23 +258,26 @@ int RangeScanExpressionCollector::RemoveSingleDuplicate()
continue;
}
// now we need to decide which one to remove,
// our consideration is to keep equals operators and then join expressions
// our consideration is to keep first JOIN expressions and then EQUALS expressions
int victim = -1;
if ((_index_ops[i]._op_class == JIT_WOC_EQUALS) || (_index_ops[j]._op_class == JIT_WOC_EQUALS)) {
if ((_index_ops[i]._op_class != JIT_WOC_EQUALS) || (_index_ops[j]._op_class != JIT_WOC_EQUALS)) {
// we keep the equals operator for index scan, and leave the other as a filter
MOT_LOG_TRACE("RangeScanExpressionCollector(): Rejecting query due to duplicate index column "
"reference, one with EQUALS, one without");
MOT_LOG_TRACE("RangeScanExpressionCollector(): Found duplicate index column reference, one with "
"EQUALS, one without - non-equals column will be considered as a filter");
if (_index_ops[i]._op_class != JIT_WOC_EQUALS) {
victim = i;
} else {
victim = j;
}
MOT_LOG_TRACE("Selected non-EQUALS victim at index %d", victim);
} else if (_index_scan->_search_exprs._exprs[i]._join_expr &&
!_index_scan->_search_exprs._exprs[j]._join_expr) {
victim = j;
MOT_LOG_TRACE("Selected non-JOIN victim at index %d", victim);
} else if (!_index_scan->_search_exprs._exprs[i]._join_expr &&
_index_scan->_search_exprs._exprs[j]._join_expr) {
victim = i;
MOT_LOG_TRACE("Selected non-JOIN victim at index %d", victim);
} else if (_index_scan->_search_exprs._exprs[i]._join_expr &&
_index_scan->_search_exprs._exprs[j]._join_expr) {
// both are join expressions, this is unacceptable, so we abort
@ -284,12 +290,18 @@ int RangeScanExpressionCollector::RemoveSingleDuplicate()
// both items are not join expressions, both refer to index columns, so we arbitrarily drop one
// of them
victim = j;
MOT_LOG_TRACE("Selected arbitrary duplicate EQUALS victim at index %d", victim);
}
// switch victim with last item
MOT_LOG_TRACE(
"Removing victim index op at index %d and putting there index %d", victim, _index_op_count - 1);
if (_index_scan->_search_exprs._exprs[victim]._expr != nullptr) {
freeExpr(_index_scan->_search_exprs._exprs[victim]._expr);
}
MOT_LOG_TRACE("Removing victim index op at index %d", victim);
_index_scan->_search_exprs._exprs[victim] = _index_scan->_search_exprs._exprs[_index_op_count - 1];
_index_scan->_search_exprs._exprs[_index_op_count - 1]._expr = nullptr;
_index_ops[victim] = _index_ops[_index_op_count - 1];
--_index_op_count;
--_index_scan->_search_exprs._count;
return 1;
@ -317,8 +329,15 @@ bool RangeScanExpressionCollector::IndexOpCmp(const IndexOpClass& lhs, const Ind
int result = IntCmp(lhs._index_column_id, rhs._index_column_id);
if (result == 0) {
// make sure equals appears before other operators in case column id is equal
result = IntCmp(lhs._op_class, rhs._op_class);
if ((lhs._op_class == JIT_WOC_EQUALS) && (rhs._op_class != JIT_WOC_EQUALS)) {
result = -1;
} else if ((lhs._op_class != JIT_WOC_EQUALS) && (rhs._op_class == JIT_WOC_EQUALS)) {
result = 1;
}
// otherwise we keep order intact to avoid misinterpreting open range scan as inverted
}
// we return true when strict ascending order is preserved
return result < 0;
}
@ -336,6 +355,9 @@ bool RangeScanExpressionCollector::ScanHasHoles(JitIndexScanType scan_type) cons
if (_index_ops[0]._index_column_id != 0) {
MOT_LOG_TRACE(
"RangeScanExpressionCollector(): Disqualifying query - Index scan does not begin with index column 0");
for (int i = 0; i < _index_op_count; ++i) {
MOT_LOG_TRACE("Index column id %d: %d", i, _index_ops[i]._index_column_id);
}
return true;
}