mirror of https://gitee.com/bigwinds/arangodb
1300 lines
42 KiB
C
1300 lines
42 KiB
C
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief data-feeder
|
|
///
|
|
/// @file
|
|
///
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
|
|
///
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
/// you may not use this file except in compliance with the License.
|
|
/// You may obtain a copy of the License at
|
|
///
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
///
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
/// See the License for the specific language governing permissions and
|
|
/// limitations under the License.
|
|
///
|
|
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// @author Jan Steemann
|
|
/// @author Copyright 2012, triagens GmbH, Cologne, Germany
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <BasicsC/logging.h>
|
|
|
|
#include "VocBase/query-data-feeder.h"
|
|
#include "VocBase/query-join.h"
|
|
#include "V8/v8-c-utils.h"
|
|
#include "QL/optimize.h"
|
|
#include "SkipLists/sl-operator.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @addtogroup VocBase
|
|
/// @{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- type independent functions
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create a new base data data feeder struct - DEPRECATED
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_data_feeder_t* CreateDataFeederX (const TRI_data_feeder_type_e type,
|
|
const TRI_doc_collection_t* collection,
|
|
const TRI_join_t* join,
|
|
size_t level) {
|
|
TRI_data_feeder_t* feeder;
|
|
|
|
feeder = (TRI_data_feeder_t*) TRI_Allocate(sizeof(TRI_data_feeder_t));
|
|
if (!feeder) {
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_type = type;
|
|
feeder->_level = level;
|
|
feeder->_join = (TRI_select_join_t*) join;
|
|
feeder->_part = (TRI_join_part_t*) ((TRI_select_join_t*) join)->_parts._buffer[level];
|
|
feeder->_collection = collection;
|
|
feeder->_ranges = NULL;
|
|
feeder->_state = NULL;
|
|
|
|
feeder->init = NULL;
|
|
feeder->rewind = NULL;
|
|
feeder->current = NULL;
|
|
feeder->free = NULL;
|
|
|
|
return feeder;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create a new base data data feeder struct
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_data_feeder_t* CreateDataFeeder (TRI_query_instance_t* const instance,
|
|
const TRI_data_feeder_type_e type,
|
|
const TRI_doc_collection_t* collection,
|
|
size_t level) {
|
|
TRI_data_feeder_t* feeder;
|
|
|
|
feeder = (TRI_data_feeder_t*) TRI_Allocate(sizeof(TRI_data_feeder_t));
|
|
if (!feeder) {
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_instance = instance;
|
|
feeder->_type = type;
|
|
feeder->_level = level;
|
|
feeder->_part = ((TRI_query_instance_t*) instance)->_join._buffer[level];
|
|
feeder->_instance = instance;
|
|
feeder->_collection = collection;
|
|
feeder->_ranges = NULL;
|
|
feeder->_state = NULL;
|
|
|
|
feeder->init = NULL;
|
|
feeder->rewind = NULL;
|
|
feeder->current = NULL;
|
|
feeder->free = NULL;
|
|
|
|
return feeder;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- table scan
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief init table scan data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void InitFeederTableScan (TRI_data_feeder_t* feeder) {
|
|
TRI_sim_collection_t* collection;
|
|
TRI_doc_mptr_t* document;
|
|
TRI_data_feeder_table_scan_t* state;
|
|
|
|
feeder->_accessType = ACCESS_ALL;
|
|
|
|
collection = (TRI_sim_collection_t*) feeder->_collection;
|
|
state = (TRI_data_feeder_table_scan_t*) feeder->_state;
|
|
|
|
if (collection->_primaryIndex._nrAlloc == 0) {
|
|
state->_start = NULL;
|
|
state->_end = NULL;
|
|
state->_current = NULL;
|
|
return;
|
|
}
|
|
|
|
state->_start = (void**) collection->_primaryIndex._table;
|
|
state->_end = (void**) (state->_start + collection->_primaryIndex._nrAlloc);
|
|
|
|
// collections contain documents in a hash table
|
|
// some of the entries are empty, and some contain deleted documents
|
|
// it is invalid to use every entry from the hash table but the invalid documents
|
|
// must be skipped.
|
|
// adjust starts to first valid document in collection
|
|
while (state->_start < state->_end) {
|
|
document = (TRI_doc_mptr_t*) *(state->_start);
|
|
if (document != NULL && !document->_deletion) {
|
|
break;
|
|
}
|
|
|
|
state->_start++;
|
|
}
|
|
|
|
// iterate from end of document hash table to front and skip all documents
|
|
// that are either deleted or empty
|
|
while (state->_end > state->_start) {
|
|
document = (TRI_doc_mptr_t*) *(state->_end - 1);
|
|
if (document != NULL && !document->_deletion) {
|
|
break;
|
|
}
|
|
state->_end--;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief rewind table scan data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void RewindFeederTableScan (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_table_scan_t* state;
|
|
|
|
state = (TRI_data_feeder_table_scan_t*) feeder->_state;
|
|
state->_current = state->_start;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get current item from table scan data feeder and advance next pointer
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool CurrentFeederTableScan (TRI_data_feeder_t* feeder) {
|
|
TRI_doc_mptr_t* document;
|
|
TRI_data_feeder_table_scan_t* state;
|
|
TRI_join_part_t* part;
|
|
|
|
state = (TRI_data_feeder_table_scan_t*) feeder->_state;
|
|
part = (TRI_join_part_t*) feeder->_part;
|
|
|
|
while (state->_current < state->_end) {
|
|
document = (TRI_doc_mptr_t*) *(state->_current);
|
|
|
|
state->_current++;
|
|
if (document && document->_deletion == 0) {
|
|
part->_singleDocument = document;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
part->_singleDocument = NULL;
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief free table scan data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void FreeFeederTableScan (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_table_scan_t* state;
|
|
|
|
state = (TRI_data_feeder_table_scan_t*) feeder->_state;
|
|
|
|
if (state) {
|
|
TRI_Free(state);
|
|
}
|
|
|
|
if (feeder->_ranges) {
|
|
TRI_DestroyVectorPointer(feeder->_ranges);
|
|
TRI_Free(feeder->_ranges);
|
|
}
|
|
|
|
TRI_Free(feeder);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create a new table scan data feeder - DEPRECATED
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_data_feeder_t* TRI_CreateDataFeederTableScanX (const TRI_doc_collection_t* collection,
|
|
TRI_join_t* join,
|
|
size_t level) {
|
|
TRI_data_feeder_t* feeder;
|
|
|
|
feeder = CreateDataFeederX(FEEDER_TABLE_SCAN, collection, join, level);
|
|
if (!feeder) {
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_state = (TRI_data_feeder_table_scan_t*)
|
|
TRI_Allocate(sizeof(TRI_data_feeder_table_scan_t));
|
|
|
|
if (!feeder->_state) {
|
|
TRI_Free(feeder);
|
|
return NULL;
|
|
}
|
|
|
|
feeder->init = InitFeederTableScan;
|
|
feeder->rewind = RewindFeederTableScan;
|
|
feeder->current = CurrentFeederTableScan;
|
|
feeder->free = FreeFeederTableScan;
|
|
|
|
return feeder;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create a new table scan data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_data_feeder_t* TRI_CreateDataFeederTableScan (TRI_query_instance_t* const instance,
|
|
const TRI_doc_collection_t* collection,
|
|
const size_t level) {
|
|
TRI_data_feeder_t* feeder;
|
|
|
|
feeder = CreateDataFeeder(instance, FEEDER_TABLE_SCAN, collection, level);
|
|
if (!feeder) {
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_state = (TRI_data_feeder_table_scan_t*)
|
|
TRI_Allocate(sizeof(TRI_data_feeder_table_scan_t));
|
|
|
|
if (!feeder->_state) {
|
|
TRI_Free(feeder);
|
|
return NULL;
|
|
}
|
|
|
|
feeder->init = InitFeederTableScan;
|
|
feeder->rewind = RewindFeederTableScan;
|
|
feeder->current = CurrentFeederTableScan;
|
|
feeder->free = FreeFeederTableScan;
|
|
|
|
return feeder;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- primary index
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief init primary index data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void InitFeederPrimaryLookup (TRI_data_feeder_t* feeder) {
|
|
QL_optimize_range_t* range;
|
|
TRI_vector_string_t parts;
|
|
TRI_data_feeder_primary_lookup_t* state;
|
|
TRI_string_buffer_t* buffer;
|
|
|
|
state = (TRI_data_feeder_primary_lookup_t*) feeder->_state;
|
|
state->_isEmpty = true;
|
|
state->_context = NULL;
|
|
|
|
assert(feeder->_ranges);
|
|
assert(feeder->_ranges->_length == 1);
|
|
|
|
range = (QL_optimize_range_t*) feeder->_ranges->_buffer[0];
|
|
|
|
if (range->_valueType == RANGE_TYPE_FIELD) {
|
|
// ref access
|
|
feeder->_accessType = ACCESS_REF;
|
|
|
|
buffer = TRI_CreateStringBuffer();
|
|
if (!buffer) {
|
|
return;
|
|
}
|
|
|
|
TRI_AppendStringStringBuffer(buffer, "(function($) { return [");
|
|
TRI_AppendStringStringBuffer(buffer, "$['");
|
|
TRI_AppendStringStringBuffer(buffer, range->_refValue._collection);
|
|
TRI_AppendStringStringBuffer(buffer, "'].");
|
|
TRI_AppendStringStringBuffer(buffer, range->_refValue._field);
|
|
TRI_AppendStringStringBuffer(buffer, "] })");
|
|
state->_context = TRI_CreateExecutionContext(buffer->_buffer);
|
|
|
|
TRI_FreeStringBuffer(buffer);
|
|
|
|
if (!state->_context) {
|
|
return;
|
|
}
|
|
state->_isEmpty = false;
|
|
}
|
|
if (range->_valueType == RANGE_TYPE_STRING) {
|
|
// const access
|
|
feeder->_accessType = ACCESS_CONST;
|
|
parts = TRI_SplitString(range->_minValue._stringValue, ':');
|
|
if (parts._length > 0) {
|
|
if (TRI_UInt64String(parts._buffer[0]) ==
|
|
((TRI_collection_t*) feeder->_collection)->_cid) {
|
|
state->_didValue = TRI_UInt64String(parts._buffer[1]);
|
|
state->_isEmpty = false;
|
|
}
|
|
}
|
|
TRI_DestroyVectorString(&parts);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief rewind primary index data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void RewindFeederPrimaryLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_primary_lookup_t* state;
|
|
|
|
state = (TRI_data_feeder_primary_lookup_t*) feeder->_state;
|
|
state->_hasCompared = true;
|
|
|
|
if (feeder->_accessType == ACCESS_REF) {
|
|
TRI_json_t* parameters;
|
|
|
|
if (!state->_context) {
|
|
return;
|
|
}
|
|
|
|
parameters = TRI_CreateListJson();
|
|
if (!parameters) {
|
|
return;
|
|
}
|
|
TRI_DefineWhereExecutionContext(feeder->_instance,
|
|
state->_context,
|
|
feeder->_level,
|
|
true);
|
|
if (TRI_ExecuteRefExecutionContext (state->_context, parameters)) {
|
|
TRI_json_t* value;
|
|
TRI_vector_string_t parts;
|
|
|
|
if (parameters->_type != TRI_JSON_LIST) {
|
|
TRI_FreeJson(parameters);
|
|
return;
|
|
}
|
|
if (parameters->_value._objects._length != 1) {
|
|
TRI_FreeJson(parameters);
|
|
return;
|
|
}
|
|
|
|
value = TRI_AtVector(¶meters->_value._objects, 0);
|
|
parts = TRI_SplitString(value->_value._string.data, ':');
|
|
if (parts._length == 2) {
|
|
if (TRI_UInt64String(parts._buffer[0]) ==
|
|
((TRI_collection_t*) feeder->_collection)->_cid) {
|
|
state->_didValue = TRI_UInt64String(parts._buffer[1]);
|
|
}
|
|
}
|
|
TRI_DestroyVectorString(&parts);
|
|
}
|
|
TRI_FreeJson(parameters);
|
|
}
|
|
|
|
state->_hasCompared = false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get current item from primary index feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool CurrentFeederPrimaryLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_sim_collection_t* collection;
|
|
TRI_data_feeder_primary_lookup_t* state;
|
|
TRI_join_part_t* part;
|
|
|
|
state = (TRI_data_feeder_primary_lookup_t*) feeder->_state;
|
|
part = (TRI_join_part_t*) feeder->_part;
|
|
|
|
if (state->_hasCompared || state->_isEmpty) {
|
|
part->_singleDocument = NULL;
|
|
return false;
|
|
}
|
|
|
|
state->_hasCompared = true;
|
|
collection = (TRI_sim_collection_t*) feeder->_collection;
|
|
part->_singleDocument = (TRI_doc_mptr_t*)
|
|
TRI_LookupByKeyAssociativePointer(&collection->_primaryIndex, &state->_didValue);
|
|
|
|
return (part->_singleDocument != NULL);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief free primary index data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void FreeFeederPrimaryLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_primary_lookup_t* state;
|
|
|
|
state = (TRI_data_feeder_primary_lookup_t*) feeder->_state;
|
|
|
|
if (state->_context) {
|
|
TRI_FreeExecutionContext(state->_context);
|
|
}
|
|
|
|
if (state) {
|
|
TRI_Free(state);
|
|
}
|
|
|
|
if (feeder->_ranges) {
|
|
TRI_DestroyVectorPointer(feeder->_ranges);
|
|
TRI_Free(feeder->_ranges);
|
|
}
|
|
|
|
TRI_Free(feeder);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create a new primary index data feeder - DEPRECATED
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_data_feeder_t* TRI_CreateDataFeederPrimaryLookupX (const TRI_doc_collection_t* collection,
|
|
TRI_join_t* join,
|
|
size_t level) {
|
|
TRI_data_feeder_t* feeder;
|
|
|
|
feeder = CreateDataFeederX(FEEDER_PRIMARY_LOOKUP, collection, join, level);
|
|
if (!feeder) {
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_state = (TRI_data_feeder_primary_lookup_t*)
|
|
TRI_Allocate(sizeof(TRI_data_feeder_primary_lookup_t));
|
|
if (!feeder->_state) {
|
|
TRI_Free(feeder);
|
|
return NULL;
|
|
}
|
|
|
|
// init feeder
|
|
feeder->init = InitFeederPrimaryLookup;
|
|
feeder->rewind = RewindFeederPrimaryLookup;
|
|
feeder->current = CurrentFeederPrimaryLookup;
|
|
feeder->free = FreeFeederPrimaryLookup;
|
|
|
|
return feeder;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create a new primary index data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_data_feeder_t* TRI_CreateDataFeederPrimaryLookup (TRI_query_instance_t* const instance,
|
|
const TRI_doc_collection_t* collection,
|
|
const size_t level,
|
|
const TRI_vector_pointer_t* ranges) {
|
|
TRI_data_feeder_t* feeder;
|
|
|
|
feeder = CreateDataFeeder(instance, FEEDER_PRIMARY_LOOKUP, collection, level);
|
|
if (!feeder) {
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_state = (TRI_data_feeder_primary_lookup_t*)
|
|
TRI_Allocate(sizeof(TRI_data_feeder_primary_lookup_t));
|
|
if (!feeder->_state) {
|
|
TRI_Free(feeder);
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_ranges = (TRI_vector_pointer_t*) ranges;
|
|
|
|
// init feeder
|
|
feeder->init = InitFeederPrimaryLookup;
|
|
feeder->rewind = RewindFeederPrimaryLookup;
|
|
feeder->current = CurrentFeederPrimaryLookup;
|
|
feeder->free = FreeFeederPrimaryLookup;
|
|
|
|
return feeder;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- hash index
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief init hash lookup data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void InitFeederHashLookup (TRI_data_feeder_t* feeder) {
|
|
QL_optimize_range_t* range;
|
|
TRI_data_feeder_hash_lookup_t* state;
|
|
TRI_json_t* parameters;
|
|
TRI_json_t* doc;
|
|
TRI_string_buffer_t* buffer;
|
|
size_t i;
|
|
|
|
state = (TRI_data_feeder_hash_lookup_t*) feeder->_state;
|
|
state->_isEmpty = true;
|
|
state->_context = NULL;
|
|
state->_position = 0;
|
|
|
|
state->_hashElements = NULL;
|
|
state->_index = TRI_IndexSimCollection((TRI_sim_collection_t*) feeder->_collection,
|
|
feeder->_indexId);
|
|
if (!state->_index) {
|
|
return;
|
|
}
|
|
assert(feeder->_ranges);
|
|
assert(feeder->_ranges->_length >= 1);
|
|
|
|
range = (QL_optimize_range_t*) feeder->_ranges->_buffer[0];
|
|
if (range->_valueType == RANGE_TYPE_FIELD) {
|
|
// ref access
|
|
feeder->_accessType = ACCESS_REF;
|
|
buffer = TRI_CreateStringBuffer();
|
|
if (!buffer) {
|
|
return;
|
|
}
|
|
|
|
TRI_AppendStringStringBuffer(buffer, "(function($) { return [");
|
|
for (i = 0; i < feeder->_ranges->_length; i++) {
|
|
range = (QL_optimize_range_t*) feeder->_ranges->_buffer[i];
|
|
if (i > 0) {
|
|
TRI_AppendCharStringBuffer(buffer, ',');
|
|
}
|
|
TRI_AppendStringStringBuffer(buffer, "$['");
|
|
TRI_AppendStringStringBuffer(buffer, range->_refValue._collection);
|
|
TRI_AppendStringStringBuffer(buffer, "'].");
|
|
TRI_AppendStringStringBuffer(buffer, range->_refValue._field);
|
|
}
|
|
TRI_AppendStringStringBuffer(buffer, "] })");
|
|
state->_context = TRI_CreateExecutionContext(buffer->_buffer);
|
|
|
|
TRI_FreeStringBuffer(buffer);
|
|
|
|
if (!state->_context) {
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
// const access
|
|
feeder->_accessType = ACCESS_CONST;
|
|
|
|
parameters = TRI_CreateListJson();
|
|
if (!parameters) {
|
|
return;
|
|
}
|
|
for (i = 0; i < feeder->_ranges->_length; i++) {
|
|
range = (QL_optimize_range_t*) feeder->_ranges->_buffer[i];
|
|
if (range->_valueType == RANGE_TYPE_STRING) {
|
|
TRI_PushBack2ListJson(parameters,
|
|
TRI_CreateStringCopyJson(range->_minValue._stringValue));
|
|
}
|
|
else if (range->_valueType == RANGE_TYPE_DOUBLE) {
|
|
TRI_PushBack2ListJson(parameters,
|
|
TRI_CreateNumberJson(range->_minValue._doubleValue));
|
|
}
|
|
else if (range->_valueType == RANGE_TYPE_JSON) {
|
|
doc = TRI_JsonString(range->_minValue._stringValue);
|
|
if (!doc) {
|
|
// TODO: properly free parameters
|
|
TRI_FreeJson(parameters);
|
|
return;
|
|
}
|
|
TRI_PushBackListJson(parameters, doc);
|
|
}
|
|
}
|
|
state->_hashElements = TRI_LookupHashIndex(state->_index, parameters);
|
|
// TODO: properly free parameters
|
|
TRI_FreeJson(parameters);
|
|
}
|
|
|
|
state->_isEmpty = false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief rewind hash lookup data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void RewindFeederHashLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_hash_lookup_t* state;
|
|
TRI_json_t* parameters;
|
|
|
|
state = (TRI_data_feeder_hash_lookup_t*) feeder->_state;
|
|
state->_position = 0;
|
|
|
|
if (feeder->_accessType == ACCESS_REF) {
|
|
if (state->_hashElements) {
|
|
TRI_Free(state->_hashElements->_elements);
|
|
TRI_Free(state->_hashElements);
|
|
}
|
|
state->_hashElements = NULL;
|
|
|
|
if (!state->_context) {
|
|
return;
|
|
}
|
|
parameters = TRI_CreateListJson();
|
|
if (!parameters) {
|
|
return;
|
|
}
|
|
TRI_DefineWhereExecutionContext(feeder->_instance,
|
|
state->_context,
|
|
feeder->_level,
|
|
true);
|
|
if (TRI_ExecuteRefExecutionContext (state->_context, parameters)) {
|
|
state->_hashElements = TRI_LookupHashIndex(state->_index, parameters);
|
|
}
|
|
|
|
TRI_FreeJson(parameters);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get current item from hash lookup feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool CurrentFeederHashLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_hash_lookup_t* state;
|
|
TRI_doc_mptr_t* document;
|
|
TRI_join_part_t* part;
|
|
|
|
state = (TRI_data_feeder_hash_lookup_t*) feeder->_state;
|
|
part = (TRI_join_part_t*) feeder->_part;
|
|
|
|
if (state->_isEmpty || !state->_hashElements) {
|
|
part->_singleDocument = NULL;
|
|
return false;
|
|
}
|
|
|
|
while (state->_position < state->_hashElements->_numElements) {
|
|
document = (TRI_doc_mptr_t*) ((state->_hashElements->_elements[state->_position++]).data);
|
|
if (document && !document->_deletion) {
|
|
part->_singleDocument = document;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
part->_singleDocument = NULL;
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief free hash lookup data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void FreeFeederHashLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_hash_lookup_t* state;
|
|
|
|
state = (TRI_data_feeder_hash_lookup_t*) feeder->_state;
|
|
if (state->_hashElements) {
|
|
TRI_Free(state->_hashElements->_elements);
|
|
TRI_Free(state->_hashElements);
|
|
}
|
|
|
|
if (state->_context) {
|
|
TRI_FreeExecutionContext(state->_context);
|
|
}
|
|
|
|
if (state) {
|
|
TRI_Free(state);
|
|
}
|
|
|
|
if (feeder->_ranges) {
|
|
TRI_DestroyVectorPointer(feeder->_ranges);
|
|
TRI_Free(feeder->_ranges);
|
|
}
|
|
|
|
TRI_Free(feeder);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Create a new data feeder for hash lookups - DEPRECATED
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_data_feeder_t* TRI_CreateDataFeederHashLookupX (const TRI_doc_collection_t* collection,
|
|
TRI_join_t* join,
|
|
size_t level) {
|
|
TRI_data_feeder_t* feeder;
|
|
|
|
feeder = CreateDataFeederX(FEEDER_HASH_LOOKUP, collection, join, level);
|
|
if (!feeder) {
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_state = (TRI_data_feeder_hash_lookup_t*)
|
|
TRI_Allocate(sizeof(TRI_data_feeder_hash_lookup_t));
|
|
if (!feeder->_state) {
|
|
TRI_Free(feeder);
|
|
return NULL;
|
|
}
|
|
|
|
feeder->init = InitFeederHashLookup;
|
|
feeder->rewind = RewindFeederHashLookup;
|
|
feeder->current = CurrentFeederHashLookup;
|
|
feeder->free = FreeFeederHashLookup;
|
|
|
|
return feeder;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Create a new data feeder for hash lookups
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_data_feeder_t* TRI_CreateDataFeederHashLookup (TRI_query_instance_t* const instance,
|
|
const TRI_doc_collection_t* collection,
|
|
size_t level,
|
|
const TRI_idx_iid_t indexId,
|
|
const TRI_vector_pointer_t* ranges) {
|
|
TRI_data_feeder_t* feeder;
|
|
|
|
feeder = CreateDataFeeder(instance, FEEDER_HASH_LOOKUP, collection, level);
|
|
if (!feeder) {
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_state = (TRI_data_feeder_hash_lookup_t*)
|
|
TRI_Allocate(sizeof(TRI_data_feeder_hash_lookup_t));
|
|
if (!feeder->_state) {
|
|
TRI_Free(feeder);
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_indexId = indexId;
|
|
feeder->_ranges = (TRI_vector_pointer_t*) ranges;
|
|
|
|
feeder->init = InitFeederHashLookup;
|
|
feeder->rewind = RewindFeederHashLookup;
|
|
feeder->current = CurrentFeederHashLookup;
|
|
feeder->free = FreeFeederHashLookup;
|
|
|
|
return feeder;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- skiplists
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief free skiplist index elements
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void FreeSkiplistElements (SkiplistIndexElements* elements) {
|
|
TRI_Free(elements->_elements);
|
|
TRI_Free(elements);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create a skiplist single-value operator
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_sl_operator_t* CreateSkipListValueOperator (const TRI_sl_operator_type_e type,
|
|
const QL_optimize_range_t* const range,
|
|
const bool useMax) {
|
|
TRI_sl_operator_t* operator;
|
|
|
|
TRI_json_t* parameters = TRI_CreateListJson();
|
|
if (!parameters) {
|
|
return NULL;
|
|
}
|
|
|
|
if (range->_valueType == RANGE_TYPE_STRING) {
|
|
if (useMax) {
|
|
TRI_PushBack2ListJson(parameters, TRI_CreateStringCopyJson(range->_maxValue._stringValue));
|
|
}
|
|
else {
|
|
TRI_PushBack2ListJson(parameters, TRI_CreateStringCopyJson(range->_minValue._stringValue));
|
|
}
|
|
}
|
|
else if (range->_valueType == RANGE_TYPE_DOUBLE) {
|
|
if (useMax) {
|
|
TRI_PushBack2ListJson(parameters, TRI_CreateNumberJson(range->_maxValue._doubleValue));
|
|
}
|
|
else {
|
|
TRI_PushBack2ListJson(parameters, TRI_CreateNumberJson(range->_minValue._doubleValue));
|
|
}
|
|
}
|
|
else if (range->_valueType == RANGE_TYPE_JSON) {
|
|
TRI_json_t* doc = TRI_JsonString(range->_minValue._stringValue);
|
|
if (!doc) {
|
|
TRI_FreeJson(parameters);
|
|
return NULL;
|
|
}
|
|
TRI_PushBackListJson(parameters, doc);
|
|
}
|
|
|
|
operator = CreateSLOperator(type, NULL, NULL, parameters, NULL, 1, NULL);
|
|
|
|
return operator;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief create a skiplist operation (complete instruction)
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static TRI_sl_operator_t* CreateSkipListOperation (TRI_data_feeder_t* feeder) {
|
|
TRI_sl_operator_t* lastOp = NULL;
|
|
size_t i;
|
|
|
|
for (i = 0; i < feeder->_ranges->_length; i++) {
|
|
TRI_sl_operator_t* op = NULL;
|
|
QL_optimize_range_t* range;
|
|
|
|
range = (QL_optimize_range_t*) feeder->_ranges->_buffer[i];
|
|
|
|
if (range->_minStatus == RANGE_VALUE_INFINITE &&
|
|
range->_maxStatus == RANGE_VALUE_INCLUDED) {
|
|
// oo .. x|
|
|
op = CreateSkipListValueOperator(TRI_SL_LE_OPERATOR, range, true);
|
|
}
|
|
else if (range->_minStatus == RANGE_VALUE_INFINITE &&
|
|
range->_maxStatus == RANGE_VALUE_EXCLUDED) {
|
|
// oo .. |x
|
|
op = CreateSkipListValueOperator(TRI_SL_LT_OPERATOR, range, true);
|
|
}
|
|
else if (range->_minStatus == RANGE_VALUE_INCLUDED &&
|
|
range->_maxStatus == RANGE_VALUE_INFINITE) {
|
|
// |x .. oo
|
|
op = CreateSkipListValueOperator(TRI_SL_GE_OPERATOR, range, false);
|
|
}
|
|
else if (range->_minStatus == RANGE_VALUE_EXCLUDED &&
|
|
range->_maxStatus == RANGE_VALUE_INFINITE) {
|
|
// x| .. oo
|
|
op = CreateSkipListValueOperator(TRI_SL_GT_OPERATOR, range, false);
|
|
}
|
|
else if (range->_minStatus == RANGE_VALUE_INCLUDED &&
|
|
range->_maxStatus == RANGE_VALUE_INCLUDED) {
|
|
// x
|
|
if ((range->_valueType == RANGE_TYPE_DOUBLE && range->_minValue._doubleValue == range->_maxValue._doubleValue) ||
|
|
(range->_valueType == RANGE_TYPE_STRING && strcmp(range->_minValue._stringValue, range->_maxValue._stringValue) == 0) ||
|
|
(range->_valueType == RANGE_TYPE_JSON)) {
|
|
op = CreateSkipListValueOperator(TRI_SL_EQ_OPERATOR, range, true);
|
|
}
|
|
}
|
|
|
|
if (op == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (lastOp != NULL) {
|
|
lastOp = CreateSLOperator(TRI_SL_AND_OPERATOR, op, lastOp, NULL, NULL, 2, NULL);
|
|
}
|
|
else {
|
|
lastOp = op;
|
|
}
|
|
}
|
|
|
|
return lastOp;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief init skiplist data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void InitFeederSkiplistLookup (TRI_data_feeder_t* feeder) {
|
|
QL_optimize_range_t* range;
|
|
TRI_data_feeder_skiplist_lookup_t* state;
|
|
|
|
state = (TRI_data_feeder_skiplist_lookup_t*) feeder->_state;
|
|
state->_isEmpty = true;
|
|
state->_context = NULL;
|
|
state->_position = 0;
|
|
|
|
state->_skiplistIterator = NULL;
|
|
state->_index = TRI_IndexSimCollection((TRI_sim_collection_t*) feeder->_collection,
|
|
feeder->_indexId);
|
|
if (!state->_index) {
|
|
return;
|
|
}
|
|
assert(feeder->_ranges);
|
|
assert(feeder->_ranges->_length >= 1);
|
|
|
|
range = (QL_optimize_range_t*) feeder->_ranges->_buffer[0];
|
|
if (range->_valueType == RANGE_TYPE_FIELD) {
|
|
TRI_string_buffer_t* buffer;
|
|
size_t i;
|
|
|
|
// ref access
|
|
feeder->_accessType = ACCESS_REF;
|
|
buffer = TRI_CreateStringBuffer();
|
|
if (!buffer) {
|
|
return;
|
|
}
|
|
|
|
TRI_AppendStringStringBuffer(buffer, "(function($) { return [");
|
|
for (i = 0; i < feeder->_ranges->_length; i++) {
|
|
range = (QL_optimize_range_t*) feeder->_ranges->_buffer[i];
|
|
if (i > 0) {
|
|
TRI_AppendCharStringBuffer(buffer, ',');
|
|
}
|
|
TRI_AppendStringStringBuffer(buffer, "$['");
|
|
TRI_AppendStringStringBuffer(buffer, range->_refValue._collection);
|
|
TRI_AppendStringStringBuffer(buffer, "'].");
|
|
TRI_AppendStringStringBuffer(buffer, range->_refValue._field);
|
|
}
|
|
TRI_AppendStringStringBuffer(buffer, "] })");
|
|
state->_context = TRI_CreateExecutionContext(buffer->_buffer);
|
|
|
|
TRI_FreeStringBuffer(buffer);
|
|
|
|
if (!state->_context) {
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
TRI_sl_operator_t* skipListOperation;
|
|
|
|
// const access
|
|
feeder->_accessType = ACCESS_CONST;
|
|
|
|
skipListOperation = CreateSkipListOperation(feeder);
|
|
if (!skipListOperation) {
|
|
return;
|
|
}
|
|
state->_skiplistIterator = TRI_LookupSkiplistIndex(state->_index, skipListOperation);
|
|
}
|
|
|
|
state->_isEmpty = false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief rewind skiplist data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void RewindFeederSkiplistLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_skiplist_lookup_t* state;
|
|
TRI_json_t* parameters;
|
|
|
|
state = (TRI_data_feeder_skiplist_lookup_t*) feeder->_state;
|
|
state->_position = 0;
|
|
|
|
if (feeder->_accessType == ACCESS_REF) {
|
|
if (state->_skiplistIterator) {
|
|
// TODO: free skiplist iterator!
|
|
// FreeSkiplistElements(state->_skiplistElements);
|
|
}
|
|
state->_skiplistIterator = NULL;
|
|
|
|
if (!state->_context) {
|
|
return;
|
|
}
|
|
parameters = TRI_CreateListJson();
|
|
if (!parameters) {
|
|
return;
|
|
}
|
|
TRI_DefineWhereExecutionContext(feeder->_instance,
|
|
state->_context,
|
|
feeder->_level,
|
|
true);
|
|
if (TRI_ExecuteRefExecutionContext (state->_context, parameters)) {
|
|
// TODO: fix
|
|
// state->_skiplistIterator = TRI_LookupSkiplistIndex(state->_index, parameters);
|
|
}
|
|
|
|
TRI_FreeJson(parameters);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get current item from skiplist feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool CurrentFeederSkiplistLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_skiplist_lookup_t* state;
|
|
SkiplistIndexElement* indexElement;
|
|
TRI_doc_mptr_t* document;
|
|
TRI_join_part_t* part;
|
|
|
|
state = (TRI_data_feeder_skiplist_lookup_t*) feeder->_state;
|
|
part = (TRI_join_part_t*) feeder->_part;
|
|
|
|
if (state->_isEmpty || !state->_skiplistIterator) {
|
|
part->_singleDocument = NULL;
|
|
return false;
|
|
}
|
|
|
|
indexElement = (SkiplistIndexElement*) state->_skiplistIterator->_next(state->_skiplistIterator);
|
|
if (indexElement) {
|
|
document = (TRI_doc_mptr_t*) indexElement->data;
|
|
part->_singleDocument = document;
|
|
return true;
|
|
}
|
|
|
|
part->_singleDocument = NULL;
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief free skiplist lookup data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void FreeFeederSkiplistLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_skiplist_lookup_t* state;
|
|
|
|
state = (TRI_data_feeder_skiplist_lookup_t*) feeder->_state;
|
|
if (state->_skiplistIterator) {
|
|
// TODO: free iterator!!!!!!
|
|
// FreeSkiplistElements(state->_skiplistElements);
|
|
}
|
|
|
|
if (state->_context) {
|
|
TRI_FreeExecutionContext(state->_context);
|
|
}
|
|
|
|
if (state) {
|
|
TRI_Free(state);
|
|
}
|
|
|
|
if (feeder->_ranges) {
|
|
TRI_DestroyVectorPointer(feeder->_ranges);
|
|
TRI_Free(feeder->_ranges);
|
|
}
|
|
|
|
TRI_Free(feeder);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Create a new data feeder for skiplist lookups - DEPRECATED
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_data_feeder_t* TRI_CreateDataFeederSkiplistLookupX (const TRI_doc_collection_t* collection,
|
|
TRI_join_t* join,
|
|
size_t level) {
|
|
TRI_data_feeder_t* feeder;
|
|
|
|
feeder = CreateDataFeederX(FEEDER_SKIPLIST_LOOKUP, collection, join, level);
|
|
if (!feeder) {
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_state = (TRI_data_feeder_skiplist_lookup_t*)
|
|
TRI_Allocate(sizeof(TRI_data_feeder_skiplist_lookup_t));
|
|
if (!feeder->_state) {
|
|
TRI_Free(feeder);
|
|
return NULL;
|
|
}
|
|
|
|
feeder->init = InitFeederSkiplistLookup;
|
|
feeder->rewind = RewindFeederSkiplistLookup;
|
|
feeder->current = CurrentFeederSkiplistLookup;
|
|
feeder->free = FreeFeederSkiplistLookup;
|
|
|
|
return feeder;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Create a new data feeder for skiplist lookups
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_data_feeder_t* TRI_CreateDataFeederSkiplistLookup (TRI_query_instance_t* const instance,
|
|
const TRI_doc_collection_t* collection,
|
|
size_t level,
|
|
const TRI_idx_iid_t indexId,
|
|
const TRI_vector_pointer_t* ranges) {
|
|
TRI_data_feeder_t* feeder;
|
|
|
|
feeder = CreateDataFeeder(instance, FEEDER_SKIPLIST_LOOKUP, collection, level);
|
|
if (!feeder) {
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_state = (TRI_data_feeder_skiplist_lookup_t*)
|
|
TRI_Allocate(sizeof(TRI_data_feeder_skiplist_lookup_t));
|
|
if (!feeder->_state) {
|
|
TRI_Free(feeder);
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_indexId = indexId;
|
|
feeder->_ranges = (TRI_vector_pointer_t*) ranges;
|
|
|
|
feeder->init = InitFeederSkiplistLookup;
|
|
feeder->rewind = RewindFeederSkiplistLookup;
|
|
feeder->current = CurrentFeederSkiplistLookup;
|
|
feeder->free = FreeFeederSkiplistLookup;
|
|
|
|
return feeder;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// --SECTION-- geo index
|
|
// -----------------------------------------------------------------------------
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief init geo index data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void InitFeederGeoLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_geo_lookup_t* state;
|
|
|
|
state = (TRI_data_feeder_geo_lookup_t*) feeder->_state;
|
|
state->_isEmpty = true;
|
|
state->_position = 0;
|
|
state->_coordinates = NULL;
|
|
|
|
state->_index = TRI_IndexSimCollection((TRI_sim_collection_t*) feeder->_collection,
|
|
feeder->_indexId);
|
|
if (!state->_index) {
|
|
return;
|
|
}
|
|
if (!state->_restriction) {
|
|
return;
|
|
}
|
|
|
|
state->_isEmpty = false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief rewind geo index data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void RewindFeederGeoLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_geo_lookup_t* state;
|
|
|
|
state = (TRI_data_feeder_geo_lookup_t*) feeder->_state;
|
|
state->_position = 0;
|
|
|
|
if (state->_restriction->_type == RESTRICT_WITHIN) {
|
|
state->_coordinates = TRI_WithinGeoIndex(state->_index,
|
|
state->_restriction->_lat,
|
|
state->_restriction->_lon,
|
|
state->_restriction->_arg._radius);
|
|
}
|
|
else {
|
|
state->_coordinates = TRI_NearestGeoIndex(state->_index,
|
|
state->_restriction->_lat,
|
|
state->_restriction->_lon,
|
|
state->_restriction->_arg._numDocuments);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get current item from geo index feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool CurrentFeederGeoLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_geo_lookup_t* state;
|
|
TRI_doc_mptr_t* document;
|
|
TRI_join_part_t* part;
|
|
size_t position;
|
|
|
|
state = (TRI_data_feeder_geo_lookup_t*) feeder->_state;
|
|
part = (TRI_join_part_t*) feeder->_part;
|
|
|
|
if (state->_isEmpty || !state->_coordinates) {
|
|
part->_singleDocument = NULL;
|
|
part->_extraData._singleValue = NULL;
|
|
return false;
|
|
}
|
|
|
|
while (state->_position < state->_coordinates->length) {
|
|
position = state->_position++;
|
|
document = (TRI_doc_mptr_t*) ((state->_coordinates->coordinates[position].data));
|
|
if (document && !document->_deletion) {
|
|
part->_singleDocument = document;
|
|
// store extra data
|
|
part->_extraData._singleValue = &state->_coordinates->distances[position];
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
part->_singleDocument = NULL;
|
|
part->_extraData._singleValue = NULL;
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief free geo index data feeder
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void FreeFeederGeoLookup (TRI_data_feeder_t* feeder) {
|
|
TRI_data_feeder_geo_lookup_t* state;
|
|
|
|
state = (TRI_data_feeder_geo_lookup_t*) feeder->_state;
|
|
if (state->_coordinates) {
|
|
GeoIndex_CoordinatesFree(state->_coordinates);
|
|
}
|
|
|
|
if (state) {
|
|
TRI_Free(state);
|
|
}
|
|
|
|
if (feeder) {
|
|
TRI_Free(feeder);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Create a new data feeder for geo lookups - DEPRECATED
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_data_feeder_t* TRI_CreateDataFeederGeoLookupX (const TRI_doc_collection_t* collection,
|
|
TRI_join_t* join,
|
|
size_t level,
|
|
QL_ast_query_geo_restriction_t* restriction) {
|
|
TRI_data_feeder_t* feeder;
|
|
TRI_data_feeder_geo_lookup_t* state;
|
|
|
|
feeder = CreateDataFeederX(FEEDER_GEO_LOOKUP, collection, join, level);
|
|
if (!feeder) {
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_state = (TRI_data_feeder_geo_lookup_t*)
|
|
TRI_Allocate(sizeof(TRI_data_feeder_geo_lookup_t));
|
|
|
|
state = (TRI_data_feeder_geo_lookup_t*) feeder->_state;
|
|
|
|
if (!state) {
|
|
TRI_Free(feeder);
|
|
return NULL;
|
|
}
|
|
|
|
state->_restriction = restriction;
|
|
|
|
feeder->init = InitFeederGeoLookup;
|
|
feeder->rewind = RewindFeederGeoLookup;
|
|
feeder->current = CurrentFeederGeoLookup;
|
|
feeder->free = FreeFeederGeoLookup;
|
|
|
|
return feeder;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Create a new data feeder for geo lookups
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
TRI_data_feeder_t* TRI_CreateDataFeederGeoLookup (TRI_query_instance_t* const instance,
|
|
const TRI_doc_collection_t* collection,
|
|
const size_t level,
|
|
const TRI_idx_iid_t indexId,
|
|
const QL_ast_query_geo_restriction_t* restriction) {
|
|
TRI_data_feeder_t* feeder;
|
|
TRI_data_feeder_geo_lookup_t* state;
|
|
|
|
feeder = CreateDataFeeder(instance, FEEDER_GEO_LOOKUP, collection, level);
|
|
if (!feeder) {
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_state = (TRI_data_feeder_geo_lookup_t*)
|
|
TRI_Allocate(sizeof(TRI_data_feeder_geo_lookup_t));
|
|
|
|
state = (TRI_data_feeder_geo_lookup_t*) feeder->_state;
|
|
|
|
if (!state) {
|
|
TRI_Free(feeder);
|
|
return NULL;
|
|
}
|
|
|
|
feeder->_indexId = indexId;
|
|
|
|
state->_restriction = (QL_ast_query_geo_restriction_t*) restriction;
|
|
|
|
feeder->init = InitFeederGeoLookup;
|
|
feeder->rewind = RewindFeederGeoLookup;
|
|
feeder->current = CurrentFeederGeoLookup;
|
|
feeder->free = FreeFeederGeoLookup;
|
|
|
|
return feeder;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Local Variables:
|
|
// mode: outline-minor
|
|
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
|
|
// End:
|
|
|