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, " })"); 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) /// @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_GEO2_INDEX:
case TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX: case TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX:
case TRI_IDX_TYPE_CAP_CONSTRAINT: case TRI_IDX_TYPE_CAP_CONSTRAINT:
case TRI_IDX_TYPE_BITARRAY_INDEX:
// these index types are not yet supported // these index types are not yet supported
generator->_errorCode = TRI_ERROR_INTERNAL; generator->_errorCode = TRI_ERROR_INTERNAL;
break; break;
@ -1303,6 +1384,11 @@ static void ProcessCollectionHinted (TRI_aql_codegen_js_t* const generator,
case TRI_IDX_TYPE_SKIPLIST_INDEX: case TRI_IDX_TYPE_SKIPLIST_INDEX:
GenerateSkiplistAccess(generator, hint->_index, hint->_collection, collectionName); GenerateSkiplistAccess(generator, hint->_index, hint->_collection, collectionName);
break; 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) { bool TRI_OptimiseQueryContextAql (TRI_aql_context_t* const context) {
// do some basic optimisations in the AST // do some basic optimisations in the AST
if (!TRI_OptimiseAql(context)) { if (!TRI_OptimiseAql(context)) {
// constant folding failed // 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, TRI_aql_index_t* pickedIndex,
const TRI_index_t* const idx, const TRI_index_t* const idx,
TRI_vector_pointer_t* fieldAccesses) { TRI_vector_pointer_t* fieldAccesses) {
bool isBetter; bool isBetter = false;
assert(idx); assert(idx);
assert(fieldAccesses); assert(fieldAccesses);
if (pickedIndex == NULL) { if (pickedIndex == NULL) {
pickedIndex = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_index_t), false); pickedIndex = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_index_t), false);
pickedIndex->_idx = NULL; pickedIndex->_idx = NULL;
@ -121,21 +121,98 @@ static TRI_aql_index_t* PickIndex (TRI_aql_context_t* const context,
return NULL; 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) { 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; 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 if ( (isBetter == false) && (idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) &&
(idx->_unique && !pickedIndex->_idx->_unique) || // unique indexes are better than non-unique ones (pickedIndex->_idx->_type != TRI_IDX_TYPE_HASH_INDEX) ) {
(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 the index type is a skiplist index, use this -- but only if we have NOT
// located something better BEFORE.
// 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); 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 (isBetter) {
if (pickedIndex->_fieldAccesses != NULL) { if (pickedIndex->_fieldAccesses != NULL) {
TRI_FreeVectorPointer(TRI_UNKNOWN_MEM_ZONE, pickedIndex->_fieldAccesses); 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(context);
assert(collectionName); assert(collectionName);
assert(candidates); assert(candidates);
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];
@ -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_GEO2_INDEX:
case TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX: case TRI_IDX_TYPE_PRIORITY_QUEUE_INDEX:
case TRI_IDX_TYPE_CAP_CONSTRAINT: case TRI_IDX_TYPE_CAP_CONSTRAINT:
case TRI_IDX_TYPE_BITARRAY_INDEX:
// ignore all these index types for now // ignore all these index types for now
continue; continue;
case TRI_IDX_TYPE_PRIMARY_INDEX: case TRI_IDX_TYPE_PRIMARY_INDEX:
case TRI_IDX_TYPE_HASH_INDEX: case TRI_IDX_TYPE_HASH_INDEX:
case TRI_IDX_TYPE_SKIPLIST_INDEX: case TRI_IDX_TYPE_SKIPLIST_INDEX:
case TRI_IDX_TYPE_BITARRAY_INDEX:
// these indexes are valid candidates // these indexes are valid candidates
break; break;
} }
@ -239,6 +316,7 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context,
for (k = 0; k < candidates->_length; ++k) { for (k = 0; k < candidates->_length; ++k) {
TRI_aql_field_access_t* candidate = (TRI_aql_field_access_t*) TRI_AtVectorPointer(candidates, k); TRI_aql_field_access_t* candidate = (TRI_aql_field_access_t*) TRI_AtVectorPointer(candidates, k);
if (candidate->_type == TRI_AQL_ACCESS_IMPOSSIBLE || if (candidate->_type == TRI_AQL_ACCESS_IMPOSSIBLE ||
candidate->_type == TRI_AQL_ACCESS_ALL) { candidate->_type == TRI_AQL_ACCESS_ALL) {
// wrong index type, doesn't help us at 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); TRI_PushBackVectorPointer(&matches, candidate);
} }
else if (idx->_type == TRI_IDX_TYPE_HASH_INDEX) { else if (idx->_type == TRI_IDX_TYPE_HASH_INDEX) {
if (!IsExactCandidate(candidate)) { if (!IsExactCandidate(candidate)) {
// wrong access type for hash index // 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); 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) { else if (idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) {
bool candidateIsExact; 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); collectionName = TRI_AQL_NODE_STRING(nameNode);
assert(collectionName); assert(collectionName);
hint = (TRI_aql_collection_hint_t*) TRI_AQL_NODE_DATA(node); hint = (TRI_aql_collection_hint_t*) TRI_AQL_NODE_DATA(node);
if (hint == NULL) { if (hint == NULL) {
@ -93,7 +93,7 @@ static void AttachCollectionHint (TRI_aql_context_t* const context,
return; return;
} }
if (hint->_ranges == NULL) { if (hint->_ranges == NULL) {
// no ranges found to be used as indexes // 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 */ /* "points" lists the slotid of the points. This is */
/* only used for a leaf pot. */ /* only used for a leaf pot. */
/* =================================================== */ /* =================================================== */
typedef struct typedef struct {
{ int LorLeaf;
int LorLeaf; int RorPoints;
int RorPoints; GeoString middle;
GeoString middle; GeoFix maxdist[GeoIndexFIXEDPOINTS];
GeoFix maxdist[GeoIndexFIXEDPOINTS]; GeoString start;
GeoString start; GeoString end;
GeoString end; int level;
int level; int points[GeoIndexPOTSIZE];
int points[GeoIndexPOTSIZE]; } GeoPot;
} GeoPot;
/* =================================================== */ /* =================================================== */
/* GeoIx structure */ /* GeoIx structure */
/* This is the REAL GeoIndex structure - the one in */ /* 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 */ /* There is no provision at present for the index to */
/* get smaller when the majority of points are deleted */ /* get smaller when the majority of points are deleted */
/* =================================================== */ /* =================================================== */
typedef struct typedef struct {
{ GeoIndexFixed fixed; /* fixed point data */
GeoIndexFixed fixed; /* fixed point data */ int potct; /* pots allocated */
int potct; /* pots allocated */ int slotct; /* slots allocated */
int slotct; /* slots allocated */ GeoPot * pots; /* the pots themselves */
GeoPot * pots; /* the pots themselves */ GeoCoordinate * gc; /* the slots themselves */
GeoCoordinate * gc; /* the slots themselves */ } GeoIx;
} GeoIx;
/* =================================================== */ /* =================================================== */
/* GeoDetailedPoint structure */ /* GeoDetailedPoint structure */
/* The routine GeoMkDetail is given a point - really */ /* The routine GeoMkDetail is given a point - really */
@ -369,15 +367,14 @@ int GeoIndexNewPot(GeoIx * gix)
/* GeoString values of real (latitude, longitude) */ /* GeoString values of real (latitude, longitude) */
/* points */ /* points */
/* =================================================== */ /* =================================================== */
GeoIndex * GeoIndex_new(void) GeoIndex * GeoIndex_new(void) {
{
GeoIx * gix; GeoIx * gix;
int i,j; int i,j;
double lat, lon, x, y, z; double lat, lon, x, y, z;
gix = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(GeoIx), false); gix = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(GeoIx), false);
if(gix == NULL) { if (gix == NULL) {
return (GeoIndex *) gix; return (GeoIndex *) gix;
} }
@ -576,8 +573,7 @@ GeoIndex * GeoIndex_new(void)
/* objects that may have been pointed to by the user's */ /* objects that may have been pointed to by the user's */
/* data pointers are (of course) not freed by this call*/ /* data pointers are (of course) not freed by this call*/
/* =================================================== */ /* =================================================== */
void GeoIndex_free(GeoIndex * gi) void GeoIndex_free(GeoIndex * gi) {
{
GeoIx * gix; GeoIx * gix;
if (gi == NULL) { if (gi == NULL) {
@ -2275,6 +2271,7 @@ int GeoIndex_INDEXVALID(GeoIndex * gi)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int GeoIndex_assignMethod(void* methodHandle, TRI_index_method_assignment_type_e methodType) { int GeoIndex_assignMethod(void* methodHandle, TRI_index_method_assignment_type_e methodType) {
switch (methodType) { switch (methodType) {
case TRI_INDEX_METHOD_ASSIGNMENT_FREE : { 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 // 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); GeoIndex * GeoIndex_new(void);
void GeoIndex_free(GeoIndex * gi); 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 the various operator conditions
// ........................................................................ // ........................................................................
// ........................................................................
// Check for an 'AND' condition. The following are acceptable: '&', '&&' 'and'
// ........................................................................
if (condition->HasOwnProperty(v8::String::New("&"))) { if (condition->HasOwnProperty(v8::String::New("&"))) {
operatorType = TRI_AND_INDEX_OPERATOR;
value = condition->Get(v8::String::New("&")); 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")); 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] // Check for an 'OR' condition. The following are acceptable: '|', '||' 'or'
return 0; // ........................................................................
}
}
else if (condition->HasOwnProperty(v8::String::New("|"))) { else if (condition->HasOwnProperty(v8::String::New("|"))) {
value = condition->Get(v8::String::New("|")); value = condition->Get(v8::String::New("|"));
operatorType = TRI_OR_INDEX_OPERATOR; operatorType = TRI_OR_INDEX_OPERATOR;
if (!value->IsArray()) { }
// wrong data type for OR condition -- we require [leftOperation,rightOperation] else if (condition->HasOwnProperty(v8::String::New("||"))) {
return 0; value = condition->Get(v8::String::New("||"));
} operatorType = TRI_OR_INDEX_OPERATOR;
} }
else if (condition->HasOwnProperty(v8::String::New("or"))) { else if (condition->HasOwnProperty(v8::String::New("or"))) {
value = condition->Get(v8::String::New("or")); value = condition->Get(v8::String::New("or"));
operatorType = TRI_OR_INDEX_OPERATOR; 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("!"))) { else if (condition->HasOwnProperty(v8::String::New("!"))) {
value = condition->Get(v8::String::New("!")); value = condition->Get(v8::String::New("!"));
operatorType = TRI_NOT_INDEX_OPERATOR; 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"))) { 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; 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("=="))) { else if (condition->HasOwnProperty(v8::String::New("=="))) {
value = condition->Get(v8::String::New("==")); value = condition->Get(v8::String::New("=="));
operatorType = TRI_EQ_INDEX_OPERATOR; 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("=")); value = condition->Get(v8::String::New("="));
operatorType = TRI_EQ_INDEX_OPERATOR; 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("!="))) { else if (condition->HasOwnProperty(v8::String::New("!="))) {
value = condition->Get(v8::String::New("!=")); value = condition->Get(v8::String::New("!="));
operatorType = TRI_NE_INDEX_OPERATOR; 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("<="))) { else if (condition->HasOwnProperty(v8::String::New("<="))) {
value = condition->Get(v8::String::New("<=")); value = condition->Get(v8::String::New("<="));
operatorType = TRI_LE_INDEX_OPERATOR; 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("<"))) { else if (condition->HasOwnProperty(v8::String::New("<"))) {
value = condition->Get(v8::String::New("<")); value = condition->Get(v8::String::New("<"));
operatorType = TRI_LT_INDEX_OPERATOR; 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(">="))) { else if (condition->HasOwnProperty(v8::String::New(">="))) {
value = condition->Get(v8::String::New(">=")); value = condition->Get(v8::String::New(">="));
operatorType = TRI_GE_INDEX_OPERATOR; 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(">"))) { else if (condition->HasOwnProperty(v8::String::New(">"))) {
value = condition->Get(v8::String::New(">")); value = condition->Get(v8::String::New(">"));
operatorType = TRI_GT_INDEX_OPERATOR; 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 else { // invalid operator index condition
return 0; return 0;
} }
// ........................................................................ // ........................................................................
// Since we have a valid condition condition, act upon it // Since we have a valid condition, act upon it
// may require recursion // may require recursion
// ........................................................................ // ........................................................................
@ -609,7 +652,41 @@ static TRI_index_operator_t* SetupConditionsBitarrayHelper (TRI_index_t* idx,
case TRI_AND_INDEX_OPERATOR: case TRI_AND_INDEX_OPERATOR:
case TRI_OR_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); 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> leftValue = andValues->Get(0);
v8::Handle<v8::Value> rightValue = andValues->Get(1); 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> leftObject = v8::Handle<v8::Object>::Cast(leftValue);
v8::Handle<v8::Object> rightObject = v8::Handle<v8::Object>::Cast(rightValue); 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* leftOp = SetupConditionsBitarrayHelper(idx, shaper, leftObject);
TRI_index_operator_t* rightOp = SetupConditionsBitarrayHelper(idx, shaper, rightObject); 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: { 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); 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); TRI_index_operator_t* leftOp = SetupConditionsBitarrayHelper(idx, shaper, leftObject);
if (leftOp == 0) { if (leftOp == 0) {
@ -651,6 +748,7 @@ static TRI_index_operator_t* SetupConditionsBitarrayHelper (TRI_index_t* idx,
case TRI_LT_INDEX_OPERATOR: case TRI_LT_INDEX_OPERATOR:
case TRI_GE_INDEX_OPERATOR: case TRI_GE_INDEX_OPERATOR:
case TRI_GT_INDEX_OPERATOR: { case TRI_GT_INDEX_OPERATOR: {
v8::Handle<v8::Object> leftObject = v8::Handle<v8::Object>::Cast(value); v8::Handle<v8::Object> leftObject = v8::Handle<v8::Object>::Cast(value);
TRI_json_t* parameters = SetupBitarrayAttributeValuesHelper(idx, leftObject); 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) } // end of switch (operatorType)
return indexOperator; return indexOperator;
} }
@ -1166,6 +1264,7 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv, st
else { else {
LOG_WARNING("index iterator returned with a NULL value in ExecuteBitarrayQuery"); LOG_WARNING("index iterator returned with a NULL value in ExecuteBitarrayQuery");
// return an empty list
} }
collection->_collection->endRead(collection->_collection); collection->_collection->endRead(collection->_collection);

View File

@ -1338,6 +1338,7 @@ static v8::Handle<v8::Value> ExecuteQueryNativeAhuacatl (TRI_aql_context_t* cons
// bind values // bind values
// optimise // optimise
// lock // lock
if (!TRI_ValidateQueryContextAql(context) || if (!TRI_ValidateQueryContextAql(context) ||
!TRI_BindQueryContextAql(context, parameters) || !TRI_BindQueryContextAql(context, parameters) ||
!TRI_LockQueryContextAql(context) || !TRI_LockQueryContextAql(context) ||
@ -2088,7 +2089,6 @@ static v8::Handle<v8::Value> JS_RunAhuacatl (v8::Arguments const& argv) {
} }
const string queryString = TRI_ObjectToString(queryArg); const string queryString = TRI_ObjectToString(queryArg);
// return number of total records in cursor? // return number of total records in cursor?
bool doCount = false; bool doCount = false;
// maximum number of results to return at once // 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) ) { 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)"); LOG_WARNING("bitarray index creation failed -- invalid parameters (require key_1,values_1,...,key_n,values_n)");
TRI_ReleaseCollection(collection); 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) { bool ignoreNull) {
TRI_geo_index_t* geo; TRI_geo_index_t* geo;
char* ln; char* ln;
int result;
geo = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_geo_index_t), false); geo = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_geo_index_t), false);
if (geo == NULL) { if (geo == NULL) {
@ -1047,13 +1048,32 @@ TRI_index_t* TRI_CreateGeo1Index (struct TRI_doc_collection_s* collection,
geo->_constraint = constraint; geo->_constraint = constraint;
geo->_geoIndex = GeoIndex_new(); 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->_variant = geoJson ? INDEX_GEO_COMBINED_LAT_LON : INDEX_GEO_COMBINED_LON_LAT;
geo->_location = location; geo->_location = location;
geo->_latitude = 0; geo->_latitude = 0;
geo->_longitude = 0; geo->_longitude = 0;
geo->_geoJson = geoJson; 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; return &geo->base;
} }
@ -1071,7 +1091,8 @@ TRI_index_t* TRI_CreateGeo2Index (struct TRI_doc_collection_s* collection,
TRI_geo_index_t* geo; TRI_geo_index_t* geo;
char* lat; char* lat;
char* lon; char* lon;
int result;
geo = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_geo_index_t), false); geo = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_geo_index_t), false);
if (geo == NULL) { if (geo == NULL) {
@ -1103,11 +1124,30 @@ TRI_index_t* TRI_CreateGeo2Index (struct TRI_doc_collection_s* collection,
geo->_constraint = constraint; geo->_constraint = constraint;
geo->_geoIndex = GeoIndex_new(); 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->_variant = INDEX_GEO_INDIVIDUAL_LAT_LON;
geo->_location = 0; geo->_location = 0;
geo->_latitude = latitude; geo->_latitude = latitude;
geo->_longitude = longitude; 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; return &geo->base;
} }
@ -1732,7 +1772,7 @@ TRI_index_t* TRI_CreateHashIndex (struct TRI_doc_collection_s* collection,
hashIndex->_hashIndex = MultiHashIndex_new(); hashIndex->_hashIndex = MultiHashIndex_new();
} }
if (hashIndex->_hashIndex == NULL) { if (hashIndex->_hashIndex == NULL) { // oops out of memory?
TRI_DestroyVector(&hashIndex->_paths); TRI_DestroyVector(&hashIndex->_paths);
TRI_DestroyVectorString(&hashIndex->base._fields); TRI_DestroyVectorString(&hashIndex->base._fields);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, hashIndex); 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) { if (result != TRI_ERROR_NO_ERROR) {
TRI_DestroyVector(&hashIndex->_paths); TRI_DestroyVector(&hashIndex->_paths);
TRI_DestroyVectorString(&hashIndex->base._fields); 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"); LOG_WARNING("hash index creation failed -- internal error when assigning function calls");
return NULL; return NULL;
} }
@ -3484,6 +3525,15 @@ TRI_index_t* TRI_CreateSkiplistIndex (struct TRI_doc_collection_s* collection,
skiplistIndex->_skiplistIndex = MultiSkiplistIndex_new(); 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 // 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) { if (result != TRI_ERROR_NO_ERROR) {
TRI_DestroyVector(&skiplistIndex->_paths); TRI_DestroyVector(&skiplistIndex->_paths);
TRI_DestroyVectorString(&skiplistIndex->base._fields); 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"); LOG_WARNING("skiplist index creation failed -- internal error when assigning function calls");
return NULL; return NULL;
} }
@ -4384,7 +4435,6 @@ TRI_index_t* TRI_CreateBitarrayIndex (struct TRI_doc_collection_s* collection,
createContext = NULL; createContext = NULL;
// ........................................................................... // ...........................................................................
// Check that the attributes have not been repeated // 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) { if (value == NULL) {
TRI_DestroyVector(&baIndex->_paths); TRI_DestroyVector(&baIndex->_paths);
TRI_DestroyVector(&baIndex->_values); 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"); LOG_WARNING("bitarray index creation failed -- list of values for index undefined");
return NULL; return NULL;
} }
@ -4428,7 +4478,7 @@ TRI_index_t* TRI_CreateBitarrayIndex (struct TRI_doc_collection_s* collection,
if (cardinality > 64) { if (cardinality > 64) {
TRI_DestroyVector(&baIndex->_paths); TRI_DestroyVector(&baIndex->_paths);
TRI_DestroyVector(&baIndex->_values); 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"); LOG_WARNING("bitarray index creation failed -- more than 64 possible values");
return NULL; return NULL;
} }
@ -4437,7 +4487,7 @@ TRI_index_t* TRI_CreateBitarrayIndex (struct TRI_doc_collection_s* collection,
if (cardinality < 1 ) { if (cardinality < 1 ) {
TRI_DestroyVector(&baIndex->_paths); TRI_DestroyVector(&baIndex->_paths);
TRI_DestroyVector(&baIndex->_values); 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"); LOG_WARNING("bitarray index creation failed -- no index values defined");
return NULL; return NULL;
} }
@ -4455,7 +4505,7 @@ TRI_index_t* TRI_CreateBitarrayIndex (struct TRI_doc_collection_s* collection,
if (result != TRI_ERROR_NO_ERROR) { if (result != TRI_ERROR_NO_ERROR) {
TRI_DestroyVector(&baIndex->_paths); TRI_DestroyVector(&baIndex->_paths);
TRI_DestroyVector(&baIndex->_values); 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"); LOG_WARNING("bitarray index creation failed -- internal error when assigning function calls");
return NULL; return NULL;
} }
@ -4471,6 +4521,7 @@ TRI_index_t* TRI_CreateBitarrayIndex (struct TRI_doc_collection_s* collection,
TRI_DestroyVector(&baIndex->_paths); TRI_DestroyVector(&baIndex->_paths);
TRI_DestroyVector(&baIndex->_values); TRI_DestroyVector(&baIndex->_values);
TRI_FreeBitarrayIndex(&baIndex->base); TRI_FreeBitarrayIndex(&baIndex->base);
TRI_Free(TRI_UNKNOWN_MEM_ZONE,baIndex);
LOG_WARNING("bitarray index creation failed -- your guess as good as mine"); LOG_WARNING("bitarray index creation failed -- your guess as good as mine");
return NULL; return NULL;
} }

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

@ -1356,6 +1356,32 @@ function ArangoCollection (database, data) {
return true; 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 /// @brief adds a cap constraint
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -1357,6 +1357,32 @@ static string JS_client_client =
" return true;\n" " return true;\n"
" };\n" " };\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" "////////////////////////////////////////////////////////////////////////////////\n"
"/// @brief adds a cap constraint\n" "/// @brief adds a cap constraint\n"
"////////////////////////////////////////////////////////////////////////////////\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; 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 /// @brief get documents from the specified collection using a skiplist
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -457,6 +457,40 @@ static string JS_server_ahuacatl =
"}\n" "}\n"
"\n" "\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" "/// @brief get documents from the specified collection using a skiplist\n"
"////////////////////////////////////////////////////////////////////////////////\n" "////////////////////////////////////////////////////////////////////////////////\n"
"\n" "\n"