mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2
Conflicts: arangod/Makefile.files
This commit is contained in:
commit
934c1df189
|
@ -0,0 +1,600 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Aql, query context
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Aql/Query.h"
|
||||
#include "BasicsC/json.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
||||
using namespace triagens::aql;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors / destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief creates a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Query::Query (TRI_vocbase_t* vocbase,
|
||||
char const* queryString,
|
||||
size_t queryLength,
|
||||
TRI_json_t* bindParameters)
|
||||
: _vocbase(vocbase),
|
||||
_queryString(queryString),
|
||||
_queryLength(queryLength),
|
||||
_queryType(QUERY_READ),
|
||||
_bindParameters(bindParameters),
|
||||
_error() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief destroys a query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Query::~Query () {
|
||||
if (_bindParameters != nullptr) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, _bindParameters);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief execute an AQL query - TODO: implement and determine return type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Query::execute () {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief parse an AQL query - TODO: implement and determine return type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Query::parse () {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief explain an AQL query - TODO: implement and determine return type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Query::explain () {
|
||||
}
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief shortcut macro for signalling out of memory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define ABORT_OOM \
|
||||
TRI_SetErrorContextAql( \
|
||||
__FILE__, __LINE__, context, TRI_ERROR_OUT_OF_MEMORY, NULL); \
|
||||
return NULL;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief free all collection memory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void FreeCollections (TRI_aql_context_t* const context) {
|
||||
size_t i = context->_collections._length;
|
||||
|
||||
while (i--) {
|
||||
TRI_aql_collection_t* collection = (TRI_aql_collection_t*) context->_collections._buffer[i];
|
||||
|
||||
if (collection != NULL) {
|
||||
TRI_FreeCollectionAql(collection);
|
||||
}
|
||||
}
|
||||
TRI_DestroyVectorPointer(&context->_collections);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief free all strings
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void FreeStrings (TRI_aql_context_t* const context) {
|
||||
size_t i = context->_memory._strings._length;
|
||||
|
||||
while (i--) {
|
||||
void* string = context->_memory._strings._buffer[i];
|
||||
|
||||
if (string) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, context->_memory._strings._buffer[i]);
|
||||
}
|
||||
}
|
||||
TRI_DestroyVectorPointer(&context->_memory._strings);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief free all nodes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void FreeNodes (TRI_aql_context_t* const context) {
|
||||
size_t i = context->_memory._nodes._length;
|
||||
|
||||
while (i--) {
|
||||
TRI_aql_node_t* node = (TRI_aql_node_t*) context->_memory._nodes._buffer[i];
|
||||
|
||||
if (node == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TRI_DestroyVectorPointer(&node->_members);
|
||||
|
||||
if (node->_type == TRI_AQL_NODE_COLLECTION) {
|
||||
// free attached collection hint
|
||||
TRI_aql_collection_hint_t* hint = (TRI_aql_collection_hint_t*) (TRI_AQL_NODE_DATA(node));
|
||||
|
||||
if (hint != NULL) {
|
||||
TRI_FreeCollectionHintAql(hint);
|
||||
}
|
||||
}
|
||||
else if (node->_type == TRI_AQL_NODE_FOR) {
|
||||
// free attached for hint
|
||||
TRI_aql_for_hint_t* hint = (TRI_aql_for_hint_t*) (TRI_AQL_NODE_DATA(node));
|
||||
|
||||
if (hint != NULL) {
|
||||
TRI_FreeForHintScopeAql(hint);
|
||||
}
|
||||
}
|
||||
|
||||
// free node itself
|
||||
delete node;
|
||||
}
|
||||
|
||||
TRI_DestroyVectorPointer(&context->_memory._nodes);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief process options from the context
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void ProcessOptions (TRI_aql_context_t* context) {
|
||||
TRI_json_t* value;
|
||||
|
||||
// default values
|
||||
context->_fullCount = false;
|
||||
|
||||
value = TRI_GetOptionContextAql(context, "fullCount");
|
||||
|
||||
if (value != NULL && value->_type == TRI_JSON_BOOLEAN) {
|
||||
context->_fullCount = value->_value._boolean;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors / destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create and initialize a context
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_aql_context_t* TRI_CreateContextAql (TRI_vocbase_t* vocbase,
|
||||
const char* const query,
|
||||
const size_t queryLength,
|
||||
bool isCoordinator,
|
||||
TRI_json_t* userOptions) {
|
||||
TRI_aql_context_t* context;
|
||||
int res;
|
||||
|
||||
TRI_ASSERT(vocbase != NULL);
|
||||
TRI_ASSERT(query != NULL);
|
||||
|
||||
LOG_TRACE("creating context");
|
||||
|
||||
context = (TRI_aql_context_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_aql_context_t), false);
|
||||
|
||||
if (context == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
context->_type = TRI_AQL_QUERY_READ;
|
||||
context->_vocbase = vocbase;
|
||||
context->_userOptions = userOptions;
|
||||
context->_writeOptions = NULL;
|
||||
context->_writeCollection = NULL;
|
||||
|
||||
context->_variableIndex = 0;
|
||||
context->_scopeIndex = 0;
|
||||
context->_subQueries = 0;
|
||||
|
||||
// actual bind parameter values
|
||||
res = TRI_InitAssociativePointer(&context->_parameters._values,
|
||||
TRI_UNKNOWN_MEM_ZONE,
|
||||
&TRI_HashStringKeyAssociativePointer,
|
||||
&TRI_HashBindParameterAql,
|
||||
&TRI_EqualBindParameterAql,
|
||||
0);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, context);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// bind parameter names used in the query
|
||||
res = TRI_InitAssociativePointer(&context->_parameters._names,
|
||||
TRI_UNKNOWN_MEM_ZONE,
|
||||
&TRI_HashStringKeyAssociativePointer,
|
||||
&TRI_HashStringKeyAssociativePointer,
|
||||
&TRI_EqualStringKeyAssociativePointer,
|
||||
0);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_DestroyAssociativePointer(&context->_parameters._values);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, context);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// collections
|
||||
res = TRI_InitAssociativePointer(&context->_collectionNames,
|
||||
TRI_UNKNOWN_MEM_ZONE,
|
||||
&TRI_HashStringKeyAssociativePointer,
|
||||
&TRI_HashStringKeyAssociativePointer,
|
||||
&TRI_EqualStringKeyAssociativePointer,
|
||||
0);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_DestroyAssociativePointer(&context->_parameters._names);
|
||||
TRI_DestroyAssociativePointer(&context->_parameters._values);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, context);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TRI_InitVectorPointer2(&context->_memory._nodes, TRI_UNKNOWN_MEM_ZONE, 16);
|
||||
TRI_InitVectorPointer2(&context->_memory._strings, TRI_UNKNOWN_MEM_ZONE, 16);
|
||||
TRI_InitVectorPointer(&context->_collections, TRI_UNKNOWN_MEM_ZONE);
|
||||
|
||||
TRI_InitErrorAql(&context->_error);
|
||||
|
||||
context->_parser = NULL;
|
||||
context->_statements = NULL;
|
||||
context->_query = query;
|
||||
|
||||
TRI_InitScopesAql(context);
|
||||
|
||||
context->_parser = TRI_CreateParserAql(context->_query, queryLength);
|
||||
|
||||
if (context->_parser == NULL) {
|
||||
// could not create the parser
|
||||
TRI_FreeContextAql(context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (! TRI_InitParserAql(context)) {
|
||||
// could not initialise the lexer
|
||||
TRI_FreeContextAql(context);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
context->_statements = TRI_CreateStatementListAql();
|
||||
|
||||
if (context->_statements == NULL) {
|
||||
// could not create statement list
|
||||
TRI_FreeContextAql(context);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ProcessOptions(context);
|
||||
|
||||
context->_isCoordinator = isCoordinator;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief free a context
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_FreeContextAql (TRI_aql_context_t* const context) {
|
||||
TRI_ASSERT(context != NULL);
|
||||
|
||||
LOG_TRACE("freeing context");
|
||||
|
||||
// release all scopes
|
||||
TRI_FreeScopesAql(context);
|
||||
|
||||
FreeStrings(context);
|
||||
FreeNodes(context);
|
||||
|
||||
// free parameter names hash
|
||||
TRI_DestroyAssociativePointer(&context->_parameters._names);
|
||||
|
||||
// free collection names
|
||||
TRI_DestroyAssociativePointer(&context->_collectionNames);
|
||||
|
||||
FreeCollections(context);
|
||||
|
||||
// free parameter values
|
||||
TRI_FreeBindParametersAql(context);
|
||||
TRI_DestroyAssociativePointer(&context->_parameters._values);
|
||||
|
||||
// free parser/lexer
|
||||
TRI_FreeParserAql(context->_parser);
|
||||
|
||||
// free statement list
|
||||
TRI_FreeStatementListAql(context->_statements);
|
||||
|
||||
// free error struct
|
||||
TRI_DestroyErrorAql(&context->_error);
|
||||
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, context);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief parse & validate the query string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_ValidateQueryContextAql (TRI_aql_context_t* const context) {
|
||||
if (context->_parser->_length == 0) {
|
||||
// query is empty, no need to parse it
|
||||
TRI_SetErrorContextAql(__FILE__, __LINE__, context, TRI_ERROR_QUERY_EMPTY, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse the query
|
||||
if (! TRI_ParseAql(context)) {
|
||||
// lexing/parsing failed
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context->_error._code) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add bind parameters to the query context
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_BindQueryContextAql (TRI_aql_context_t* const context,
|
||||
const TRI_json_t* const parameters) {
|
||||
|
||||
// add the bind parameters
|
||||
if (! TRI_AddParameterValuesAql(context, parameters)) {
|
||||
// adding parameters failed
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate the bind parameters used/passed
|
||||
if (! TRI_ValidateBindParametersAql(context)) {
|
||||
// invalid bind parameters
|
||||
return false;
|
||||
}
|
||||
|
||||
// inject the bind parameter values into the query AST
|
||||
if (! TRI_InjectBindParametersAql(context)) {
|
||||
// bind parameter injection failed
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context->_error._code) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief perform some AST optimisations
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_OptimiseQueryContextAql (TRI_aql_context_t* const context) {
|
||||
|
||||
// do some basic optimisations in the AST
|
||||
if (! TRI_OptimiseAql(context)) {
|
||||
// constant folding failed
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context->_error._code) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TRI_CompactStatementListAql(context->_statements);
|
||||
TRI_PulloutStatementListAql(context->_statements);
|
||||
|
||||
// TRI_DumpStatementsAql(context->_statements);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set up all collections used in the query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_SetupCollectionsContextAql (TRI_aql_context_t* const context) {
|
||||
// mark all used collections as being used
|
||||
if (! TRI_SetupCollectionsAql(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context->_error._code) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_RegisterNodeContextAql (TRI_aql_context_t* const context,
|
||||
void* const node) {
|
||||
TRI_ASSERT(context != NULL);
|
||||
TRI_ASSERT(node != NULL);
|
||||
|
||||
TRI_PushBackVectorPointer(&context->_memory._nodes, node);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* TRI_RegisterStringAql (TRI_aql_context_t* const context,
|
||||
const char* const value,
|
||||
const size_t length,
|
||||
const bool deescape) {
|
||||
char* copy;
|
||||
|
||||
if (value == NULL) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (deescape && length > 0) {
|
||||
size_t outLength;
|
||||
|
||||
copy = TRI_UnescapeUtf8StringZ(TRI_UNKNOWN_MEM_ZONE, value, length, &outLength);
|
||||
}
|
||||
else {
|
||||
copy = TRI_DuplicateString2Z(TRI_UNKNOWN_MEM_ZONE, value, length);
|
||||
}
|
||||
|
||||
if (copy == NULL) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (TRI_PushBackVectorPointer(&context->_memory._strings, copy) != TRI_ERROR_NO_ERROR) {
|
||||
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, copy);
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a combined string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* TRI_RegisterString2Aql (TRI_aql_context_t* const context,
|
||||
const char* const s1,
|
||||
const char* const s2) {
|
||||
char* copy;
|
||||
|
||||
copy = TRI_Concatenate2StringZ(TRI_UNKNOWN_MEM_ZONE, s1, s2);
|
||||
|
||||
if (copy == NULL) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (TRI_PushBackVectorPointer(&context->_memory._strings, copy) != TRI_ERROR_NO_ERROR) {
|
||||
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, copy);
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a combined string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* TRI_RegisterString3Aql (TRI_aql_context_t* const context,
|
||||
const char* const s1,
|
||||
const char* const s2,
|
||||
const char* const s3) {
|
||||
char* copy;
|
||||
|
||||
copy = TRI_Concatenate3StringZ(TRI_UNKNOWN_MEM_ZONE, s1, s2, s3);
|
||||
|
||||
if (copy == NULL) {
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
if (TRI_PushBackVectorPointer(&context->_memory._strings, copy) != TRI_ERROR_NO_ERROR) {
|
||||
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, copy);
|
||||
ABORT_OOM
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register an error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_SetErrorContextAql (const char* file,
|
||||
int line,
|
||||
TRI_aql_context_t* const context,
|
||||
const int code,
|
||||
const char* const data) {
|
||||
|
||||
TRI_ASSERT(context != NULL);
|
||||
TRI_ASSERT(code > 0);
|
||||
|
||||
if (context->_error._code == 0) {
|
||||
// do not overwrite previous error
|
||||
TRI_set_errno(code);
|
||||
context->_error._code = code;
|
||||
context->_error._message = (char*) TRI_last_error();
|
||||
context->_error._file = file;
|
||||
context->_error._line = line;
|
||||
|
||||
if (data) {
|
||||
context->_error._data = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the value of an option variable
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_json_t* TRI_GetOptionContextAql (TRI_aql_context_t* const context,
|
||||
const char* name) {
|
||||
if (context->_userOptions == NULL || context->_userOptions->_type != TRI_JSON_ARRAY) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return TRI_LookupArrayJson(context->_userOptions, name);
|
||||
}
|
||||
*/
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -0,0 +1,265 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Aql, query context
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_AQL_QUERY_H
|
||||
#define ARANGODB_AQL_QUERY_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Aql/QueryError.h"
|
||||
|
||||
struct TRI_json_s;
|
||||
struct TRI_vocbase_s;
|
||||
|
||||
namespace triagens {
|
||||
namespace aql {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the type of query to execute
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum QueryType {
|
||||
QUERY_READ,
|
||||
QUERY_REMOVE,
|
||||
QUERY_INSERT,
|
||||
QUERY_UPDATE,
|
||||
QUERY_REPLACE
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- class Query
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief an AQL query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class Query {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors / destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
Query (struct TRI_vocbase_s*,
|
||||
char const*,
|
||||
size_t,
|
||||
struct TRI_json_s*);
|
||||
|
||||
~Query ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief execute an AQL query - TODO: implement and determine return type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void execute ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief parse an AQL query - TODO: implement and determine return type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void parse ();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief explain an AQL query - TODO: implement and determine return type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void explain ();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
|
||||
struct TRI_vocbase_s* _vocbase;
|
||||
|
||||
char const* _queryString;
|
||||
size_t const _queryLength;
|
||||
QueryType _queryType;
|
||||
|
||||
struct TRI_json_s* _bindParameters;
|
||||
|
||||
QueryError _error;
|
||||
};
|
||||
|
||||
/*
|
||||
typedef struct TRI_aql_context_s {
|
||||
struct TRI_vocbase_s* _vocbase;
|
||||
struct TRI_aql_parser_s* _parser;
|
||||
TRI_aql_statement_list_t* _statements;
|
||||
TRI_aql_error_t _error;
|
||||
TRI_vector_pointer_t _collections;
|
||||
TRI_associative_pointer_t _collectionNames;
|
||||
|
||||
struct {
|
||||
TRI_vector_pointer_t _nodes;
|
||||
TRI_vector_pointer_t _strings;
|
||||
TRI_vector_pointer_t _scopes;
|
||||
}
|
||||
_memory;
|
||||
|
||||
TRI_vector_pointer_t _currentScopes;
|
||||
|
||||
struct {
|
||||
TRI_associative_pointer_t _values;
|
||||
TRI_associative_pointer_t _names;
|
||||
}
|
||||
_parameters;
|
||||
|
||||
const char* _query;
|
||||
|
||||
size_t _variableIndex;
|
||||
size_t _scopeIndex;
|
||||
size_t _subQueries;
|
||||
|
||||
TRI_aql_query_type_e _type;
|
||||
char* _writeCollection;
|
||||
struct TRI_aql_node_t* _writeOptions;
|
||||
|
||||
struct TRI_json_s* _userOptions;
|
||||
bool _fullCount;
|
||||
bool _isCoordinator;
|
||||
}
|
||||
TRI_aql_context_t;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors / destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create and initialize a context
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_aql_context_t* TRI_CreateContextAql (struct TRI_vocbase_s*,
|
||||
const char* const,
|
||||
const size_t,
|
||||
bool,
|
||||
struct TRI_json_s*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief parse & validate the query string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_ValidateQueryContextAql (TRI_aql_context_t* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add bind parameters to the query context
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_BindQueryContextAql (TRI_aql_context_t* const,
|
||||
const struct TRI_json_s* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief perform some AST optimisations
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_OptimiseQueryContextAql (TRI_aql_context_t* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set up all collections used in the query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_SetupCollectionsContextAql (TRI_aql_context_t* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* TRI_RegisterStringAql (TRI_aql_context_t* const,
|
||||
const char* const,
|
||||
const size_t,
|
||||
const bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a combined string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* TRI_RegisterString2Aql (TRI_aql_context_t* const,
|
||||
const char* const,
|
||||
const char* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a combined string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* TRI_RegisterString3Aql (TRI_aql_context_t* const,
|
||||
const char* const,
|
||||
const char* const,
|
||||
const char* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register a node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_RegisterNodeContextAql (TRI_aql_context_t* const,
|
||||
void* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register an error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_SetErrorContextAql (const char* file,
|
||||
int line,
|
||||
TRI_aql_context_t* const,
|
||||
const int,
|
||||
const char* const);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the value of an option variable
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct TRI_json_s* TRI_GetOptionContextAql (TRI_aql_context_t* const,
|
||||
const char*);
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -0,0 +1,149 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Aql, error handling
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Aql/QueryError.h"
|
||||
|
||||
#include "BasicsC/tri-strings.h"
|
||||
|
||||
using namespace triagens::aql;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the error string registered last
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* QueryError::getMessage () const {
|
||||
if (getCode() == TRI_ERROR_NO_ERROR) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (_message == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (_data && (nullptr != strstr(_message, "%s"))) {
|
||||
char buffer[256];
|
||||
|
||||
int written = snprintf(buffer, sizeof(buffer), _message, _data);
|
||||
|
||||
return TRI_DuplicateString2Z(TRI_UNKNOWN_MEM_ZONE, (const char*) &buffer, (size_t) written);
|
||||
}
|
||||
|
||||
return TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, _message);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a formatted query error message
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* QueryError::getContextError (char const* query,
|
||||
size_t queryLength,
|
||||
size_t line,
|
||||
size_t column) const {
|
||||
const char* p;
|
||||
char* q;
|
||||
char* result;
|
||||
char c;
|
||||
// note: line numbers reported by bison/flex start at 1, columns start at 0
|
||||
size_t offset;
|
||||
size_t currentLine = 1;
|
||||
size_t currentColumn = 0;
|
||||
|
||||
TRI_ASSERT(query);
|
||||
|
||||
p = query;
|
||||
while ((c = *p)) {
|
||||
if (currentLine > line || (currentLine >= line && currentColumn >= column)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '\n') {
|
||||
++p;
|
||||
++currentLine;
|
||||
currentColumn = 0;
|
||||
}
|
||||
else if (c == '\r') {
|
||||
++p;
|
||||
++currentLine;
|
||||
currentColumn = 0;
|
||||
|
||||
if (*p == '\n') {
|
||||
++p;
|
||||
}
|
||||
}
|
||||
else {
|
||||
++currentColumn;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
// p is pointing at the position in the query the parse error occurred at
|
||||
TRI_ASSERT(p >= query);
|
||||
|
||||
offset = (size_t) (p - query);
|
||||
|
||||
static int const SNIPPET_LENGTH = 32;
|
||||
static char const* SNIPPET_SUFFIX = "...";
|
||||
|
||||
if (queryLength < offset + SNIPPET_LENGTH) {
|
||||
return TRI_DuplicateString2Z(TRI_UNKNOWN_MEM_ZONE, query + offset, queryLength - offset);
|
||||
}
|
||||
|
||||
q = result = static_cast<char*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE,
|
||||
SNIPPET_LENGTH + strlen(SNIPPET_SUFFIX) + 1, false));
|
||||
|
||||
if (result == nullptr) {
|
||||
// out of memory
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// copy query part
|
||||
memcpy(q, query + offset, SNIPPET_LENGTH);
|
||||
q += SNIPPET_LENGTH;
|
||||
|
||||
// copy ...
|
||||
memcpy(q, SNIPPET_SUFFIX, strlen(SNIPPET_SUFFIX));
|
||||
q += strlen(SNIPPET_SUFFIX);
|
||||
|
||||
*q = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -0,0 +1,92 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Aql, error handling
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
|
||||
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_AQL_QUERYERROR_H
|
||||
#define ARANGODB_AQL_QUERYERROR_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace aql {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief query error structure
|
||||
///
|
||||
/// This struct is used to hold information about errors that happen during
|
||||
/// query execution. The data will be passed to the end user.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct QueryError {
|
||||
|
||||
QueryError ()
|
||||
: _code(TRI_ERROR_NO_ERROR),
|
||||
_data(nullptr) {
|
||||
}
|
||||
|
||||
~QueryError () {
|
||||
if (_data != nullptr) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, _data);
|
||||
}
|
||||
}
|
||||
|
||||
inline int getCode () const {
|
||||
return _code;
|
||||
}
|
||||
|
||||
char* getMessage () const;
|
||||
|
||||
char* getContextError (char const*,
|
||||
size_t,
|
||||
size_t,
|
||||
size_t) const;
|
||||
|
||||
int _code;
|
||||
char* _message;
|
||||
char* _data;
|
||||
const char* _file;
|
||||
int _line;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
|
||||
// End:
|
|
@ -57,6 +57,8 @@ add_executable(
|
|||
Ahuacatl/ahuacatl-statementlist.cpp
|
||||
Ahuacatl/ahuacatl-tokens.cpp
|
||||
Ahuacatl/ahuacatl-variable.cpp
|
||||
Aql/Query.cpp
|
||||
Aql/QueryError.cpp
|
||||
BitIndexes/bitarray.cpp
|
||||
BitIndexes/bitarrayIndex.cpp
|
||||
CapConstraint/cap-constraint.cpp
|
||||
|
|
|
@ -39,6 +39,8 @@ arangod_libarangod_a_SOURCES = \
|
|||
arangod/Ahuacatl/ahuacatl-tokens.cpp \
|
||||
arangod/Ahuacatl/ahuacatl-variable.cpp \
|
||||
arangod/Aql/ExecutionPlan.cpp \
|
||||
arangod/Aql/Query.cpp \
|
||||
arangod/Aql/QueryError.cpp \
|
||||
arangod/BitIndexes/bitarray.cpp \
|
||||
arangod/BitIndexes/bitarrayIndex.cpp \
|
||||
arangod/CapConstraint/cap-constraint.cpp \
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "Ahuacatl/ahuacatl-context.h"
|
||||
#include "Ahuacatl/ahuacatl-explain.h"
|
||||
#include "Ahuacatl/ahuacatl-result.h"
|
||||
#include "Aql/Query.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Basics/Utf8Helper.h"
|
||||
#include "BasicsC/conversions.h"
|
||||
|
@ -5333,6 +5334,54 @@ static v8::Handle<v8::Value> JS_ForgetApplierReplication (v8::Arguments const& a
|
|||
return scope.Close(v8::True());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- AQL
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes an AQL query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static v8::Handle<v8::Value> JS_ExecuteAql (v8::Arguments const& argv) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
if (argv.Length() < 1 || argv.Length() > 3) {
|
||||
TRI_V8_EXCEPTION_USAGE(scope, "AQL_EXECUTE(<querystring>, <bindvalues>, <options>)");
|
||||
}
|
||||
|
||||
TRI_vocbase_t* vocbase = GetContextVocBase();
|
||||
|
||||
if (vocbase == nullptr) {
|
||||
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// get the query string
|
||||
if (! argv[0]->IsString()) {
|
||||
TRI_V8_TYPE_ERROR(scope, "expecting string for <querystring>");
|
||||
}
|
||||
|
||||
string const&& queryString = TRI_ObjectToString(argv[0]);
|
||||
|
||||
// bind parameters
|
||||
TRI_json_t* parameters = nullptr;
|
||||
|
||||
if (argv.Length() > 1 && argv[1]->IsObject()) {
|
||||
parameters = TRI_ObjectToJson(argv[1]);
|
||||
}
|
||||
|
||||
// execute the query
|
||||
std::cout << "ABOUT TO EXECUTE AQL QUERY '" << queryString << "'" << std::endl;
|
||||
|
||||
// bind parameters will be freed by context...
|
||||
triagens::aql::Query query(vocbase, queryString.c_str(), queryString.size(), parameters);
|
||||
|
||||
query.execute();
|
||||
|
||||
v8::Handle<v8::Object> result = v8::Object::New();
|
||||
|
||||
return scope.Close(result);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- AHUACATL
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -10597,6 +10646,9 @@ void TRI_InitV8VocBridge (v8::Handle<v8::Context> context,
|
|||
TRI_AddGlobalFunctionVocbase(context, "AHUACATL_RUN", JS_RunAhuacatl, true);
|
||||
TRI_AddGlobalFunctionVocbase(context, "AHUACATL_EXPLAIN", JS_ExplainAhuacatl, true);
|
||||
TRI_AddGlobalFunctionVocbase(context, "AHUACATL_PARSE", JS_ParseAhuacatl, true);
|
||||
|
||||
// new AQL functions. not intended to be used directly by end users
|
||||
TRI_AddGlobalFunctionVocbase(context, "AQL_EXECUTE", JS_ExecuteAql, true);
|
||||
|
||||
// cursor functions. not intended to be used by end users
|
||||
TRI_AddGlobalFunctionVocbase(context, "CURSOR", JS_Cursor, true);
|
||||
|
|
Loading…
Reference in New Issue