1
0
Fork 0

added limited AQL support for bit indexes

This commit is contained in:
Oreste Panaia 2012-09-10 20:42:14 +08:00
parent d632fb820b
commit 8847d87580
14 changed files with 572 additions and 89 deletions

View File

@ -0,0 +1,35 @@
> curl --data @- -X POST --dump - http://localhost:8529/_api/index?collection=109061392
{ "type" : "skiplist", "unique" : false, "fields" : [ "x", [0,1,[]], "y", ["a","b",[]] ] }
HTTP/1.1 201 Created
content-type: application/json
{
"fields": [
[
"x",
[
0,
1,
[
]
]
],
[
"y",
[
"a",
"b",
[
]
]
]
],
"id": "109061392/173166777",
"type": "bitarray",
"isNewlyCreated": true,
"unique": false,
"undefined": false,
"code": 201,
"error": false
}

88
arangod/Ahuacatl/ahuacatl-codegen.c Normal file → Executable file
View File

@ -1088,6 +1088,88 @@ static void GenerateSkiplistAccess (TRI_aql_codegen_js_t* const generator,
ScopeOutput(generator, " })");
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate code for bitarray access
////////////////////////////////////////////////////////////////////////////////
static void GenerateBitarrayAccess (TRI_aql_codegen_js_t* const generator,
const TRI_aql_index_t* const idx,
const TRI_aql_collection_t* const collection,
const char* const collectionName) {
size_t i, n;
n = idx->_fieldAccesses->_length;
assert(n >= 1);
if (n == 1) {
// peek at first element and check if it is a list access
TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) TRI_AtVectorPointer(idx->_fieldAccesses, 0);
if (fieldAccess->_type == TRI_AQL_ACCESS_LIST) {
assert(false);
ScopeOutput(generator, "AHUACATL_GET_DOCUMENTS_BITARRAY_LIST('");
ScopeOutput(generator, collectionName);
ScopeOutput(generator, "', ");
ScopeOutputIndexId(generator, collection, idx);
ScopeOutput(generator, ", ");
ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1);
ScopeOutput(generator, ", ");
ScopeOutputJson(generator, fieldAccess->_value._value);
ScopeOutput(generator, ")");
return;
}
// fall through to other access types
}
ScopeOutput(generator, "AHUACATL_GET_DOCUMENTS_BITARRAY('");
ScopeOutput(generator, collectionName);
ScopeOutput(generator, "', ");
ScopeOutputIndexId(generator, collection, idx);
ScopeOutput(generator, ", { \"==\" : {"); // only support the equality operator for now
// ..................................................................................
// Construct the javascript object which will eventually be used to generate
// the index operator. The object is in the form: {"==": {"x":0}}
// ..................................................................................
for (i = 0; i < n; ++i) {
TRI_aql_field_access_t* fieldAccess = (TRI_aql_field_access_t*) TRI_AtVectorPointer(idx->_fieldAccesses, i);
// ................................................................................
// Only implement equality operator for now
// ................................................................................
ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1);
ScopeOutput(generator, " : ");
switch (fieldAccess->_type) {
case TRI_AQL_ACCESS_EXACT: {
ScopeOutputJson(generator, fieldAccess->_value._value);
break;
}
case TRI_AQL_ACCESS_REFERENCE: {
ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node);
}
default: {
assert(false);
}
}
if (i < (n-1)) {
ScopeOutput(generator, ", ");
}
}
ScopeOutput(generator, "} })");
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate code for a reference (the name of a variable)
////////////////////////////////////////////////////////////////////////////////
@ -1287,7 +1369,6 @@ static void ProcessCollectionHinted (TRI_aql_codegen_js_t* const generator,
case TRI_IDX_TYPE_GEO2_INDEX:
case TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX:
case TRI_IDX_TYPE_CAP_CONSTRAINT:
case TRI_IDX_TYPE_BITARRAY_INDEX:
// these index types are not yet supported
generator->_errorCode = TRI_ERROR_INTERNAL;
break;
@ -1303,6 +1384,11 @@ static void ProcessCollectionHinted (TRI_aql_codegen_js_t* const generator,
case TRI_IDX_TYPE_SKIPLIST_INDEX:
GenerateSkiplistAccess(generator, hint->_index, hint->_collection, collectionName);
break;
case TRI_IDX_TYPE_BITARRAY_INDEX: {
GenerateBitarrayAccess(generator, hint->_index, hint->_collection, collectionName);
break;
}
}
}

1
arangod/Ahuacatl/ahuacatl-context.c Normal file → Executable file
View File

@ -335,6 +335,7 @@ bool TRI_BindQueryContextAql (TRI_aql_context_t* const context,
////////////////////////////////////////////////////////////////////////////////
bool TRI_OptimiseQueryContextAql (TRI_aql_context_t* const context) {
// do some basic optimisations in the AST
if (!TRI_OptimiseAql(context)) {
// constant folding failed

122
arangod/Ahuacatl/ahuacatl-index.c Normal file → Executable file
View File

@ -104,11 +104,11 @@ static TRI_aql_index_t* PickIndex (TRI_aql_context_t* const context,
TRI_aql_index_t* pickedIndex,
const TRI_index_t* const idx,
TRI_vector_pointer_t* fieldAccesses) {
bool isBetter;
bool isBetter = false;
assert(idx);
assert(fieldAccesses);
if (pickedIndex == NULL) {
pickedIndex = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_index_t), false);
pickedIndex->_idx = NULL;
@ -121,21 +121,98 @@ static TRI_aql_index_t* PickIndex (TRI_aql_context_t* const context,
return NULL;
}
// ...........................................................................
// If we do not have an index yet, then this index will do. As has been said
// before 'any index is better than none'
// ...........................................................................
if (pickedIndex->_idx == NULL) {
// any index is better than none
pickedIndex->_idx = (TRI_index_t*) idx;
pickedIndex->_fieldAccesses = TRI_CopyVectorPointer(TRI_UNKNOWN_MEM_ZONE, fieldAccesses);
return pickedIndex;
}
// ...........................................................................
// We have previously selected an index, if it happens to be the primary then
// we stick with it.
// ...........................................................................
if (pickedIndex->_idx->_type == TRI_IDX_TYPE_PRIMARY_INDEX) {
return pickedIndex;
}
// ...........................................................................
// Now go through the various possibilities if we have not located something
// better.
// ...........................................................................
if ( (isBetter == false) && (idx->_type == TRI_IDX_TYPE_PRIMARY_INDEX) ) {
// .........................................................................
// If we can used the primary index, then this is better than any other
// index so use it.
// .........................................................................
isBetter = true;
}
if ( (isBetter == false) && (idx->_type == TRI_IDX_TYPE_HASH_INDEX) ) {
// .........................................................................
// If the index type is a hash index, use this -- but only if we have NOT
// located something better BEFORE.
// .........................................................................
isBetter = true;
}
else {
isBetter = idx->_type == TRI_IDX_TYPE_PRIMARY_INDEX || // primary index is better than any others
(idx->_type == TRI_IDX_TYPE_HASH_INDEX && pickedIndex->_idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) || // hash is better than skiplist
(idx->_unique && !pickedIndex->_idx->_unique) || // unique indexes are better than non-unique ones
(fieldAccesses->_length < pickedIndex->_fieldAccesses->_length && idx->_unique) || // shorter indexes are better if unique
(fieldAccesses->_length > pickedIndex->_fieldAccesses->_length && !idx->_unique); // longer indexes are better if non-unique
// if we have already picked the primary index, we won't overwrite it with any other index
isBetter &= (pickedIndex->_idx->_type != TRI_IDX_TYPE_PRIMARY_INDEX);
if ( (isBetter == false) && (idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) &&
(pickedIndex->_idx->_type != TRI_IDX_TYPE_HASH_INDEX) ) {
// .........................................................................
// If the index type is a skiplist index, use this -- but only if we have NOT
// located something better BEFORE.
// .........................................................................
isBetter = true;
}
if ( (isBetter == false) && (idx->_type == TRI_IDX_TYPE_BITARRAY_INDEX) &&
(pickedIndex->_idx->_type != TRI_IDX_TYPE_HASH_INDEX) &&
(pickedIndex->_idx->_type != TRI_IDX_TYPE_SKIPLIST_INDEX) ) {
// .........................................................................
// If the index type is a bitarray index, use this -- but only if we have NOT
// located something better BEFORE.
// .........................................................................
isBetter = true;
}
if ( (isBetter == false) && (idx->_unique == true) && (pickedIndex->_idx->_unique == false) ) {
// .........................................................................
// If the index is a unique one and the picked index is non-unique, then
// replace it with the unique overriding the preferences above. E.g. if
// we have a non-unique hash index (which we have chosen) and now we are
// testing a unique skiplist, replace it with the skiplist.
// .........................................................................
isBetter = true;
}
if ( (isBetter == false) &&
(fieldAccesses->_length < pickedIndex->_fieldAccesses->_length ) &&
(idx->_unique == true) ) {
isBetter = true;
}
if ( (isBetter == false) &&
(fieldAccesses->_length > pickedIndex->_fieldAccesses->_length ) &&
(idx->_unique == false) ) {
isBetter = true;
}
if (isBetter) {
if (pickedIndex->_fieldAccesses != NULL) {
TRI_FreeVectorPointer(TRI_UNKNOWN_MEM_ZONE, pickedIndex->_fieldAccesses);
@ -189,7 +266,7 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
assert(context);
assert(collectionName);
assert(candidates);
n = availableIndexes->_length;
for (i = 0; i < n; ++i) {
TRI_index_t* idx = (TRI_index_t*) availableIndexes->_buffer[i];
@ -207,12 +284,12 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
case TRI_IDX_TYPE_GEO2_INDEX:
case TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX:
case TRI_IDX_TYPE_CAP_CONSTRAINT:
case TRI_IDX_TYPE_BITARRAY_INDEX:
// ignore all these index types for now
continue;
case TRI_IDX_TYPE_PRIMARY_INDEX:
case TRI_IDX_TYPE_HASH_INDEX:
case TRI_IDX_TYPE_SKIPLIST_INDEX:
case TRI_IDX_TYPE_BITARRAY_INDEX:
// these indexes are valid candidates
break;
}
@ -239,6 +316,7 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
for (k = 0; k < candidates->_length; ++k) {
TRI_aql_field_access_t* candidate = (TRI_aql_field_access_t*) TRI_AtVectorPointer(candidates, k);
if (candidate->_type == TRI_AQL_ACCESS_IMPOSSIBLE ||
candidate->_type == TRI_AQL_ACCESS_ALL) {
// wrong index type, doesn't help us at all
@ -260,6 +338,7 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
TRI_PushBackVectorPointer(&matches, candidate);
}
else if (idx->_type == TRI_IDX_TYPE_HASH_INDEX) {
if (!IsExactCandidate(candidate)) {
// wrong access type for hash index
@ -273,6 +352,21 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
TRI_PushBackVectorPointer(&matches, candidate);
}
else if (idx->_type == TRI_IDX_TYPE_BITARRAY_INDEX) {
if (!IsExactCandidate(candidate)) {
// wrong access type for hash index
continue;
}
if (candidate->_type == TRI_AQL_ACCESS_LIST) {
// we found a list, but the index covers multiple attributes. that means we cannot use list access
continue;
}
TRI_PushBackVectorPointer(&matches, candidate);
}
else if (idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) {
bool candidateIsExact;

4
arangod/Ahuacatl/ahuacatl-optimiser.c Normal file → Executable file
View File

@ -85,7 +85,7 @@ static void AttachCollectionHint (TRI_aql_context_t* const context,
collectionName = TRI_AQL_NODE_STRING(nameNode);
assert(collectionName);
hint = (TRI_aql_collection_hint_t*) TRI_AQL_NODE_DATA(node);
if (hint == NULL) {
@ -93,7 +93,7 @@ static void AttachCollectionHint (TRI_aql_context_t* const context,
return;
}
if (hint->_ranges == NULL) {
// no ranges found to be used as indexes

View File

@ -96,17 +96,16 @@ typedef struct
/* "points" lists the slotid of the points. This is */
/* only used for a leaf pot. */
/* =================================================== */
typedef struct
{
int LorLeaf;
int RorPoints;
GeoString middle;
GeoFix maxdist[GeoIndexFIXEDPOINTS];
GeoString start;
GeoString end;
int level;
int points[GeoIndexPOTSIZE];
} GeoPot;
typedef struct {
int LorLeaf;
int RorPoints;
GeoString middle;
GeoFix maxdist[GeoIndexFIXEDPOINTS];
GeoString start;
GeoString end;
int level;
int points[GeoIndexPOTSIZE];
} GeoPot;
/* =================================================== */
/* GeoIx structure */
/* This is the REAL GeoIndex structure - the one in */
@ -125,14 +124,13 @@ typedef struct
/* There is no provision at present for the index to */
/* get smaller when the majority of points are deleted */
/* =================================================== */
typedef struct
{
GeoIndexFixed fixed; /* fixed point data */
int potct; /* pots allocated */
int slotct; /* slots allocated */
GeoPot * pots; /* the pots themselves */
GeoCoordinate * gc; /* the slots themselves */
} GeoIx;
typedef struct {
GeoIndexFixed fixed; /* fixed point data */
int potct; /* pots allocated */
int slotct; /* slots allocated */
GeoPot * pots; /* the pots themselves */
GeoCoordinate * gc; /* the slots themselves */
} GeoIx;
/* =================================================== */
/* GeoDetailedPoint structure */
/* The routine GeoMkDetail is given a point - really */
@ -369,15 +367,14 @@ int GeoIndexNewPot(GeoIx * gix)
/* GeoString values of real (latitude, longitude) */
/* points */
/* =================================================== */
GeoIndex * GeoIndex_new(void)
{
GeoIndex * GeoIndex_new(void) {
GeoIx * gix;
int i,j;
double lat, lon, x, y, z;
gix = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(GeoIx), false);
if(gix == NULL) {
if (gix == NULL) {
return (GeoIndex *) gix;
}
@ -576,8 +573,7 @@ GeoIndex * GeoIndex_new(void)
/* objects that may have been pointed to by the user's */
/* data pointers are (of course) not freed by this call*/
/* =================================================== */
void GeoIndex_free(GeoIndex * gi)
{
void GeoIndex_free(GeoIndex * gi) {
GeoIx * gix;
if (gi == NULL) {
@ -2275,6 +2271,7 @@ int GeoIndex_INDEXVALID(GeoIndex * gi)
////////////////////////////////////////////////////////////////////////////////
int GeoIndex_assignMethod(void* methodHandle, TRI_index_method_assignment_type_e methodType) {
switch (methodType) {
case TRI_INDEX_METHOD_ASSIGNMENT_FREE : {

View File

@ -102,7 +102,7 @@ int GeoIndex_assignMethod (void*, TRI_index_method_assignment_type_e);
// Allows one or more call back functions to be assigned
///////////////////////////////////////////////////////////////////////////////////////
int GeoIndexIndex_assignMethod (void*, TRI_index_method_assignment_type_e);
int GeoIndex_assignMethod (void*, TRI_index_method_assignment_type_e);
GeoIndex * GeoIndex_new(void);
void GeoIndex_free(GeoIndex * gi);

View File

@ -519,54 +519,51 @@ static TRI_index_operator_t* SetupConditionsBitarrayHelper (TRI_index_t* idx,
// Check the various operator conditions
// ........................................................................
// ........................................................................
// Check for an 'AND' condition. The following are acceptable: '&', '&&' 'and'
// ........................................................................
if (condition->HasOwnProperty(v8::String::New("&"))) {
operatorType = TRI_AND_INDEX_OPERATOR;
value = condition->Get(v8::String::New("&"));
operatorType = TRI_AND_INDEX_OPERATOR;
if (!value->IsArray()) {
// wrong data type for AND condition -- we require [leftOperation,rightOperation]
return 0;
}
}
if (condition->HasOwnProperty(v8::String::New("and"))) {
else if (condition->HasOwnProperty(v8::String::New("&&"))) {
operatorType = TRI_AND_INDEX_OPERATOR;
value = condition->Get(v8::String::New("&&"));
}
else if (condition->HasOwnProperty(v8::String::New("and"))) {
operatorType = TRI_AND_INDEX_OPERATOR;
value = condition->Get(v8::String::New("and"));
operatorType = TRI_AND_INDEX_OPERATOR;
if (!value->IsArray()) {
// wrong data type for AND condition -- we require [leftOperation,rightOperation]
return 0;
}
}
}
// ........................................................................
// Check for an 'OR' condition. The following are acceptable: '|', '||' 'or'
// ........................................................................
else if (condition->HasOwnProperty(v8::String::New("|"))) {
value = condition->Get(v8::String::New("|"));
operatorType = TRI_OR_INDEX_OPERATOR;
if (!value->IsArray()) {
// wrong data type for OR condition -- we require [leftOperation,rightOperation]
return 0;
}
}
else if (condition->HasOwnProperty(v8::String::New("||"))) {
value = condition->Get(v8::String::New("||"));
operatorType = TRI_OR_INDEX_OPERATOR;
}
else if (condition->HasOwnProperty(v8::String::New("or"))) {
value = condition->Get(v8::String::New("or"));
operatorType = TRI_OR_INDEX_OPERATOR;
if (!value->IsArray()) {
// wrong data type for OR condition -- we require [leftOperation,rightOperation]
return 0;
}
}
// ........................................................................
// Check for an 'NOT' condition. The following are acceptable: '!', 'not'
// ........................................................................
else if (condition->HasOwnProperty(v8::String::New("!"))) {
value = condition->Get(v8::String::New("!"));
operatorType = TRI_NOT_INDEX_OPERATOR;
if (!value->IsObject()) {
// wrong data type for NOT condition -- we require {condition...} ]
return 0;
}
}
else if (condition->HasOwnProperty(v8::String::New("not"))) {
value = condition->Get(v8::String::New("!"));
value = condition->Get(v8::String::New("not"));
operatorType = TRI_NOT_INDEX_OPERATOR;
if (!value->IsObject()) {
// wrong data type for NOT condition -- we require {condition...} ]
return 0;
}
}
// ........................................................................
// Check for an 'EQUAL' condition. The following are acceptable: '=', '==', 'eq'
// ........................................................................
else if (condition->HasOwnProperty(v8::String::New("=="))) {
value = condition->Get(v8::String::New("=="));
operatorType = TRI_EQ_INDEX_OPERATOR;
@ -575,33 +572,79 @@ static TRI_index_operator_t* SetupConditionsBitarrayHelper (TRI_index_t* idx,
value = condition->Get(v8::String::New("="));
operatorType = TRI_EQ_INDEX_OPERATOR;
}
else if (condition->HasOwnProperty(v8::String::New("eq"))) {
value = condition->Get(v8::String::New("eq"));
operatorType = TRI_EQ_INDEX_OPERATOR;
}
// ........................................................................
// Check for an 'NOT EQUAL' condition. The following are acceptable: '!=', '<>, 'ne'
// ........................................................................
else if (condition->HasOwnProperty(v8::String::New("!="))) {
value = condition->Get(v8::String::New("!="));
operatorType = TRI_NE_INDEX_OPERATOR;
}
else if (condition->HasOwnProperty(v8::String::New("<>"))) {
value = condition->Get(v8::String::New("<>"));
operatorType = TRI_NE_INDEX_OPERATOR;
}
else if (condition->HasOwnProperty(v8::String::New("ne"))) {
value = condition->Get(v8::String::New("ne"));
operatorType = TRI_NE_INDEX_OPERATOR;
}
// ........................................................................
// Check for an 'LESS THAN OR EQUAL' condition. The following are acceptable: '<=', 'le'
// ........................................................................
else if (condition->HasOwnProperty(v8::String::New("<="))) {
value = condition->Get(v8::String::New("<="));
operatorType = TRI_LE_INDEX_OPERATOR;
}
else if (condition->HasOwnProperty(v8::String::New("le"))) {
value = condition->Get(v8::String::New("le"));
operatorType = TRI_LE_INDEX_OPERATOR;
}
// ........................................................................
// Check for an 'LESS THAN ' condition. The following are acceptable: '<', 'lt'
// ........................................................................
else if (condition->HasOwnProperty(v8::String::New("<"))) {
value = condition->Get(v8::String::New("<"));
operatorType = TRI_LT_INDEX_OPERATOR;
}
else if (condition->HasOwnProperty(v8::String::New("lt"))) {
value = condition->Get(v8::String::New("lt"));
operatorType = TRI_LT_INDEX_OPERATOR;
}
// ........................................................................
// Check for an 'GREATER THAN OR EQUAL' condition. The following are acceptable: '>=', 'ge'
// ........................................................................
else if (condition->HasOwnProperty(v8::String::New(">="))) {
value = condition->Get(v8::String::New(">="));
operatorType = TRI_GE_INDEX_OPERATOR;
}
else if (condition->HasOwnProperty(v8::String::New("ge"))) {
value = condition->Get(v8::String::New("ge"));
operatorType = TRI_GE_INDEX_OPERATOR;
}
// ........................................................................
// Check for an 'GREATER THAN ' condition. The following are acceptable: '>', 'gt'
// ........................................................................
else if (condition->HasOwnProperty(v8::String::New(">"))) {
value = condition->Get(v8::String::New(">"));
operatorType = TRI_GT_INDEX_OPERATOR;
}
else if (condition->HasOwnProperty(v8::String::New("gt"))) {
value = condition->Get(v8::String::New("gt"));
operatorType = TRI_GT_INDEX_OPERATOR;
}
// ........................................................................
// We received an invalid condition. Most likely we are really expressing
// a condition {"x":1} which should be BY_EXAMPLE rather than BY_CONDITION
// ........................................................................
else { // invalid operator index condition
return 0;
}
// ........................................................................
// Since we have a valid condition condition, act upon it
// Since we have a valid condition, act upon it
// may require recursion
// ........................................................................
@ -609,7 +652,41 @@ static TRI_index_operator_t* SetupConditionsBitarrayHelper (TRI_index_t* idx,
case TRI_AND_INDEX_OPERATOR:
case TRI_OR_INDEX_OPERATOR: {
// ....................................................................
// For both the 'AND' and 'OR' index operators, we require an array
// with 2 elements for the value of the condition object. E.g. we
// expect: {"&": [{"x":0},{"x":1}]} <-- this is a special "and" call
// see the ensureBitarray doc for
// more information.
// More common is
// expect: {"or": [{"x":0},{"x":1}]} <-- which means return all docs
// where attribute "x" has the
// value of 0 or 1.
// To have "x" = 0 or "x" = 1 or "x" = 2 we expect:
// {"or":[{"x":0},{"or":[{"x":1},{"x":2}]}]} or any valid iteration
// of this. TODO: shortcut this with the "list" index operator
// ....................................................................
// ....................................................................
// wrong data type for this condition -- we require [leftOperation,rightOperation]
// ....................................................................
if (!value->IsArray()) {
return 0;
}
v8::Handle<v8::Array> andValues = v8::Handle<v8::Array>::Cast(value);
// ....................................................................
// Check the length of the array to ensure that it is exactly 2
// ....................................................................
if (andValues->Length() != 2) {
return 0;
}
v8::Handle<v8::Value> leftValue = andValues->Get(0);
v8::Handle<v8::Value> rightValue = andValues->Get(1);
@ -620,6 +697,11 @@ static TRI_index_operator_t* SetupConditionsBitarrayHelper (TRI_index_t* idx,
v8::Handle<v8::Object> leftObject = v8::Handle<v8::Object>::Cast(leftValue);
v8::Handle<v8::Object> rightObject = v8::Handle<v8::Object>::Cast(rightValue);
// ....................................................................
// recurse the left and right operators
// ....................................................................
TRI_index_operator_t* leftOp = SetupConditionsBitarrayHelper(idx, shaper, leftObject);
TRI_index_operator_t* rightOp = SetupConditionsBitarrayHelper(idx, shaper, rightObject);
@ -634,7 +716,22 @@ static TRI_index_operator_t* SetupConditionsBitarrayHelper (TRI_index_t* idx,
}
case TRI_NOT_INDEX_OPERATOR: {
// ....................................................................
// wrong data type for this condition -- we require {...} which becomes
// the left object for not operator.
// ....................................................................
if (!value->IsObject()) {
return 0;
}
v8::Handle<v8::Object> leftObject = v8::Handle<v8::Object>::Cast(value);
// ....................................................................
// recurse the left and only operator
// ....................................................................
TRI_index_operator_t* leftOp = SetupConditionsBitarrayHelper(idx, shaper, leftObject);
if (leftOp == 0) {
@ -651,6 +748,7 @@ static TRI_index_operator_t* SetupConditionsBitarrayHelper (TRI_index_t* idx,
case TRI_LT_INDEX_OPERATOR:
case TRI_GE_INDEX_OPERATOR:
case TRI_GT_INDEX_OPERATOR: {
v8::Handle<v8::Object> leftObject = v8::Handle<v8::Object>::Cast(value);
TRI_json_t* parameters = SetupBitarrayAttributeValuesHelper(idx, leftObject);
@ -667,7 +765,7 @@ static TRI_index_operator_t* SetupConditionsBitarrayHelper (TRI_index_t* idx,
}
} // end of switch (operatorType)
return indexOperator;
}
@ -1166,6 +1264,7 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
else {
LOG_WARNING("index iterator returned with a NULL value in ExecuteBitarrayQuery");
// return an empty list
}
collection->_collection->endRead(collection->_collection);

View File

@ -1338,6 +1338,7 @@ static v8::Handle<v8::Value> ExecuteQueryNativeAhuacatl (TRI_aql_context_t* cons
// bind values
// optimise
// lock
if (!TRI_ValidateQueryContextAql(context) ||
!TRI_BindQueryContextAql(context, parameters) ||
!TRI_LockQueryContextAql(context) ||
@ -2088,7 +2089,6 @@ static v8::Handle<v8::Value> JS_RunAhuacatl (v8::Arguments const& argv) {
}
const string queryString = TRI_ObjectToString(queryArg);
// return number of total records in cursor?
bool doCount = false;
// maximum number of results to return at once
@ -2781,7 +2781,7 @@ static v8::Handle<v8::Value> EnsureBitarray (v8::Arguments const& argv, bool sup
if ( (argv.Length() < 2) || (argv.Length() % 2 != 0) ) {
LOG_WARNING("bitarray index creation failed -- invalid parameters (require key_1,values_1,...,key_n,values_n)");
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, "usage: ensureBitarray(<path>, <list of values>, ...)")));
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, "usage: ensureBitarray(path 1, <list of values 1>, <path 2>, <list of values 2>, ...)")));
}

75
arangod/VocBase/index.c Normal file → Executable file
View File

@ -1017,7 +1017,8 @@ TRI_index_t* TRI_CreateGeo1Index (struct TRI_doc_collection_s* collection,
bool ignoreNull) {
TRI_geo_index_t* geo;
char* ln;
int result;
geo = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_geo_index_t), false);
if (geo == NULL) {
@ -1047,13 +1048,32 @@ TRI_index_t* TRI_CreateGeo1Index (struct TRI_doc_collection_s* collection,
geo->_constraint = constraint;
geo->_geoIndex = GeoIndex_new();
if (geo->_geoIndex == NULL) { // oops out of memory?
LOG_WARNING("geo index creation failed -- internal error when creating new goe index structure");
TRI_DestroyVectorString(&geo->base._fields);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, geo);
return NULL;
}
geo->_variant = geoJson ? INDEX_GEO_COMBINED_LAT_LON : INDEX_GEO_COMBINED_LON_LAT;
geo->_location = location;
geo->_latitude = 0;
geo->_longitude = 0;
geo->_geoJson = geoJson;
result = GeoIndex_assignMethod(&(geo->base.indexQuery), TRI_INDEX_METHOD_ASSIGNMENT_QUERY);
result = result || GeoIndex_assignMethod(&(geo->base.indexQueryFree), TRI_INDEX_METHOD_ASSIGNMENT_FREE);
result = result || GeoIndex_assignMethod(&(geo->base.indexQueryResult), TRI_INDEX_METHOD_ASSIGNMENT_RESULT);
if (result != TRI_ERROR_NO_ERROR) {
TRI_DestroyVectorString(&geo->base._fields);
GeoIndex_free(geo->_geoIndex);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, geo);
LOG_WARNING("geo index creation failed -- internal error when assigning function calls");
return NULL;
}
return &geo->base;
}
@ -1071,7 +1091,8 @@ TRI_index_t* TRI_CreateGeo2Index (struct TRI_doc_collection_s* collection,
TRI_geo_index_t* geo;
char* lat;
char* lon;
int result;
geo = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_geo_index_t), false);
if (geo == NULL) {
@ -1103,11 +1124,30 @@ TRI_index_t* TRI_CreateGeo2Index (struct TRI_doc_collection_s* collection,
geo->_constraint = constraint;
geo->_geoIndex = GeoIndex_new();
if (geo->_geoIndex == NULL) { // oops out of memory?
LOG_WARNING("geo index creation failed -- internal error when creating new goe index structure");
TRI_DestroyVectorString(&geo->base._fields);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, geo);
return NULL;
}
geo->_variant = INDEX_GEO_INDIVIDUAL_LAT_LON;
geo->_location = 0;
geo->_latitude = latitude;
geo->_longitude = longitude;
result = GeoIndex_assignMethod(&(geo->base.indexQuery), TRI_INDEX_METHOD_ASSIGNMENT_QUERY);
result = result || GeoIndex_assignMethod(&(geo->base.indexQueryFree), TRI_INDEX_METHOD_ASSIGNMENT_FREE);
result = result || GeoIndex_assignMethod(&(geo->base.indexQueryResult), TRI_INDEX_METHOD_ASSIGNMENT_RESULT);
if (result != TRI_ERROR_NO_ERROR) {
TRI_DestroyVectorString(&geo->base._fields);
GeoIndex_free(geo->_geoIndex);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, geo);
LOG_WARNING("geo index creation failed -- internal error when assigning function calls");
return NULL;
}
return &geo->base;
}
@ -1732,7 +1772,7 @@ TRI_index_t* TRI_CreateHashIndex (struct TRI_doc_collection_s* collection,
hashIndex->_hashIndex = MultiHashIndex_new();
}
if (hashIndex->_hashIndex == NULL) {
if (hashIndex->_hashIndex == NULL) { // oops out of memory?
TRI_DestroyVector(&hashIndex->_paths);
TRI_DestroyVectorString(&hashIndex->base._fields);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, hashIndex);
@ -1750,7 +1790,8 @@ TRI_index_t* TRI_CreateHashIndex (struct TRI_doc_collection_s* collection,
if (result != TRI_ERROR_NO_ERROR) {
TRI_DestroyVector(&hashIndex->_paths);
TRI_DestroyVectorString(&hashIndex->base._fields);
TRI_FreeBitarrayIndex(&hashIndex->base);
HashIndex_free(hashIndex->_hashIndex);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, hashIndex);
LOG_WARNING("hash index creation failed -- internal error when assigning function calls");
return NULL;
}
@ -3484,6 +3525,15 @@ TRI_index_t* TRI_CreateSkiplistIndex (struct TRI_doc_collection_s* collection,
skiplistIndex->_skiplistIndex = MultiSkiplistIndex_new();
}
if (skiplistIndex->_skiplistIndex == NULL) {
TRI_DestroyVector(&skiplistIndex->_paths);
TRI_DestroyVectorString(&skiplistIndex->base._fields);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, skiplistIndex);
LOG_WARNING("skiplist index creation failed -- internal error when creating skiplist structure");
return NULL;
}
// ...........................................................................
// Assign the function calls used by the query engine
// ...........................................................................
@ -3495,7 +3545,8 @@ TRI_index_t* TRI_CreateSkiplistIndex (struct TRI_doc_collection_s* collection,
if (result != TRI_ERROR_NO_ERROR) {
TRI_DestroyVector(&skiplistIndex->_paths);
TRI_DestroyVectorString(&skiplistIndex->base._fields);
TRI_FreeBitarrayIndex(&skiplistIndex->base);
SkiplistIndex_free(skiplistIndex->_skiplistIndex);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, skiplistIndex);
LOG_WARNING("skiplist index creation failed -- internal error when assigning function calls");
return NULL;
}
@ -4384,7 +4435,6 @@ TRI_index_t* TRI_CreateBitarrayIndex (struct TRI_doc_collection_s* collection,
createContext = NULL;
// ...........................................................................
// Check that the attributes have not been repeated
// ...........................................................................
@ -4403,7 +4453,7 @@ TRI_index_t* TRI_CreateBitarrayIndex (struct TRI_doc_collection_s* collection,
if (value == NULL) {
TRI_DestroyVector(&baIndex->_paths);
TRI_DestroyVector(&baIndex->_values);
TRI_FreeBitarrayIndex(&baIndex->base);
TRI_Free(TRI_UNKNOWN_MEM_ZONE,baIndex);
LOG_WARNING("bitarray index creation failed -- list of values for index undefined");
return NULL;
}
@ -4428,7 +4478,7 @@ TRI_index_t* TRI_CreateBitarrayIndex (struct TRI_doc_collection_s* collection,
if (cardinality > 64) {
TRI_DestroyVector(&baIndex->_paths);
TRI_DestroyVector(&baIndex->_values);
TRI_FreeBitarrayIndex(&baIndex->base);
TRI_Free(TRI_UNKNOWN_MEM_ZONE,baIndex);
LOG_WARNING("bitarray index creation failed -- more than 64 possible values");
return NULL;
}
@ -4437,7 +4487,7 @@ TRI_index_t* TRI_CreateBitarrayIndex (struct TRI_doc_collection_s* collection,
if (cardinality < 1 ) {
TRI_DestroyVector(&baIndex->_paths);
TRI_DestroyVector(&baIndex->_values);
TRI_FreeBitarrayIndex(&baIndex->base);
TRI_Free(TRI_UNKNOWN_MEM_ZONE,baIndex);
LOG_WARNING("bitarray index creation failed -- no index values defined");
return NULL;
}
@ -4455,7 +4505,7 @@ TRI_index_t* TRI_CreateBitarrayIndex (struct TRI_doc_collection_s* collection,
if (result != TRI_ERROR_NO_ERROR) {
TRI_DestroyVector(&baIndex->_paths);
TRI_DestroyVector(&baIndex->_values);
TRI_FreeBitarrayIndex(&baIndex->base);
TRI_Free(TRI_UNKNOWN_MEM_ZONE,baIndex);
LOG_WARNING("bitarray index creation failed -- internal error when assigning function calls");
return NULL;
}
@ -4471,6 +4521,7 @@ TRI_index_t* TRI_CreateBitarrayIndex (struct TRI_doc_collection_s* collection,
TRI_DestroyVector(&baIndex->_paths);
TRI_DestroyVector(&baIndex->_values);
TRI_FreeBitarrayIndex(&baIndex->base);
TRI_Free(TRI_UNKNOWN_MEM_ZONE,baIndex);
LOG_WARNING("bitarray index creation failed -- your guess as good as mine");
return NULL;
}

26
js/client/client.js Normal file → Executable file
View File

@ -1356,6 +1356,32 @@ function ArangoCollection (database, data) {
return true;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief adds a bitarray index
////////////////////////////////////////////////////////////////////////////////
ArangoCollection.prototype.ensureBitarray = function () {
var i;
var body;
var fields = [];
for (i = 0; i < arguments.length; ++i) {
fields.push(arguments[i]);
}
body = { type : "bitarray", unique : false, fields : fields };
var requestResult = this._database._connection.POST(
"/_api/index?collection=" + encodeURIComponent(this._id),
JSON.stringify(body));
client.checkRequestResult(requestResult);
return requestResult;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief adds a cap constraint
////////////////////////////////////////////////////////////////////////////////

View File

@ -1357,6 +1357,32 @@ static string JS_client_client =
" return true;\n"
" };\n"
"\n"
" \n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief adds a bitarray index\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
" ArangoCollection.prototype.ensureBitarray = function () {\n"
" var i;\n"
" var body;\n"
" var fields = [];\n"
"\n"
" for (i = 0; i < arguments.length; ++i) {\n"
" fields.push(arguments[i]);\n"
" }\n"
"\n"
" body = { type : \"bitarray\", unique : false, fields : fields };\n"
"\n"
" var requestResult = this._database._connection.POST(\n"
" \"/_api/index?collection=\" + encodeURIComponent(this._id),\n"
" JSON.stringify(body));\n"
"\n"
" client.checkRequestResult(requestResult);\n"
"\n"
" return requestResult;\n"
" };\n"
"\n"
" \n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief adds a cap constraint\n"
"////////////////////////////////////////////////////////////////////////////////\n"

34
js/server/ahuacatl.js Normal file → Executable file
View File

@ -455,6 +455,40 @@ function AHUACATL_GET_DOCUMENTS_HASH_LIST (collection, idx, attribute, values) {
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get documents from the specified collection using a bitarray
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_GET_DOCUMENTS_BITARRAY (collection, idx, example) {
return internal.db[collection].BY_CONDITION_BITARRAY(idx, example).documents;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get documents from the specified collection using a bitarray
/// (multiple index values) TODO: replace by 'IN index operator'
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_GET_DOCUMENTS_BITARRAY_LIST (collection, idx, attribute, values) {
var result = [ ];
for (var i in values) {
var value = values[i];
var example = { };
example[attribute] = value;
var documents = internal.db[collection].BY_EXAMPLE_BITARRAY(idx, example).documents;
for (var j in documents) {
result.push(documents[j]);
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get documents from the specified collection using a skiplist
////////////////////////////////////////////////////////////////////////////////

View File

@ -457,6 +457,40 @@ static string JS_server_ahuacatl =
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief get documents from the specified collection using a bitarray\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_GET_DOCUMENTS_BITARRAY (collection, idx, example) {\n"
" return internal.db[collection].BY_CONDITION_BITARRAY(idx, example).documents;\n"
"}\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief get documents from the specified collection using a bitarray\n"
"/// (multiple index values) TODO: replace by 'IN index operator'\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"function AHUACATL_GET_DOCUMENTS_BITARRAY_LIST (collection, idx, attribute, values) {\n"
" var result = [ ];\n"
"\n"
" for (var i in values) {\n"
" var value = values[i];\n"
" var example = { };\n"
"\n"
" example[attribute] = value;\n"
"\n"
" var documents = internal.db[collection].BY_EXAMPLE_BITARRAY(idx, example).documents;\n"
" for (var j in documents) {\n"
" result.push(documents[j]);\n"
" }\n"
" }\n"
"\n"
" return result;\n"
"}\n"
"\n"
"\n"
"\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief get documents from the specified collection using a skiplist\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"