|
@@ -93,6 +93,41 @@ static node_operator getModifiedOp(node_operator op, bool duplicate)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool isSubString(IHqlExpression * expr)
|
|
|
|
+{
|
|
|
|
+ for(;;)
|
|
|
|
+ {
|
|
|
|
+ switch (expr->getOperator())
|
|
|
|
+ {
|
|
|
|
+ case no_substring:
|
|
|
|
+ return true;
|
|
|
|
+ case no_cast:
|
|
|
|
+ case no_implicitcast:
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ expr = expr->queryChild(0);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static IHqlExpression * querySubStringRange(IHqlExpression * expr)
|
|
|
|
+{
|
|
|
|
+ for(;;)
|
|
|
|
+ {
|
|
|
|
+ switch (expr->getOperator())
|
|
|
|
+ {
|
|
|
|
+ case no_substring:
|
|
|
|
+ return expr->queryChild(1);
|
|
|
|
+ case no_cast:
|
|
|
|
+ case no_implicitcast:
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ return nullptr;
|
|
|
|
+ }
|
|
|
|
+ expr = expr->queryChild(0);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
void KeyFailureInfo::merge(const KeyFailureInfo & other)
|
|
void KeyFailureInfo::merge(const KeyFailureInfo & other)
|
|
{
|
|
{
|
|
@@ -497,7 +532,7 @@ void FilterExtractor::expandSelects(IHqlExpression * expr, IHqlSimpleScope * exp
|
|
OwnedHqlExpr keySelected = createSelectExpr(LINK(keySelector), LINK(expr));
|
|
OwnedHqlExpr keySelected = createSelectExpr(LINK(keySelector), LINK(expr));
|
|
OwnedHqlExpr expandedSelected = createSelectExpr(LINK(expandedSelector), LINK(match));
|
|
OwnedHqlExpr expandedSelected = createSelectExpr(LINK(expandedSelector), LINK(match));
|
|
IHqlExpression * record = expr->queryRecord();
|
|
IHqlExpression * record = expr->queryRecord();
|
|
- if (record)
|
|
|
|
|
|
+ if (expr->isDatarow())
|
|
expandSelects(record, match->queryRecord()->querySimpleScope(), keySelected, expandedSelected);
|
|
expandSelects(record, match->queryRecord()->querySimpleScope(), keySelected, expandedSelected);
|
|
else
|
|
else
|
|
{
|
|
{
|
|
@@ -674,8 +709,11 @@ IHqlExpression * FilterExtractor::invertTransforms(IHqlExpression * left, IHqlEx
|
|
assertex(isKeySelect(left));
|
|
assertex(isKeySelect(left));
|
|
ITypeInfo * leftType = left->queryType();
|
|
ITypeInfo * leftType = left->queryType();
|
|
ITypeInfo * rightType = right->queryType();
|
|
ITypeInfo * rightType = right->queryType();
|
|
- if (leftType == rightType || !castLosesInformation(leftType, rightType))
|
|
|
|
- return LINK(right);
|
|
|
|
|
|
+ if (!createValueSets)
|
|
|
|
+ {
|
|
|
|
+ if (leftType == rightType || !castLosesInformation(leftType, rightType))
|
|
|
|
+ return LINK(right);
|
|
|
|
+ }
|
|
return ensureExprType(right, leftType);
|
|
return ensureExprType(right, leftType);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -728,6 +766,14 @@ IHqlExpression * FilterExtractor::isKeyableFilter(IHqlExpression * left, IHqlExp
|
|
IHqlExpression * uncast = left->queryChild(0);
|
|
IHqlExpression * uncast = left->queryChild(0);
|
|
ITypeInfo * castType = left->queryType();
|
|
ITypeInfo * castType = left->queryType();
|
|
ITypeInfo * uncastType = uncast->queryType();
|
|
ITypeInfo * uncastType = uncast->queryType();
|
|
|
|
+
|
|
|
|
+ //Keyed filters on alien datatypes do not work, and can trigger an internal error in ensureExprType()
|
|
|
|
+ if (uncastType->getTypeCode() == type_alien)
|
|
|
|
+ {
|
|
|
|
+ reason.set(KFRtoocomplex, left);
|
|
|
|
+ return nullptr;
|
|
|
|
+ }
|
|
|
|
+
|
|
//(ty)x = y. E.g., (int1)string2field = int1value
|
|
//(ty)x = y. E.g., (int1)string2field = int1value
|
|
//if more than one value of x[uncastType] corresponds to a single value in y[castType] then we can't sensibly create
|
|
//if more than one value of x[uncastType] corresponds to a single value in y[castType] then we can't sensibly create
|
|
//the key segment monitor. Because we will get false negatives. If it is an inverse then duplicate (see below)
|
|
//the key segment monitor. Because we will get false negatives. If it is an inverse then duplicate (see below)
|
|
@@ -786,15 +832,15 @@ IHqlExpression * FilterExtractor::isKeyableFilter(IHqlExpression * left, IHqlExp
|
|
if (range->getOperator() == no_rangeto)
|
|
if (range->getOperator() == no_rangeto)
|
|
{
|
|
{
|
|
IValue *end = range->queryChild(0)->queryValue();
|
|
IValue *end = range->queryChild(0)->queryValue();
|
|
- if (!end)
|
|
|
|
|
|
+ if (!createValueSets && !end)
|
|
break;
|
|
break;
|
|
return isKeyableFilter(left->queryChild(0), right, duplicate, compareOp, reason, keyedKind);
|
|
return isKeyableFilter(left->queryChild(0), right, duplicate, compareOp, reason, keyedKind);
|
|
}
|
|
}
|
|
else if (range->getOperator() == no_range)
|
|
else if (range->getOperator() == no_range)
|
|
{
|
|
{
|
|
- IValue *start = range->queryChild(0)->queryValue();
|
|
|
|
- IValue *end = range->queryChild(1)->queryValue();
|
|
|
|
- if (!start || !end || start->getIntValue() != 1)
|
|
|
|
|
|
+ if (!matchesConstantValue(range->queryChild(0), 1))
|
|
|
|
+ break;
|
|
|
|
+ if (!createValueSets && !range->queryChild(1)->queryValue())
|
|
break;
|
|
break;
|
|
return isKeyableFilter(left->queryChild(0), right, duplicate, compareOp, reason, keyedKind);
|
|
return isKeyableFilter(left->queryChild(0), right, duplicate, compareOp, reason, keyedKind);
|
|
}
|
|
}
|
|
@@ -1006,6 +1052,13 @@ IHqlExpression * FilterExtractor::getRangeLimit(ITypeInfo * fieldType, IHqlExpre
|
|
IHqlExpression * FilterExtractor::createRangeCompare(IHqlExpression * selector, IHqlExpression * value, IHqlExpression * lengthExpr, bool compareEqual)
|
|
IHqlExpression * FilterExtractor::createRangeCompare(IHqlExpression * selector, IHqlExpression * value, IHqlExpression * lengthExpr, bool compareEqual)
|
|
{
|
|
{
|
|
OwnedHqlExpr foldedValue = foldHqlExpression(value);
|
|
OwnedHqlExpr foldedValue = foldHqlExpression(value);
|
|
|
|
+ if (createValueSets)
|
|
|
|
+ {
|
|
|
|
+ OwnedHqlExpr rangeExpr = createValue(no_rangeto, makeNullType(), LINK(lengthExpr));
|
|
|
|
+ OwnedHqlExpr substr = createValue(no_substring, getStretchedType(UNKNOWN_LENGTH, selector->queryType()), LINK(selector), rangeExpr.getClear());
|
|
|
|
+ return createValue(compareEqual ? no_eq : no_ne, makeBoolType(), LINK(selector), foldedValue.getClear());
|
|
|
|
+ }
|
|
|
|
+
|
|
ITypeInfo * fieldType = selector->queryType();
|
|
ITypeInfo * fieldType = selector->queryType();
|
|
OwnedHqlExpr lowExpr = getRangeLimit(fieldType, lengthExpr, foldedValue, -1);
|
|
OwnedHqlExpr lowExpr = getRangeLimit(fieldType, lengthExpr, foldedValue, -1);
|
|
OwnedHqlExpr highExpr = getRangeLimit(fieldType, lengthExpr, foldedValue, +1);
|
|
OwnedHqlExpr highExpr = getRangeLimit(fieldType, lengthExpr, foldedValue, +1);
|
|
@@ -1025,6 +1078,10 @@ bool FilterExtractor::matchSubstringFilter(KeyConditionInfo & matches, node_oper
|
|
OwnedHqlExpr guard;
|
|
OwnedHqlExpr guard;
|
|
ITypeInfo * guardCastType = NULL;
|
|
ITypeInfo * guardCastType = NULL;
|
|
|
|
|
|
|
|
+ //Do not match implicit substring filters by default - because only a single substring range is supported
|
|
|
|
+ if (createValueSets && (keyedKind == KeyedNo))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
if ((left->getOperator() == no_cast) || (left->getOperator() == no_implicitcast))
|
|
if ((left->getOperator() == no_cast) || (left->getOperator() == no_implicitcast))
|
|
{
|
|
{
|
|
//code is extracted and simplified from isKeyableFilter() above - should be commoned up.
|
|
//code is extracted and simplified from isKeyableFilter() above - should be commoned up.
|
|
@@ -1089,7 +1146,7 @@ bool FilterExtractor::matchSubstringFilter(KeyConditionInfo & matches, node_oper
|
|
return false;
|
|
return false;
|
|
ITypeInfo * fieldType = selector->queryType();
|
|
ITypeInfo * fieldType = selector->queryType();
|
|
unsigned fieldLength = fieldType->getStringLen();
|
|
unsigned fieldLength = fieldType->getStringLen();
|
|
- if (fieldLength == UNKNOWN_LENGTH)
|
|
|
|
|
|
+ if (!createValueSets && (fieldLength == UNKNOWN_LENGTH))
|
|
return false;
|
|
return false;
|
|
|
|
|
|
OwnedHqlExpr range = foldHqlExpression(left->queryChild(1));
|
|
OwnedHqlExpr range = foldHqlExpression(left->queryChild(1));
|
|
@@ -1129,7 +1186,9 @@ bool FilterExtractor::matchSubstringFilter(KeyConditionInfo & matches, node_oper
|
|
newTest.setown(createBalanced(combineOp, boolType, compares));
|
|
newTest.setown(createBalanced(combineOp, boolType, compares));
|
|
}
|
|
}
|
|
|
|
|
|
- matches.appendCondition(*new KeyCondition(selector, newTest, keyedKind));
|
|
|
|
|
|
+ KeyCondition * entry = new KeyCondition(selector, newTest, keyedKind);
|
|
|
|
+ entry->subrange.set(left->queryChild(1));
|
|
|
|
+ matches.appendCondition(*entry);
|
|
if (guard)
|
|
if (guard)
|
|
matches.appendPreFilter(guard);
|
|
matches.appendPreFilter(guard);
|
|
return true;
|
|
return true;
|
|
@@ -1142,18 +1201,27 @@ bool FilterExtractor::extractSimpleCompareFilter(KeyConditionInfo & matches, IHq
|
|
IHqlExpression * l = promoted->queryChild(0);
|
|
IHqlExpression * l = promoted->queryChild(0);
|
|
IHqlExpression * r = promoted->queryChild(1);
|
|
IHqlExpression * r = promoted->queryChild(1);
|
|
bool duplicate = false;
|
|
bool duplicate = false;
|
|
|
|
+
|
|
KeyFailureInfo reasonl, reasonr;
|
|
KeyFailureInfo reasonl, reasonr;
|
|
node_operator op = expr->getOperator();
|
|
node_operator op = expr->getOperator();
|
|
IHqlExpression * matchedSelector = isKeyableFilter(l, r, duplicate, op, reasonl, keyedKind);
|
|
IHqlExpression * matchedSelector = isKeyableFilter(l, r, duplicate, op, reasonl, keyedKind);
|
|
Owned<KeyCondition> result;
|
|
Owned<KeyCondition> result;
|
|
if (matchedSelector)
|
|
if (matchedSelector)
|
|
{
|
|
{
|
|
|
|
+ //Do not match implicit substring filters by default - because only a single substring range is supported
|
|
|
|
+ if (createValueSets && isSubString(l) && (keyedKind == KeyedNo))
|
|
|
|
+ {
|
|
|
|
+ matches.appendPostFilter(expr);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
node_operator newOp = getModifiedOp(op, duplicate);
|
|
node_operator newOp = getModifiedOp(op, duplicate);
|
|
|
|
|
|
if (newOp != no_none)
|
|
if (newOp != no_none)
|
|
{
|
|
{
|
|
OwnedHqlExpr newFilter = createValue(newOp, expr->getType(), LINK(l), LINK(r));
|
|
OwnedHqlExpr newFilter = createValue(newOp, expr->getType(), LINK(l), LINK(r));
|
|
result.setown(new KeyCondition(matchedSelector, newFilter, keyedKind));
|
|
result.setown(new KeyCondition(matchedSelector, newFilter, keyedKind));
|
|
|
|
+ result->subrange.set(querySubStringRange(l));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
else
|
|
@@ -1162,11 +1230,19 @@ bool FilterExtractor::extractSimpleCompareFilter(KeyConditionInfo & matches, IHq
|
|
matchedSelector = isKeyableFilter(r, l, duplicate, op, reasonr, keyedKind);
|
|
matchedSelector = isKeyableFilter(r, l, duplicate, op, reasonr, keyedKind);
|
|
if (matchedSelector)
|
|
if (matchedSelector)
|
|
{
|
|
{
|
|
|
|
+ //Do not match implicit substring filters by default - because only a single substring range is supported
|
|
|
|
+ if (createValueSets && isSubString(r) && (keyedKind == KeyedNo))
|
|
|
|
+ {
|
|
|
|
+ matches.appendPostFilter(expr);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
node_operator newOp = getModifiedOp(getReverseOp(op), duplicate);
|
|
node_operator newOp = getModifiedOp(getReverseOp(op), duplicate);
|
|
if (newOp != no_none)
|
|
if (newOp != no_none)
|
|
{
|
|
{
|
|
OwnedHqlExpr newFilter = createValue(newOp, expr->getType(), LINK(r), LINK(l));
|
|
OwnedHqlExpr newFilter = createValue(newOp, expr->getType(), LINK(r), LINK(l));
|
|
result.setown(new KeyCondition(matchedSelector, newFilter, keyedKind));
|
|
result.setown(new KeyCondition(matchedSelector, newFilter, keyedKind));
|
|
|
|
+ result->subrange.set(querySubStringRange(r));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|