1
0
Fork 0

Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2

Conflicts:
	arangod/Makefile.files
This commit is contained in:
Max Neunhoeffer 2014-07-24 11:50:48 +02:00
commit 934c1df189
7 changed files with 1162 additions and 0 deletions

600
arangod/Aql/Query.cpp Normal file
View File

@ -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:

265
arangod/Aql/Query.h Normal file
View File

@ -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:

149
arangod/Aql/QueryError.cpp Normal file
View File

@ -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:

92
arangod/Aql/QueryError.h Normal file
View File

@ -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:

View File

@ -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

View File

@ -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 \

View File

@ -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);