1
0
Fork 0

preparation work for issue #137

This commit is contained in:
Jan Steemann 2012-08-06 10:30:15 +02:00
parent ac99877f67
commit 8326bb2abf
5 changed files with 208 additions and 275 deletions

View File

@ -57,10 +57,8 @@ static char* AccessName (const TRI_aql_access_e type) {
return "single range"; return "single range";
case TRI_AQL_ACCESS_RANGE_DOUBLE: case TRI_AQL_ACCESS_RANGE_DOUBLE:
return "double range"; return "double range";
case TRI_AQL_ACCESS_REFERENCE_EXACT: case TRI_AQL_ACCESS_REFERENCE:
return "eq reference"; return "reference";
case TRI_AQL_ACCESS_REFERENCE_RANGE:
return "range reference";
case TRI_AQL_ACCESS_ALL: case TRI_AQL_ACCESS_ALL:
return "all"; return "all";
} }
@ -123,8 +121,7 @@ static void FreeAccessMembers (TRI_aql_field_access_t* const fieldAccess) {
break; break;
} }
case TRI_AQL_ACCESS_REFERENCE_EXACT: case TRI_AQL_ACCESS_REFERENCE:
case TRI_AQL_ACCESS_REFERENCE_RANGE:
case TRI_AQL_ACCESS_ALL: case TRI_AQL_ACCESS_ALL:
case TRI_AQL_ACCESS_IMPOSSIBLE: { case TRI_AQL_ACCESS_IMPOSSIBLE: {
// nada // nada
@ -317,8 +314,7 @@ static TRI_aql_field_access_t* MergeAndExact (TRI_aql_context_t* const context,
return rhs; return rhs;
} }
if (rhs->_type == TRI_AQL_ACCESS_REFERENCE_EXACT || if (rhs->_type == TRI_AQL_ACCESS_REFERENCE) {
rhs->_type == TRI_AQL_ACCESS_REFERENCE_RANGE) {
// for simplicity, always return the const access // for simplicity, always return the const access
TRI_FreeAccessAql(rhs); TRI_FreeAccessAql(rhs);
return lhs; return lhs;
@ -445,8 +441,7 @@ static TRI_aql_field_access_t* MergeAndList (TRI_aql_context_t* const context,
return lhs; return lhs;
} }
if (rhs->_type == TRI_AQL_ACCESS_REFERENCE_EXACT || if (rhs->_type == TRI_AQL_ACCESS_REFERENCE) {
rhs->_type == TRI_AQL_ACCESS_REFERENCE_RANGE) {
// for simplicity, always return the const access // for simplicity, always return the const access
TRI_FreeAccessAql(rhs); TRI_FreeAccessAql(rhs);
return lhs; return lhs;
@ -790,8 +785,7 @@ static TRI_aql_field_access_t* MergeAndRangeSingle (TRI_aql_context_t* const con
return lhs; return lhs;
} }
if (rhs->_type == TRI_AQL_ACCESS_REFERENCE_EXACT || if (rhs->_type == TRI_AQL_ACCESS_REFERENCE) {
rhs->_type == TRI_AQL_ACCESS_REFERENCE_RANGE) {
// for simplicity, always return the const access // for simplicity, always return the const access
TRI_FreeAccessAql(rhs); TRI_FreeAccessAql(rhs);
return lhs; return lhs;
@ -859,8 +853,7 @@ static TRI_aql_field_access_t* MergeAndRangeDouble (TRI_aql_context_t* const con
return lhs; return lhs;
} }
if (rhs->_type == TRI_AQL_ACCESS_REFERENCE_EXACT || if (rhs->_type == TRI_AQL_ACCESS_REFERENCE) {
rhs->_type == TRI_AQL_ACCESS_REFERENCE_RANGE) {
// for simplicity, always return the const access // for simplicity, always return the const access
TRI_FreeAccessAql(rhs); TRI_FreeAccessAql(rhs);
return lhs; return lhs;
@ -880,112 +873,98 @@ static TRI_aql_field_access_t* MergeAndRangeDouble (TRI_aql_context_t* const con
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief merge two access structures using a logical AND /// @brief merge two access structures using a logical AND
/// ///
/// left hand operand is a reference, so it will always be returned /// left hand operand is a reference
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static TRI_aql_field_access_t* MergeAndReferenceExact (TRI_aql_context_t* const context, static TRI_aql_field_access_t* MergeAndReference (TRI_aql_context_t* const context,
TRI_aql_field_access_t* lhs, TRI_aql_field_access_t* lhs,
TRI_aql_field_access_t* rhs) { TRI_aql_field_access_t* rhs) {
assert(lhs->_type == TRI_AQL_ACCESS_REFERENCE_EXACT); assert(lhs->_type == TRI_AQL_ACCESS_REFERENCE);
if (rhs->_type == TRI_AQL_ACCESS_REFERENCE_EXACT) { if (rhs->_type == TRI_AQL_ACCESS_REFERENCE) {
if (TRI_EqualString(lhs->_value._name, TRI_aql_node_type_e lhsType = lhs->_value._reference._type;
rhs->_value._name)) { TRI_aql_node_type_e rhsType = rhs->_value._reference._type;
// reference to the same variable/attribute, no special treatment here bool isSameAttribute = TRI_EqualString(lhs->_value._reference._name, rhs->_value._reference._name);
// fall-through bool possible;
}
// reference to different variable/attribute if (!isSameAttribute) {
TRI_FreeAccessAql(rhs); // different attribute names are referred to. we can return either
return lhs;
}
if (rhs->_type == TRI_AQL_ACCESS_REFERENCE_RANGE) {
if (TRI_EqualString(lhs->_value._name,
rhs->_value._referenceRange._name)) {
// reference to the same variable/attribute
if (rhs->_value._referenceRange._type == TRI_AQL_NODE_OPERATOR_BINARY_LT ||
rhs->_value._referenceRange._type == TRI_AQL_NODE_OPERATOR_BINARY_GT) {
// == && > or == && < => impossible
TRI_FreeAccessAql(rhs);
FreeAccessMembers(lhs);
lhs->_type = TRI_AQL_ACCESS_IMPOSSIBLE;
return lhs;
}
// everything else results in lhs
// == && >= or == && <=
TRI_FreeAccessAql(rhs); TRI_FreeAccessAql(rhs);
return lhs; return lhs;
} }
// reference to different variable/attribute, no special treatment here
}
TRI_FreeAccessAql(rhs); // both references refer to the same variable, now compare their operators
return lhs; assert(isSameAttribute);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief merge two access structures using a logical AND
///
/// left hand operand is a reference, so it will always be returned
////////////////////////////////////////////////////////////////////////////////
static TRI_aql_field_access_t* MergeAndReferenceRange (TRI_aql_context_t* const context,
TRI_aql_field_access_t* lhs,
TRI_aql_field_access_t* rhs) {
assert(lhs->_type == TRI_AQL_ACCESS_REFERENCE_RANGE);
if (rhs->_type == TRI_AQL_ACCESS_REFERENCE_RANGE) {
if (TRI_EqualString(lhs->_value._referenceRange._name,
rhs->_value._referenceRange._name)) {
// both references refer to the same variable, now compare their operators
TRI_aql_node_type_e lhsType = lhs->_value._referenceRange._type;
TRI_aql_node_type_e rhsType = rhs->_value._referenceRange._type;
bool possible = true;
if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT &&
(rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GE || rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT)) {
// lhs < ref && (lhs >= ref || lhs > ref) => impossible
possible = false;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LE &&
rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT) {
// lhs <= ref && lhs > ref => impossible
possible = false;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT &&
(rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LE || rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT)) {
// lhs > ref && (lhs <= ref || lhs < ref) => impossible
possible = false;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_GE &&
rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT) {
// lhs >= ref && lhs < ref => impossible
possible = false;
}
if (!possible) {
// return the impossible range
TRI_FreeAccessAql(rhs);
FreeAccessMembers(lhs);
lhs->_type = TRI_AQL_ACCESS_IMPOSSIBLE;
return lhs; if (lhsType == rhsType) {
} // same operator, i.e. the two references are absolutely identical
TRI_FreeAccessAql(rhs);
// fall-through return lhs;
} }
// return either side (we pick lhs, but it does not matter) if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LE) {
// < && <=, merge to <
TRI_FreeAccessAql(rhs);
return lhs;
}
if (rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT && lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LE) {
// <= && <, merge to <
TRI_FreeAccessAql(lhs);
return rhs;
}
possible = true;
if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_EQ &&
(rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT ||
rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT)) {
// lhs == ref && (lhs < ref || lhs > ref)
possible = false;
}
else if (rhsType == TRI_AQL_NODE_OPERATOR_BINARY_EQ &&
(lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT ||
lhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT)) {
// (lhs < ref || lhs > ref) && lhs == ref
possible = false;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT &&
(rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GE || rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT)) {
// lhs < ref && (lhs >= ref || lhs > ref) => impossible
possible = false;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LE &&
rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT) {
// lhs <= ref && lhs > ref => impossible
possible = false;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT &&
(rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LE || rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT)) {
// lhs > ref && (lhs <= ref || lhs < ref) => impossible
possible = false;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_GE &&
rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT) {
// lhs >= ref && lhs < ref => impossible
possible = false;
}
if (!possible) {
// return the impossible range
TRI_FreeAccessAql(rhs);
FreeAccessMembers(lhs);
lhs->_type = TRI_AQL_ACCESS_IMPOSSIBLE;
return lhs;
}
// everything else results in lhs
TRI_FreeAccessAql(rhs); TRI_FreeAccessAql(rhs);
return lhs; return lhs;
} }
if (rhs->_type == TRI_AQL_ACCESS_ALL) { if (rhs->_type == TRI_AQL_ACCESS_ALL) {
TRI_FreeAccessAql(rhs); TRI_FreeAccessAql(rhs);
return lhs; return lhs;
@ -1157,8 +1136,7 @@ static TRI_aql_field_access_t* MergeOrExact (TRI_aql_context_t* const context,
return rhs; return rhs;
} }
if (rhs->_type == TRI_AQL_ACCESS_REFERENCE_EXACT || if (rhs->_type == TRI_AQL_ACCESS_REFERENCE) {
rhs->_type == TRI_AQL_ACCESS_REFERENCE_RANGE) {
// reference cannot be ORed with anything else // reference cannot be ORed with anything else
TRI_FreeAccessAql(rhs); TRI_FreeAccessAql(rhs);
FreeAccessMembers(lhs); FreeAccessMembers(lhs);
@ -1374,8 +1352,7 @@ static TRI_aql_field_access_t* MergeOrRangeDouble (TRI_aql_context_t* const cont
return lhs; return lhs;
} }
if (rhs->_type == TRI_AQL_ACCESS_REFERENCE_EXACT || if (rhs->_type == TRI_AQL_ACCESS_REFERENCE) {
rhs->_type == TRI_AQL_ACCESS_REFERENCE_RANGE) {
// reference cannot be ORed with anything else // reference cannot be ORed with anything else
TRI_FreeAccessAql(rhs); TRI_FreeAccessAql(rhs);
FreeAccessMembers(lhs); FreeAccessMembers(lhs);
@ -1401,117 +1378,63 @@ static TRI_aql_field_access_t* MergeOrRangeDouble (TRI_aql_context_t* const cont
/// left hand operand is reference access /// left hand operand is reference access
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static TRI_aql_field_access_t* MergeOrReferenceExact (TRI_aql_context_t* const context, static TRI_aql_field_access_t* MergeOrReference (TRI_aql_context_t* const context,
TRI_aql_field_access_t* lhs, TRI_aql_field_access_t* lhs,
TRI_aql_field_access_t* rhs) { TRI_aql_field_access_t* rhs) {
assert(lhs->_type == TRI_AQL_ACCESS_REFERENCE_EXACT); assert(lhs->_type == TRI_AQL_ACCESS_REFERENCE);
if (rhs->_type == TRI_AQL_ACCESS_REFERENCE_EXACT) { if (rhs->_type == TRI_AQL_ACCESS_REFERENCE) {
if (TRI_EqualString(lhs->_value._name, TRI_aql_node_type_e lhsType = lhs->_value._reference._type;
rhs->_value._name)) { TRI_aql_node_type_e rhsType = rhs->_value._reference._type;
// both references refer to the same variable bool isSameAttribute = TRI_EqualString(lhs->_value._reference._name, rhs->_value._reference._name);
if (!isSameAttribute) {
// references refer to different attributes
TRI_FreeAccessAql(rhs);
FreeAccessMembers(lhs);
lhs->_type = TRI_AQL_ACCESS_ALL;
return lhs;
}
// both references refer to the same thing, now compare their operators
assert(isSameAttribute);
if (lhsType == rhsType) {
// same operator, i.e. the two references are identical
TRI_FreeAccessAql(rhs); TRI_FreeAccessAql(rhs);
return lhs; return lhs;
} }
// fall-through else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LE) {
} // < || <=, merge to <=
TRI_FreeAccessAql(lhs);
if (rhs->_type == TRI_AQL_ACCESS_REFERENCE_RANGE) { return rhs;
if (TRI_EqualString(lhs->_value._name,
rhs->_value._referenceRange._name)) {
// both references refer to the same variable
TRI_aql_node_type_e lhsType = lhs->_value._referenceRange._type;
TRI_aql_node_type_e rhsType = rhs->_value._referenceRange._type;
if (lhsType == rhsType) {
// same operation
TRI_FreeAccessAql(rhs);
return lhs;
}
if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LE) {
TRI_FreeAccessAql(lhs);
return rhs;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LE && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT) {
TRI_FreeAccessAql(rhs);
return lhs;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GE) {
TRI_FreeAccessAql(lhs);
return rhs;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_GE && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT) {
TRI_FreeAccessAql(rhs);
return lhs;
}
} }
// fall-through else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LE && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT) {
} // <= || <, merge to <=
TRI_FreeAccessAql(rhs);
// for everything else, we have to use the ALL range unfortunately return lhs;
TRI_FreeAccessAql(rhs);
FreeAccessMembers(lhs);
lhs->_type = TRI_AQL_ACCESS_ALL;
return lhs;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief merge two access structures using a logical OR
///
/// left hand operand is reference access
////////////////////////////////////////////////////////////////////////////////
static TRI_aql_field_access_t* MergeOrReferenceRange (TRI_aql_context_t* const context,
TRI_aql_field_access_t* lhs,
TRI_aql_field_access_t* rhs) {
assert(lhs->_type == TRI_AQL_ACCESS_REFERENCE_RANGE);
if (rhs->_type == TRI_AQL_ACCESS_REFERENCE_RANGE) {
if (TRI_EqualString(lhs->_value._referenceRange._name,
rhs->_value._referenceRange._name)) {
// both references refer to the same variable
TRI_aql_node_type_e lhsType = lhs->_value._referenceRange._type;
TRI_aql_node_type_e rhsType = rhs->_value._referenceRange._type;
if (lhsType == rhsType) {
// same operation
TRI_FreeAccessAql(rhs);
return lhs;
}
if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LE) {
TRI_FreeAccessAql(lhs);
return rhs;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_LE && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_LT) {
TRI_FreeAccessAql(rhs);
return lhs;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GE) {
TRI_FreeAccessAql(lhs);
return rhs;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_GE && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT) {
TRI_FreeAccessAql(rhs);
return lhs;
}
} }
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GE) {
// > || >=, merge to >=
TRI_FreeAccessAql(lhs);
return rhs;
}
else if (lhsType == TRI_AQL_NODE_OPERATOR_BINARY_GE && rhsType == TRI_AQL_NODE_OPERATOR_BINARY_GT) {
// >= || >, merge to >=
TRI_FreeAccessAql(rhs);
return lhs;
}
// fall-through // fall-through
} }
// for everything else, we have to use the ALL range unfortunately // for everything else, we have to use the ALL range unfortunately
TRI_FreeAccessAql(rhs); TRI_FreeAccessAql(rhs);
FreeAccessMembers(lhs); FreeAccessMembers(lhs);
@ -1553,10 +1476,8 @@ static TRI_aql_field_access_t* MergeAttributeAccessAnd (TRI_aql_context_t* const
return MergeAndRangeSingle(context, lhs, rhs); return MergeAndRangeSingle(context, lhs, rhs);
case TRI_AQL_ACCESS_RANGE_DOUBLE: case TRI_AQL_ACCESS_RANGE_DOUBLE:
return MergeAndRangeDouble(context, lhs, rhs); return MergeAndRangeDouble(context, lhs, rhs);
case TRI_AQL_ACCESS_REFERENCE_EXACT: case TRI_AQL_ACCESS_REFERENCE:
return MergeAndReferenceExact(context, lhs, rhs); return MergeAndReference(context, lhs, rhs);
case TRI_AQL_ACCESS_REFERENCE_RANGE:
return MergeAndReferenceRange(context, lhs, rhs);
case TRI_AQL_ACCESS_ALL: case TRI_AQL_ACCESS_ALL:
return MergeAndAll(context, lhs, rhs); return MergeAndAll(context, lhs, rhs);
} }
@ -1598,10 +1519,8 @@ static TRI_aql_field_access_t* MergeAttributeAccessOr (TRI_aql_context_t* const
return MergeOrRangeSingle(context, lhs, rhs); return MergeOrRangeSingle(context, lhs, rhs);
case TRI_AQL_ACCESS_RANGE_DOUBLE: case TRI_AQL_ACCESS_RANGE_DOUBLE:
return MergeOrRangeDouble(context, lhs, rhs); return MergeOrRangeDouble(context, lhs, rhs);
case TRI_AQL_ACCESS_REFERENCE_EXACT: case TRI_AQL_ACCESS_REFERENCE:
return MergeOrReferenceExact(context, lhs, rhs); return MergeOrReference(context, lhs, rhs);
case TRI_AQL_ACCESS_REFERENCE_RANGE:
return MergeOrReferenceRange(context, lhs, rhs);
case TRI_AQL_ACCESS_ALL: case TRI_AQL_ACCESS_ALL:
return MergeOrAll(context, lhs, rhs); return MergeOrAll(context, lhs, rhs);
} }
@ -1897,15 +1816,9 @@ static TRI_aql_field_access_t* CreateAccessForNode (TRI_aql_context_t* const con
if (node->_type == TRI_AQL_NODE_REFERENCE) { if (node->_type == TRI_AQL_NODE_REFERENCE) {
// create the reference access // create the reference access
if (operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ) { fieldAccess->_type = TRI_AQL_ACCESS_REFERENCE;
fieldAccess->_type = TRI_AQL_ACCESS_REFERENCE_EXACT; fieldAccess->_value._reference._type = operator;
fieldAccess->_value._name = TRI_AQL_NODE_STRING(node); fieldAccess->_value._reference._name = TRI_AQL_NODE_STRING(node);
}
else {
fieldAccess->_type = TRI_AQL_ACCESS_REFERENCE_RANGE;
fieldAccess->_value._referenceRange._type = operator;
fieldAccess->_value._referenceRange._name = TRI_AQL_NODE_STRING(node);
}
return fieldAccess; return fieldAccess;
} }
@ -2325,14 +2238,9 @@ TRI_aql_field_access_t* TRI_CloneAccessAql (TRI_aql_context_t* const context,
break; break;
} }
case TRI_AQL_ACCESS_REFERENCE_EXACT: { case TRI_AQL_ACCESS_REFERENCE: {
fieldAccess->_value._name = source->_value._name; fieldAccess->_value._reference._type = source->_value._reference._type;
break; fieldAccess->_value._reference._name = source->_value._reference._name;
}
case TRI_AQL_ACCESS_REFERENCE_RANGE: {
fieldAccess->_value._referenceRange._type = source->_value._referenceRange._type;
fieldAccess->_value._referenceRange._name = source->_value._referenceRange._name;
break; break;
} }

View File

@ -73,8 +73,8 @@ typedef enum {
TRI_AQL_ACCESS_LIST, // a list of values is accessed TRI_AQL_ACCESS_LIST, // a list of values is accessed
TRI_AQL_ACCESS_RANGE_SINGLE, // a range with one boundary is accessed TRI_AQL_ACCESS_RANGE_SINGLE, // a range with one boundary is accessed
TRI_AQL_ACCESS_RANGE_DOUBLE, // a two bounded range is accessed TRI_AQL_ACCESS_RANGE_DOUBLE, // a two bounded range is accessed
TRI_AQL_ACCESS_REFERENCE_EXACT, // a reference can be used for eq access (a.x == b.x) TRI_AQL_ACCESS_REFERENCE, // a reference can be used for eq access (a.x == b.x)
TRI_AQL_ACCESS_REFERENCE_RANGE, // a reference can be used for rahe access (a.x > b.x) // or range access (a.x > b.x)
TRI_AQL_ACCESS_ALL // all values must be accessed (full scan) TRI_AQL_ACCESS_ALL // all values must be accessed (full scan)
} }
TRI_aql_access_e; TRI_aql_access_e;
@ -118,12 +118,11 @@ typedef struct TRI_aql_field_access_s {
TRI_aql_range_t _upper; // upper bound TRI_aql_range_t _upper; // upper bound
} }
_between; // used for TRI_AQL_ACCESS_RANGE_DOUBLE _between; // used for TRI_AQL_ACCESS_RANGE_DOUBLE
char* _name; // used for TRI_AQL_ACCESS_REFERENCE_EXACT
struct { struct {
char* _name; char* _name;
TRI_aql_node_type_e _type; TRI_aql_node_type_e _type;
} }
_referenceRange; // used for TRI_AQL_ACCESS_REFERENCE_RANGE _reference; // used for TRI_AQL_ACCESS_REFERENCE
} }
_value; _value;
} }

View File

@ -884,7 +884,8 @@ static void GeneratePrimaryAccess (TRI_aql_codegen_js_t* const generator,
assert(fieldAccess->_type == TRI_AQL_ACCESS_EXACT || assert(fieldAccess->_type == TRI_AQL_ACCESS_EXACT ||
fieldAccess->_type == TRI_AQL_ACCESS_LIST || fieldAccess->_type == TRI_AQL_ACCESS_LIST ||
fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE_EXACT); (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE &&
fieldAccess->_value._reference._type == TRI_AQL_NODE_OPERATOR_BINARY_EQ));
if (fieldAccess->_type == TRI_AQL_ACCESS_LIST) { if (fieldAccess->_type == TRI_AQL_ACCESS_LIST) {
ScopeOutput(generator, "AHUACATL_GET_DOCUMENTS_PRIMARY_LIST('"); ScopeOutput(generator, "AHUACATL_GET_DOCUMENTS_PRIMARY_LIST('");
@ -897,8 +898,10 @@ static void GeneratePrimaryAccess (TRI_aql_codegen_js_t* const generator,
ScopeOutput(generator, "', "); ScopeOutput(generator, "', ");
ScopeOutputIndexId(generator, collection, idx); ScopeOutputIndexId(generator, collection, idx);
ScopeOutput(generator, ", "); ScopeOutput(generator, ", ");
if (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE_EXACT) { if (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE) {
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._name)); assert(fieldAccess->_value._reference._type == TRI_AQL_NODE_OPERATOR_BINARY_EQ);
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._name));
} }
else { else {
ScopeOutputJson(generator, fieldAccess->_value._value); ScopeOutputJson(generator, fieldAccess->_value._value);
@ -949,7 +952,8 @@ static void GenerateHashAccess (TRI_aql_codegen_js_t* const generator,
TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) TRI_AtVectorPointer(idx->_fieldAccesses, i); TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) TRI_AtVectorPointer(idx->_fieldAccesses, i);
assert(fieldAccess->_type == TRI_AQL_ACCESS_EXACT || assert(fieldAccess->_type == TRI_AQL_ACCESS_EXACT ||
fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE_EXACT); (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE &&
fieldAccess->_value._reference._type == TRI_AQL_NODE_OPERATOR_BINARY_EQ));
if (i > 0) { if (i > 0) {
ScopeOutput(generator, ", "); ScopeOutput(generator, ", ");
@ -957,8 +961,10 @@ static void GenerateHashAccess (TRI_aql_codegen_js_t* const generator,
ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1); ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1);
ScopeOutput(generator, " : "); ScopeOutput(generator, " : ");
if (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE_EXACT) { if (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE) {
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._name)); assert(fieldAccess->_value._reference._type == TRI_AQL_NODE_OPERATOR_BINARY_EQ);
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._name));
} }
else { else {
ScopeOutputJson(generator, fieldAccess->_value._value); ScopeOutputJson(generator, fieldAccess->_value._value);
@ -1013,8 +1019,7 @@ static void GenerateSkiplistAccess (TRI_aql_codegen_js_t* const generator,
assert(fieldAccess->_type == TRI_AQL_ACCESS_EXACT || assert(fieldAccess->_type == TRI_AQL_ACCESS_EXACT ||
fieldAccess->_type == TRI_AQL_ACCESS_RANGE_SINGLE || fieldAccess->_type == TRI_AQL_ACCESS_RANGE_SINGLE ||
fieldAccess->_type == TRI_AQL_ACCESS_RANGE_DOUBLE || fieldAccess->_type == TRI_AQL_ACCESS_RANGE_DOUBLE ||
fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE_EXACT || fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE);
fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE_RANGE);
if (i > 0) { if (i > 0) {
ScopeOutput(generator, ", "); ScopeOutput(generator, ", ");
@ -1048,16 +1053,11 @@ static void GenerateSkiplistAccess (TRI_aql_codegen_js_t* const generator,
ScopeOutputJson(generator, fieldAccess->_value._between._upper._value); ScopeOutputJson(generator, fieldAccess->_value._between._upper._value);
ScopeOutput(generator, " ] "); ScopeOutput(generator, " ] ");
} }
else if (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE_EXACT) { else if (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE) {
ScopeOutput(generator, " [ \"==\", ");
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._name));
ScopeOutput(generator, " ] ");
}
else if (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE_RANGE) {
ScopeOutput(generator, " [ \""); ScopeOutput(generator, " [ \"");
ScopeOutput(generator, TRI_RangeOperatorAql(fieldAccess->_value._singleRange._type)); ScopeOutput(generator, TRI_RangeOperatorAql(fieldAccess->_value._reference._type));
ScopeOutput(generator, "\", "); ScopeOutput(generator, "\", ");
ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._name)); ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._name));
ScopeOutput(generator, " ] "); ScopeOutput(generator, " ] ");
} }

View File

@ -43,7 +43,9 @@
/// @brief log information about the used index /// @brief log information about the used index
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void LogIndexString (TRI_index_t const* idx, #ifdef TRI_DEBUG_AQL
static void LogIndexString (const char* const what,
TRI_index_t const* idx,
char const* collectionName) { char const* collectionName) {
TRI_string_buffer_t* buffer = TRI_CreateStringBuffer(TRI_UNKNOWN_MEM_ZONE); TRI_string_buffer_t* buffer = TRI_CreateStringBuffer(TRI_UNKNOWN_MEM_ZONE);
size_t i; size_t i;
@ -60,13 +62,39 @@ static void LogIndexString (TRI_index_t const* idx,
TRI_AppendStringStringBuffer(buffer, idx->_fields._buffer[i]); TRI_AppendStringStringBuffer(buffer, idx->_fields._buffer[i]);
} }
TRI_AQL_LOG("using %s index (%s) for '%s'", TRI_AQL_LOG("%s %s index (%s) for '%s'",
what,
TRI_TypeNameIndex(idx), TRI_TypeNameIndex(idx),
buffer->_buffer, buffer->_buffer,
collectionName); collectionName);
TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer); TRI_FreeStringBuffer(TRI_UNKNOWN_MEM_ZONE, buffer);
} }
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief check whether a field access candidate is an exact access
////////////////////////////////////////////////////////////////////////////////
static bool isExactCandidate (const TRI_aql_field_access_t* const candidate) {
if (candidate->_type == TRI_AQL_ACCESS_EXACT) {
// ==
return true;
}
if (candidate->_type == TRI_AQL_ACCESS_LIST) {
// in (...)
return true;
}
if (candidate->_type == TRI_AQL_ACCESS_REFERENCE &&
candidate->_value._reference._type == TRI_AQL_NODE_OPERATOR_BINARY_EQ) {
// == ref
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief pick or replace an index /// @brief pick or replace an index
@ -165,14 +193,14 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
n = availableIndexes->_length; n = availableIndexes->_length;
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
TRI_index_t* idx = (TRI_index_t*) availableIndexes->_buffer[i]; TRI_index_t* idx = (TRI_index_t*) availableIndexes->_buffer[i];
TRI_aql_access_e lastType;
size_t numIndexFields = idx->_fields._length; size_t numIndexFields = idx->_fields._length;
bool lastTypeWasExact;
if (numIndexFields == 0) { if (numIndexFields == 0) {
// index should contain at least one field // index should contain at least one field
continue; continue;
} }
// we'll use a switch here so the compiler warns if new index types are added elsewhere but not here // we'll use a switch here so the compiler warns if new index types are added elsewhere but not here
switch (idx->_type) { switch (idx->_type) {
case TRI_IDX_TYPE_GEO1_INDEX: case TRI_IDX_TYPE_GEO1_INDEX:
@ -188,10 +216,14 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
// these indexes are valid candidates // these indexes are valid candidates
break; break;
} }
#ifdef TRI_DEBUG_AQL
LogIndexString("checking", idx, collectionName);
#endif
TRI_ClearVectorPointer(&matches); TRI_ClearVectorPointer(&matches);
lastType = TRI_AQL_ACCESS_EXACT; lastTypeWasExact = true;
// now loop over all index fields, from left to right // now loop over all index fields, from left to right
// index field order is important because skiplists can be used with leftmost prefixes as well, // index field order is important because skiplists can be used with leftmost prefixes as well,
@ -221,9 +253,7 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
// attribute is used in index // attribute is used in index
if (idx->_type == TRI_IDX_TYPE_PRIMARY_INDEX) { if (idx->_type == TRI_IDX_TYPE_PRIMARY_INDEX) {
if (candidate->_type != TRI_AQL_ACCESS_EXACT && if (!isExactCandidate(candidate)) {
candidate->_type != TRI_AQL_ACCESS_LIST &&
candidate->_type != TRI_AQL_ACCESS_REFERENCE_EXACT) {
// wrong access type for primary index // wrong access type for primary index
continue; continue;
} }
@ -231,9 +261,7 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
TRI_PushBackVectorPointer(&matches, candidate); TRI_PushBackVectorPointer(&matches, candidate);
} }
else if (idx->_type == TRI_IDX_TYPE_HASH_INDEX) { else if (idx->_type == TRI_IDX_TYPE_HASH_INDEX) {
if (candidate->_type != TRI_AQL_ACCESS_EXACT && if (!isExactCandidate(candidate)) {
candidate->_type != TRI_AQL_ACCESS_LIST &&
candidate->_type != TRI_AQL_ACCESS_REFERENCE_EXACT) {
// wrong access type for hash index // wrong access type for hash index
continue; continue;
} }
@ -247,14 +275,12 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
} }
else if (idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) { else if (idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) {
bool candidateIsExact; bool candidateIsExact;
bool lastIsExact;
if (candidate->_type != TRI_AQL_ACCESS_EXACT && if (candidate->_type != TRI_AQL_ACCESS_EXACT &&
candidate->_type != TRI_AQL_ACCESS_LIST && candidate->_type != TRI_AQL_ACCESS_LIST &&
candidate->_type != TRI_AQL_ACCESS_RANGE_SINGLE && candidate->_type != TRI_AQL_ACCESS_RANGE_SINGLE &&
candidate->_type != TRI_AQL_ACCESS_RANGE_DOUBLE && candidate->_type != TRI_AQL_ACCESS_RANGE_DOUBLE &&
candidate->_type != TRI_AQL_ACCESS_REFERENCE_EXACT && candidate->_type != TRI_AQL_ACCESS_REFERENCE) {
candidate->_type != TRI_AQL_ACCESS_REFERENCE_RANGE) {
// wrong access type for skiplists // wrong access type for skiplists
continue; continue;
} }
@ -264,17 +290,16 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
continue; continue;
} }
candidateIsExact = (candidate->_type == TRI_AQL_ACCESS_EXACT || candidate->_type == TRI_AQL_ACCESS_REFERENCE_EXACT); candidateIsExact = isExactCandidate(candidate);
lastIsExact = (lastType == TRI_AQL_ACCESS_EXACT || lastType == TRI_AQL_ACCESS_REFERENCE_EXACT);
if ((candidateIsExact && !lastIsExact) || if ((candidateIsExact && !lastTypeWasExact) ||
(!candidateIsExact && !lastIsExact)) { (!candidateIsExact && !lastTypeWasExact)) {
// if we already had a range query, we cannot check for equality after that // if we already had a range query, we cannot check for equality after that
// if we already had a range query, we cannot check another range after that // if we already had a range query, we cannot check another range after that
continue; continue;
} }
lastType = candidate->_type; lastTypeWasExact = candidateIsExact;
TRI_PushBackVectorPointer(&matches, candidate); TRI_PushBackVectorPointer(&matches, candidate);
} }
@ -305,9 +330,11 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
TRI_DestroyVectorPointer(&matches); TRI_DestroyVectorPointer(&matches);
#ifdef TRI_DEBUG_AQL
if (picked) { if (picked) {
LogIndexString(picked->_idx, collectionName); LogIndexString("using", picked->_idx, collectionName);
} }
#endif
return picked; return picked;
} }

View File

@ -943,8 +943,7 @@ static void PatchVariables (TRI_aql_statement_walker_t* const walker) {
return; return;
} }
isReference = (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE_EXACT || isReference = (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE);
fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE_RANGE);
variable = TRI_GetVariableStatementWalkerAql(walker, variableName, &scopeCount); variable = TRI_GetVariableStatementWalkerAql(walker, variableName, &scopeCount);
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, variableName); TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, variableName);