1
0
Fork 0

DML for AQL

This commit is contained in:
Jan Steemann 2014-06-10 09:30:27 +02:00
parent 3f22fa03be
commit d9653bc462
21 changed files with 3069 additions and 1536 deletions

View File

@ -78,6 +78,30 @@
// --SECTION-- private functions
// -----------------------------------------------------------------------------
static void SetWriteOperation (TRI_aql_context_t* context,
TRI_aql_node_t const* collection,
TRI_aql_query_type_e type,
bool ignore) {
if (context->_writeCollection != NULL ||
context->_type != TRI_AQL_QUERY_READ) {
TRI_SetErrorContextAql(__FILE__, __LINE__, context, TRI_ERROR_QUERY_MULTI_MODIFY, NULL);
}
else if (context->_subQueries > 0) {
TRI_SetErrorContextAql(__FILE__, __LINE__, context, TRI_ERROR_QUERY_MODIFY_IN_SUBQUERY, NULL);
}
else {
TRI_aql_node_t* nameNode = TRI_AQL_NODE_MEMBER(collection, 0);
if (nameNode == NULL) {
TRI_SetErrorContextAql(__FILE__, __LINE__, context, TRI_ERROR_OUT_OF_MEMORY, NULL);
}
else {
context->_writeCollection = TRI_AQL_NODE_STRING(nameNode);
context->_writeIgnore = ignore;
context->_type = type;
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST function call node
////////////////////////////////////////////////////////////////////////////////
@ -341,6 +365,74 @@ TRI_aql_node_t* TRI_CreateNodeReturnAql (TRI_aql_context_t* const context,
return node;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST remove node
////////////////////////////////////////////////////////////////////////////////
TRI_aql_node_t* TRI_CreateNodeRemoveAql (TRI_aql_context_t* const context,
const TRI_aql_node_t* const expression,
const TRI_aql_node_t* const collection,
bool ignore) {
CREATE_NODE(TRI_AQL_NODE_REMOVE)
ADD_MEMBER(expression)
SetWriteOperation(context, collection, TRI_AQL_QUERY_REMOVE, ignore);
return node;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST save node
////////////////////////////////////////////////////////////////////////////////
TRI_aql_node_t* TRI_CreateNodeSaveAql (TRI_aql_context_t* const context,
const TRI_aql_node_t* const expression,
const TRI_aql_node_t* const collection,
bool ignore) {
CREATE_NODE(TRI_AQL_NODE_SAVE)
ADD_MEMBER(expression)
SetWriteOperation(context, collection, TRI_AQL_QUERY_SAVE, ignore);
return node;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST update node
////////////////////////////////////////////////////////////////////////////////
TRI_aql_node_t* TRI_CreateNodeUpdateAql (TRI_aql_context_t* const context,
const TRI_aql_node_t* const expression,
const TRI_aql_node_t* const collection,
bool ignore) {
CREATE_NODE(TRI_AQL_NODE_UPDATE)
ADD_MEMBER(expression)
SetWriteOperation(context, collection, TRI_AQL_QUERY_UPDATE, ignore);
return node;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST replace node
////////////////////////////////////////////////////////////////////////////////
TRI_aql_node_t* TRI_CreateNodeReplaceAql (TRI_aql_context_t* const context,
const TRI_aql_node_t* const expression,
const TRI_aql_node_t* const collection,
bool ignore) {
CREATE_NODE(TRI_AQL_NODE_REPLACE)
ADD_MEMBER(expression)
SetWriteOperation(context, collection, TRI_AQL_QUERY_REMOVE, ignore);
return node;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST collect node
////////////////////////////////////////////////////////////////////////////////

View File

@ -97,6 +97,42 @@ TRI_aql_node_t* TRI_CreateNodeFilterAql (struct TRI_aql_context_s* const,
TRI_aql_node_t* TRI_CreateNodeReturnAql (struct TRI_aql_context_s* const,
const TRI_aql_node_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST remove node
////////////////////////////////////////////////////////////////////////////////
TRI_aql_node_t* TRI_CreateNodeRemoveAql (struct TRI_aql_context_s* const,
const TRI_aql_node_t* const,
const TRI_aql_node_t* const,
bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST save node
////////////////////////////////////////////////////////////////////////////////
TRI_aql_node_t* TRI_CreateNodeSaveAql (struct TRI_aql_context_s* const,
const TRI_aql_node_t* const,
const TRI_aql_node_t* const,
bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST update node
////////////////////////////////////////////////////////////////////////////////
TRI_aql_node_t* TRI_CreateNodeUpdateAql (struct TRI_aql_context_s* const,
const TRI_aql_node_t* const,
const TRI_aql_node_t* const,
bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST replace node
////////////////////////////////////////////////////////////////////////////////
TRI_aql_node_t* TRI_CreateNodeReplaceAql (struct TRI_aql_context_s* const,
const TRI_aql_node_t* const,
const TRI_aql_node_t* const,
bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief create an AST collect node
////////////////////////////////////////////////////////////////////////////////

View File

@ -2638,6 +2638,98 @@ static void ProcessReturnEmpty (TRI_aql_codegen_js_t* const generator,
CloseLoops(generator);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate code for remove keyword
////////////////////////////////////////////////////////////////////////////////
static void ProcessRemove (TRI_aql_codegen_js_t* const generator,
const TRI_aql_node_t* const node) {
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
if (scope == NULL) {
return;
}
ScopeOutput(generator, "aql.REMOVE_DOCUMENT(ops, ");
// expression
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0));
ScopeOutput(generator, ");\n");
// }
CloseLoops(generator);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate code for save keyword
////////////////////////////////////////////////////////////////////////////////
static void ProcessSave (TRI_aql_codegen_js_t* const generator,
const TRI_aql_node_t* const node) {
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
if (scope == NULL) {
return;
}
ScopeOutput(generator, "aql.SAVE_DOCUMENT(ops, ");
// expression
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0));
ScopeOutput(generator, ");\n");
// }
CloseLoops(generator);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate code for update keyword
////////////////////////////////////////////////////////////////////////////////
static void ProcessUpdate (TRI_aql_codegen_js_t* const generator,
const TRI_aql_node_t* const node) {
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
if (scope == NULL) {
return;
}
ScopeOutput(generator, "aql.UPDATE_DOCUMENT(ops, ");
// expression
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0));
ScopeOutput(generator, ");\n");
// }
CloseLoops(generator);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate code for replace keyword
////////////////////////////////////////////////////////////////////////////////
static void ProcessReplace (TRI_aql_codegen_js_t* const generator,
const TRI_aql_node_t* const node) {
TRI_aql_codegen_scope_t* scope = CurrentScope(generator);
if (scope == NULL) {
return;
}
ScopeOutput(generator, "aql.UPDATE_DOCUMENT(ops, ");
// expression
ProcessNode(generator, TRI_AQL_NODE_MEMBER(node, 0));
ScopeOutput(generator, ");\n");
// }
CloseLoops(generator);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief generate code for let keyword
////////////////////////////////////////////////////////////////////////////////
@ -2870,6 +2962,18 @@ static void ProcessNode (TRI_aql_codegen_js_t* const generator, const TRI_aql_no
case TRI_AQL_NODE_RETURN:
ProcessReturn(generator, node);
break;
case TRI_AQL_NODE_REMOVE:
ProcessRemove(generator, node);
break;
case TRI_AQL_NODE_SAVE:
ProcessSave(generator, node);
break;
case TRI_AQL_NODE_UPDATE:
ProcessUpdate(generator, node);
break;
case TRI_AQL_NODE_REPLACE:
ProcessReplace(generator, node);
break;
case TRI_AQL_NODE_RETURN_EMPTY:
ProcessReturnEmpty(generator, node);
break;
@ -3012,8 +3116,7 @@ char* TRI_GenerateCodeAql (TRI_aql_context_t* const context,
return NULL;
}
OutputString(&generator->_functionBuffer, "(function () {\nvar aql = require(\"org/arangodb/ahuacatl\"), extra = { };\n");
OutputString(&generator->_functionBuffer, "(function () {\nvar aql = require(\"org/arangodb/ahuacatl\"), extra = { };\nvar ops = [ ];\n");
if (context->_userOptions != NULL && context->_userOptions->_type == TRI_JSON_ARRAY) {
OutputString(&generator->_functionBuffer, "var options = ");
TRI_StringifyJson(&generator->_functionBuffer, context->_userOptions);
@ -3022,12 +3125,44 @@ char* TRI_GenerateCodeAql (TRI_aql_context_t* const context,
resultRegister = CreateCode(generator);
if (context->_type != TRI_AQL_QUERY_READ) {
assert(context->_writeCollection != NULL);
OutputString(&generator->_buffer, "extra.operations = aql.EXECUTE_");
switch (context->_type) {
case TRI_AQL_QUERY_REMOVE:
OutputString(&generator->_buffer, "REMOVE");
break;
case TRI_AQL_QUERY_SAVE:
OutputString(&generator->_buffer, "SAVE");
break;
case TRI_AQL_QUERY_UPDATE:
OutputString(&generator->_buffer, "UPDATE");
break;
case TRI_AQL_QUERY_REPLACE:
OutputString(&generator->_buffer, "REPLACE");
break;
case TRI_AQL_QUERY_READ:
// cannot happen, but the compiler is unhappy otherwise
assert(false);
break;
}
OutputString(&generator->_buffer, "(ops, '");
OutputString(&generator->_buffer, context->_writeCollection);
OutputString(&generator->_buffer, "', ");
OutputString(&generator->_buffer, context->_writeIgnore ? "true" : "false");
OutputString(&generator->_buffer, ");\n");
}
// append result
OutputString(&generator->_buffer, "return {\n");
OutputString(&generator->_buffer, "docs: ");
OutputString(&generator->_buffer, REGISTER_PREFIX);
OutputInt(&generator->_buffer, (int64_t) resultRegister);
OutputString(&generator->_buffer, ",\n");
OutputString(&generator->_buffer, "extra: extra");
OutputString(&generator->_buffer, "\n};\n");

View File

@ -179,11 +179,14 @@ TRI_aql_context_t* TRI_CreateContextAql (TRI_vocbase_t* vocbase,
return NULL;
}
context->_vocbase = vocbase;
context->_userOptions = userOptions;
context->_type = TRI_AQL_QUERY_READ;
context->_vocbase = vocbase;
context->_userOptions = userOptions;
context->_writeCollection = NULL;
context->_variableIndex = 0;
context->_scopeIndex = 0;
context->_subQueries = 0;
// actual bind parameter values
res = TRI_InitAssociativePointer(&context->_parameters._values,

View File

@ -48,6 +48,19 @@ struct TRI_vocbase_s;
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief the type of query to execute
////////////////////////////////////////////////////////////////////////////////
typedef enum {
TRI_AQL_QUERY_READ,
TRI_AQL_QUERY_REMOVE,
TRI_AQL_QUERY_SAVE,
TRI_AQL_QUERY_UPDATE,
TRI_AQL_QUERY_REPLACE
}
TRI_aql_query_type_e;
////////////////////////////////////////////////////////////////////////////////
/// @brief the context for parsing a query
////////////////////////////////////////////////////////////////////////////////
@ -79,10 +92,15 @@ typedef struct TRI_aql_context_s {
size_t _variableIndex;
size_t _scopeIndex;
size_t _subQueries;
TRI_aql_query_type_e _type;
char* _writeCollection;
struct TRI_json_s* _userOptions;
bool _fullCount;
bool _isCoordinator;
bool _writeIgnore;
}
TRI_aql_context_t;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -57,46 +57,52 @@ extern int Ahuacatldebug;
T_DESC = 266,
T_IN = 267,
T_INTO = 268,
T_NULL = 269,
T_TRUE = 270,
T_FALSE = 271,
T_STRING = 272,
T_QUOTED_STRING = 273,
T_INTEGER = 274,
T_DOUBLE = 275,
T_PARAMETER = 276,
T_ASSIGN = 277,
T_NOT = 278,
T_AND = 279,
T_OR = 280,
T_EQ = 281,
T_NE = 282,
T_LT = 283,
T_GT = 284,
T_LE = 285,
T_GE = 286,
T_PLUS = 287,
T_MINUS = 288,
T_TIMES = 289,
T_DIV = 290,
T_MOD = 291,
T_EXPAND = 292,
T_QUESTION = 293,
T_COLON = 294,
T_SCOPE = 295,
T_RANGE = 296,
T_COMMA = 297,
T_OPEN = 298,
T_CLOSE = 299,
T_DOC_OPEN = 300,
T_DOC_CLOSE = 301,
T_LIST_OPEN = 302,
T_LIST_CLOSE = 303,
UMINUS = 304,
UPLUS = 305,
FUNCCALL = 306,
REFERENCE = 307,
INDEXED = 308
T_FROM = 269,
T_IGNORE = 270,
T_REMOVE = 271,
T_SAVE = 272,
T_UPDATE = 273,
T_REPLACE = 274,
T_NULL = 275,
T_TRUE = 276,
T_FALSE = 277,
T_STRING = 278,
T_QUOTED_STRING = 279,
T_INTEGER = 280,
T_DOUBLE = 281,
T_PARAMETER = 282,
T_ASSIGN = 283,
T_NOT = 284,
T_AND = 285,
T_OR = 286,
T_EQ = 287,
T_NE = 288,
T_LT = 289,
T_GT = 290,
T_LE = 291,
T_GE = 292,
T_PLUS = 293,
T_MINUS = 294,
T_TIMES = 295,
T_DIV = 296,
T_MOD = 297,
T_EXPAND = 298,
T_QUESTION = 299,
T_COLON = 300,
T_SCOPE = 301,
T_RANGE = 302,
T_COMMA = 303,
T_OPEN = 304,
T_CLOSE = 305,
T_DOC_OPEN = 306,
T_DOC_CLOSE = 307,
T_LIST_OPEN = 308,
T_LIST_CLOSE = 309,
UMINUS = 310,
UPLUS = 311,
FUNCCALL = 312,
REFERENCE = 313,
INDEXED = 314
};
#endif
@ -112,7 +118,7 @@ union YYSTYPE
bool boolval;
int64_t intval;
#line 116 "arangod/Ahuacatl/ahuacatl-grammar.h" /* yacc.c:1909 */
#line 122 "arangod/Ahuacatl/ahuacatl-grammar.h" /* yacc.c:1909 */
};
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1

View File

@ -71,6 +71,13 @@ void Ahuacatlerror (YYLTYPE* locp, TRI_aql_context_t* const context, const char*
%token T_DESC "DESC keyword"
%token T_IN "IN keyword"
%token T_INTO "INTO keyword"
%token T_FROM "FROM keyword"
%token T_IGNORE "IGNORE hint"
%token T_REMOVE "REMOVE command"
%token T_SAVE "SAVE command"
%token T_UPDATE "UPDATE command"
%token T_REPLACE "REPLACE command"
%token T_NULL "null"
%token T_TRUE "true"
@ -182,6 +189,19 @@ void Ahuacatlerror (YYLTYPE* locp, TRI_aql_context_t* const context, const char*
query:
optional_statement_block_statements return_statement {
context->_type = TRI_AQL_QUERY_READ;
}
| optional_statement_block_statements remove_statement {
context->_type = TRI_AQL_QUERY_REMOVE;
}
| optional_statement_block_statements save_statement {
context->_type = TRI_AQL_QUERY_SAVE;
}
| optional_statement_block_statements update_statement {
context->_type = TRI_AQL_QUERY_UPDATE;
}
| optional_statement_block_statements replace_statement {
context->_type = TRI_AQL_QUERY_REPLACE;
}
;
@ -416,11 +436,196 @@ return_statement:
if (! TRI_EndScopeByReturnAql(context)) {
ABORT_OOM
}
// $$ = node;
}
;
remove_statement:
T_REMOVE expression T_FROM T_STRING {
TRI_aql_node_t* coll;
TRI_aql_node_t* node;
coll = TRI_CreateNodeCollectionAql(context, $4);
if (coll == NULL) {
ABORT_OOM
}
node = TRI_CreateNodeRemoveAql(context, $2, coll, false);
if (node == NULL) {
ABORT_OOM
}
if (! TRI_AppendStatementListAql(context->_statements, node)) {
ABORT_OOM
}
if (! TRI_EndScopeByReturnAql(context)) {
ABORT_OOM
}
}
| T_REMOVE T_IGNORE expression T_FROM T_STRING {
TRI_aql_node_t* coll;
TRI_aql_node_t* node;
coll = TRI_CreateNodeCollectionAql(context, $5);
if (coll == NULL) {
ABORT_OOM
}
node = TRI_CreateNodeRemoveAql(context, $3, coll, true);
if (node == NULL) {
ABORT_OOM
}
if (! TRI_AppendStatementListAql(context->_statements, node)) {
ABORT_OOM
}
if (! TRI_EndScopeByReturnAql(context)) {
ABORT_OOM
}
}
;
save_statement:
T_SAVE expression T_INTO T_STRING {
TRI_aql_node_t* coll;
TRI_aql_node_t* node;
coll = TRI_CreateNodeCollectionAql(context, $4);
if (coll == NULL) {
ABORT_OOM
}
node = TRI_CreateNodeSaveAql(context, $2, coll, false);
if (node == NULL) {
ABORT_OOM
}
if (! TRI_AppendStatementListAql(context->_statements, node)) {
ABORT_OOM
}
if (! TRI_EndScopeByReturnAql(context)) {
ABORT_OOM
}
}
| T_SAVE T_IGNORE expression T_INTO T_STRING {
TRI_aql_node_t* coll;
TRI_aql_node_t* node;
coll = TRI_CreateNodeCollectionAql(context, $5);
if (coll == NULL) {
ABORT_OOM
}
node = TRI_CreateNodeSaveAql(context, $3, coll, true);
if (node == NULL) {
ABORT_OOM
}
if (! TRI_AppendStatementListAql(context->_statements, node)) {
ABORT_OOM
}
if (! TRI_EndScopeByReturnAql(context)) {
ABORT_OOM
}
}
;
update_statement:
T_UPDATE expression T_IN T_STRING {
TRI_aql_node_t* coll;
TRI_aql_node_t* node;
coll = TRI_CreateNodeCollectionAql(context, $4);
if (coll == NULL) {
ABORT_OOM
}
node = TRI_CreateNodeUpdateAql(context, $2, coll, false);
if (node == NULL) {
ABORT_OOM
}
if (! TRI_AppendStatementListAql(context->_statements, node)) {
ABORT_OOM
}
if (! TRI_EndScopeByReturnAql(context)) {
ABORT_OOM
}
}
| T_UPDATE T_IGNORE expression T_IN T_STRING {
TRI_aql_node_t* coll;
TRI_aql_node_t* node;
coll = TRI_CreateNodeCollectionAql(context, $5);
if (coll == NULL) {
ABORT_OOM
}
node = TRI_CreateNodeUpdateAql(context, $3, coll, true);
if (node == NULL) {
ABORT_OOM
}
if (! TRI_AppendStatementListAql(context->_statements, node)) {
ABORT_OOM
}
if (! TRI_EndScopeByReturnAql(context)) {
ABORT_OOM
}
}
;
replace_statement:
T_REPLACE expression T_IN T_STRING {
TRI_aql_node_t* coll;
TRI_aql_node_t* node;
coll = TRI_CreateNodeCollectionAql(context, $4);
if (coll == NULL) {
ABORT_OOM
}
node = TRI_CreateNodeReplaceAql(context, $2, coll, false);
if (node == NULL) {
ABORT_OOM
}
if (! TRI_AppendStatementListAql(context->_statements, node)) {
ABORT_OOM
}
if (! TRI_EndScopeByReturnAql(context)) {
ABORT_OOM
}
}
| T_REPLACE T_IGNORE expression T_IN T_STRING {
TRI_aql_node_t* coll;
TRI_aql_node_t* node;
coll = TRI_CreateNodeCollectionAql(context, $5);
if (coll == NULL) {
ABORT_OOM
}
node = TRI_CreateNodeReplaceAql(context, $3, coll, true);
if (node == NULL) {
ABORT_OOM
}
if (! TRI_AppendStatementListAql(context->_statements, node)) {
ABORT_OOM
}
if (! TRI_EndScopeByReturnAql(context)) {
ABORT_OOM
}
}
;
expression:
T_OPEN expression T_CLOSE {
@ -430,11 +635,16 @@ expression:
if (! TRI_StartScopeAql(context, TRI_AQL_SCOPE_SUBQUERY)) {
ABORT_OOM
}
context->_subQueries++;
} query T_CLOSE {
TRI_aql_node_t* result;
TRI_aql_node_t* subQuery;
TRI_aql_node_t* nameNode;
context->_subQueries--;
if (! TRI_EndScopeAql(context)) {
ABORT_OOM
}

View File

@ -48,7 +48,11 @@ bool TRI_IsTopLevelTypeAql (const TRI_aql_node_type_e type) {
type == TRI_AQL_NODE_SORT ||
type == TRI_AQL_NODE_LIMIT ||
type == TRI_AQL_NODE_COLLECT ||
type == TRI_AQL_NODE_RETURN) {
type == TRI_AQL_NODE_RETURN ||
type == TRI_AQL_NODE_REMOVE ||
type == TRI_AQL_NODE_SAVE ||
type == TRI_AQL_NODE_UPDATE ||
type == TRI_AQL_NODE_REPLACE) {
return true;
}
@ -110,6 +114,14 @@ const char* TRI_NodeNameAql (const TRI_aql_node_type_e type) {
return "filter";
case TRI_AQL_NODE_RETURN:
return "return";
case TRI_AQL_NODE_REMOVE:
return "remove";
case TRI_AQL_NODE_SAVE:
return "save";
case TRI_AQL_NODE_UPDATE:
return "update";
case TRI_AQL_NODE_REPLACE:
return "replace";
case TRI_AQL_NODE_COLLECT:
return "collect";
case TRI_AQL_NODE_SORT:

View File

@ -142,6 +142,10 @@ typedef enum {
TRI_AQL_NODE_LET,
TRI_AQL_NODE_FILTER,
TRI_AQL_NODE_RETURN,
TRI_AQL_NODE_REMOVE,
TRI_AQL_NODE_SAVE,
TRI_AQL_NODE_UPDATE,
TRI_AQL_NODE_REPLACE,
TRI_AQL_NODE_COLLECT,
TRI_AQL_NODE_SORT,
TRI_AQL_NODE_SORT_ELEMENT,

File diff suppressed because it is too large Load Diff

View File

@ -96,6 +96,30 @@
return T_INTO;
}
(?i:FROM) {
return T_FROM;
}
(?i:REMOVE) {
return T_REMOVE;
}
(?i:SAVE) {
return T_SAVE;
}
(?i:UPDATE) {
return T_UPDATE;
}
(?i:REPLACE) {
return T_REPLACE;
}
(?i:IGNORE) {
return T_IGNORE;
}
/* ---------------------------------------------------------------------------
* predefined type literals
* --------------------------------------------------------------------------- */

View File

@ -53,11 +53,6 @@ namespace triagens {
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////
public:
////////////////////////////////////////////////////////////////////////////////
@ -66,14 +61,15 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
AhuacatlTransaction (struct TRI_vocbase_s* vocbase,
TRI_aql_context_t* context) :
Transaction<T>(vocbase, TRI_GetIdServer(), false) {
TRI_aql_context_t* context)
: Transaction<T>(vocbase, TRI_GetIdServer(), false),
_context(context) {
this->addHint(TRI_TRANSACTION_HINT_LOCK_ENTIRELY);
TRI_vector_pointer_t* collections = &context->_collections;
const size_t n = collections->_length;
size_t const n = collections->_length;
for (size_t i = 0; i < n; ++i) {
TRI_aql_collection_t* collection = (TRI_aql_collection_t*) TRI_AtVectorPointer(collections, i);
@ -109,7 +105,7 @@ namespace triagens {
void processCollectionCoordinator (TRI_aql_collection_t* collection) {
TRI_voc_cid_t cid = this->resolver()->getCollectionIdCluster(collection->_name);
this->addCollection(cid, collection->_name, TRI_TRANSACTION_READ);
this->addCollection(cid, collection->_name, getCollectionAccessType(collection));
}
////////////////////////////////////////////////////////////////////////////////
@ -120,21 +116,41 @@ namespace triagens {
TRI_vocbase_col_t const* col = this->resolver()->getCollectionStruct(collection->_name);
TRI_voc_cid_t cid = 0;
if (col != 0) {
if (col != nullptr) {
cid = col->_cid;
}
int res = this->addCollection(cid, collection->_name, TRI_TRANSACTION_READ);
int res = this->addCollection(cid, collection->_name, getCollectionAccessType(collection));
if (res == TRI_ERROR_NO_ERROR && col != 0) {
if (res == TRI_ERROR_NO_ERROR && col != nullptr) {
collection->_collection = const_cast<TRI_vocbase_col_t*>(col);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @}
/// @brief determine the access type (read | write) for a collection
////////////////////////////////////////////////////////////////////////////////
TRI_transaction_type_e getCollectionAccessType (TRI_aql_collection_t const* collection) const {
if (_context->_type == TRI_AQL_QUERY_READ ||
(_context->_writeCollection != nullptr &&
strcmp(collection->_name, _context->_writeCollection) != 0)) {
// read-only query or write-query with a different write-to collection
return TRI_TRANSACTION_READ;
}
// data-modifying query
return TRI_TRANSACTION_WRITE;
}
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
private:
TRI_aql_context_t* _context;
};
}

View File

@ -3364,11 +3364,18 @@ static v8::Handle<v8::Value> ExecuteQueryNativeAhuacatl (TRI_aql_context_t* cont
v8::String::New(code, (int) codeLength),
TRI_V8_SYMBOL("query"),
false);
trx.finish(TRI_ERROR_NO_ERROR);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, code);
if (result.IsEmpty()) {
// force a rollback
trx.abort();
}
else {
// commit / finish
trx.finish(TRI_ERROR_NO_ERROR);
}
// return the result as a javascript array
return scope.Close(result);
}

View File

@ -169,6 +169,8 @@
"ERROR_QUERY_GEO_INDEX_MISSING" : { "code" : 1570, "message" : "no suitable geo index found for geo restriction on '%s'" },
"ERROR_QUERY_FULLTEXT_INDEX_MISSING" : { "code" : 1571, "message" : "no suitable fulltext index found for fulltext query on '%s'" },
"ERROR_QUERY_INVALID_DATE_VALUE" : { "code" : 1572, "message" : "invalid date value" },
"ERROR_QUERY_MULTI_MODIFY" : { "code" : 1573, "message" : "multi-modify query" },
"ERROR_QUERY_MODIFY_IN_SUBQUERY" : { "code" : 1574, "message" : "modify in subquery" },
"ERROR_QUERY_FUNCTION_INVALID_NAME" : { "code" : 1580, "message" : "invalid user function name" },
"ERROR_QUERY_FUNCTION_INVALID_CODE" : { "code" : 1581, "message" : "invalid user function code" },
"ERROR_QUERY_FUNCTION_NOT_FOUND" : { "code" : 1582, "message" : "user function '%s()' not found" },
@ -207,12 +209,8 @@
"ERROR_GRAPH_COULD_NOT_CHANGE_EDGE" : { "code" : 1908, "message" : "could not change edge" },
"ERROR_GRAPH_TOO_MANY_ITERATIONS" : { "code" : 1909, "message" : "too many iterations" },
"ERROR_GRAPH_INVALID_FILTER_RESULT" : { "code" : 1910, "message" : "invalid filter result" },
"ERROR_GRAPH_COLLECTION_MULTI_USE" : { "code" : 1920, "message" : "an edge collection may only be used once in one edge definition of a graph." },
"ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS" : { "code" : 1921, "message" : " is already used by another graph in a different edge definition." },
"ERROR_GRAPH_CREATE_MISSING_NAME" : { "code" : 1922, "message" : "a graph name is required to create a graph." },
"ERROR_GRAPH_CREATE_MISSING_EDGE_DEFINITION" : { "code" : 1923, "message" : "at least one edge definition is required to create a graph." },
"ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
"ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
"SIMPLE_CLIENT_UNKNOWN_ERROR" : { "code" : 2000, "message" : "unknown client error" },
"SIMPLE_CLIENT_COULD_NOT_CONNECT" : { "code" : 2001, "message" : "could not connect to server" },
"SIMPLE_CLIENT_COULD_NOT_WRITE" : { "code" : 2002, "message" : "could not write to server" },

View File

@ -169,6 +169,8 @@
"ERROR_QUERY_GEO_INDEX_MISSING" : { "code" : 1570, "message" : "no suitable geo index found for geo restriction on '%s'" },
"ERROR_QUERY_FULLTEXT_INDEX_MISSING" : { "code" : 1571, "message" : "no suitable fulltext index found for fulltext query on '%s'" },
"ERROR_QUERY_INVALID_DATE_VALUE" : { "code" : 1572, "message" : "invalid date value" },
"ERROR_QUERY_MULTI_MODIFY" : { "code" : 1573, "message" : "multi-modify query" },
"ERROR_QUERY_MODIFY_IN_SUBQUERY" : { "code" : 1574, "message" : "modify in subquery" },
"ERROR_QUERY_FUNCTION_INVALID_NAME" : { "code" : 1580, "message" : "invalid user function name" },
"ERROR_QUERY_FUNCTION_INVALID_CODE" : { "code" : 1581, "message" : "invalid user function code" },
"ERROR_QUERY_FUNCTION_NOT_FOUND" : { "code" : 1582, "message" : "user function '%s()' not found" },
@ -207,12 +209,8 @@
"ERROR_GRAPH_COULD_NOT_CHANGE_EDGE" : { "code" : 1908, "message" : "could not change edge" },
"ERROR_GRAPH_TOO_MANY_ITERATIONS" : { "code" : 1909, "message" : "too many iterations" },
"ERROR_GRAPH_INVALID_FILTER_RESULT" : { "code" : 1910, "message" : "invalid filter result" },
"ERROR_GRAPH_COLLECTION_MULTI_USE" : { "code" : 1920, "message" : "an edge collection may only be used once in one edge definition of a graph." },
"ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS" : { "code" : 1921, "message" : " is already used by another graph in a different edge definition." },
"ERROR_GRAPH_CREATE_MISSING_NAME" : { "code" : 1922, "message" : "a graph name is required to create a graph." },
"ERROR_GRAPH_CREATE_MISSING_EDGE_DEFINITION" : { "code" : 1923, "message" : "at least one edge definition is required to create a graph." },
"ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
"ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
"SIMPLE_CLIENT_UNKNOWN_ERROR" : { "code" : 2000, "message" : "unknown client error" },
"SIMPLE_CLIENT_COULD_NOT_CONNECT" : { "code" : 2001, "message" : "could not connect to server" },
"SIMPLE_CLIENT_COULD_NOT_WRITE" : { "code" : 2002, "message" : "could not write to server" },
@ -222,7 +220,6 @@
"ERROR_ARANGO_INDEX_BITARRAY_INSERT_ITEM_UNSUPPORTED_VALUE" : { "code" : 3413, "message" : "bitarray index insert failure - document attribute value unsupported in index" },
"ERROR_ARANGO_INDEX_BITARRAY_CREATION_FAILURE_DUPLICATE_ATTRIBUTES" : { "code" : 3415, "message" : "bitarray index creation failure - one or more index attributes are duplicated." },
"ERROR_ARANGO_INDEX_BITARRAY_CREATION_FAILURE_DUPLICATE_VALUES" : { "code" : 3417, "message" : "bitarray index creation failure - one or more index attribute values are duplicated." },
"ERROR_APP_ALREADY_EXISTS" : { "code": 4000, "message": "App is already installed" },
"RESULT_KEY_EXISTS" : { "code" : 10000, "message" : "element not inserted into structure, because key already exists" },
"RESULT_ELEMENT_EXISTS" : { "code" : 10001, "message" : "element not inserted into structure, because it already exists" },
"RESULT_KEY_NOT_FOUND" : { "code" : 10002, "message" : "key not found in structure" },

View File

@ -465,6 +465,166 @@ function COMPILE_REGEX (regex, modifiers) {
return new RegExp('^' + pattern + '$', modifiers);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief remove a document
////////////////////////////////////////////////////////////////////////////////
function REMOVE_DOCUMENT (ops, document) {
"use strict";
var weight = TYPEWEIGHT(document);
if (weight === TYPEWEIGHT_STRING) {
ops.push(document);
return;
}
if (weight === TYPEWEIGHT_DOCUMENT &&
document.hasOwnProperty("_key")) {
ops.push(document._key);
return;
}
THROW(INTERNAL.errors.ERROR_ARANGO_DOCUMENT_KEY_MISSING);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief save a document
////////////////////////////////////////////////////////////////////////////////
function SAVE_DOCUMENT (ops, document) {
"use strict";
if (TYPEWEIGHT(document) === TYPEWEIGHT_DOCUMENT) {
ops.push(document);
return;
}
THROW(INTERNAL.errors.ERROR_ARANGO_DOCUMENT_TYPE_INVALID);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief update a document
////////////////////////////////////////////////////////////////////////////////
function UPDATE_DOCUMENT (ops, document) {
"use strict";
if (TYPEWEIGHT(document) === TYPEWEIGHT_DOCUMENT &&
document.hasOwnProperty("_key")) {
ops.push(document);
return;
}
THROW(INTERNAL.errors.ERROR_ARANGO_DOCUMENT_KEY_MISSING);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief execute buffered remove operations
////////////////////////////////////////////////////////////////////////////////
function EXECUTE_REMOVE (ops, collection, ignore) {
var removed = 0, i, n = ops.length, c = COLLECTION(collection);
if (ignore) {
for (i = 0; i < n; ++i) {
try {
c.remove(ops[i]);
++removed;
}
catch (err) {
}
}
}
else {
for (i = 0; i < n; ++i) {
c.remove(ops[i]);
++removed;
}
}
return { total: n, executed: removed };
}
////////////////////////////////////////////////////////////////////////////////
/// @brief execute buffered save operations
////////////////////////////////////////////////////////////////////////////////
function EXECUTE_SAVE (ops, collection, ignore) {
var saved = 0, i, n = ops.length, c = COLLECTION(collection);
if (ignore) {
for (i = 0; i < n; ++i) {
try {
c.save(ops[i]);
++saved;
}
catch (err) {
}
}
}
else {
for (i = 0; i < n; ++i) {
c.save(ops[i]);
++saved;
}
}
return { total: n, executed: saved };
}
////////////////////////////////////////////////////////////////////////////////
/// @brief execute buffered update operations
////////////////////////////////////////////////////////////////////////////////
function EXECUTE_UPDATE (ops, collection, ignore) {
var updated = 0, i, n = ops.length, c = COLLECTION(collection);
if (ignore) {
for (i = 0; i < n; ++i) {
try {
c.update(ops[i]._key, ops[i]);
++updated;
}
catch (err) {
}
}
}
else {
for (i = 0; i < n; ++i) {
c.update(ops[i]._key, ops[i]);
++updated;
}
}
return { total: n, executed: updated };
}
////////////////////////////////////////////////////////////////////////////////
/// @brief execute buffered replace operations
////////////////////////////////////////////////////////////////////////////////
function EXECUTE_REPLACE (ops, collection, ignore) {
var replaced = 0, i, n = ops.length, c = COLLECTION(collection);
if (ignore) {
for (i = 0; i < n; ++i) {
try {
c.replace(ops[i]._key, ops[i]);
++replaced;
}
catch (err) {
}
}
}
else {
for (i = 0; i < n; ++i) {
c.replace(ops[i]._key, ops[i]);
++replaced;
}
}
return { total: n, executed: removed };
}
////////////////////////////////////////////////////////////////////////////////
/// @brief call a function
////////////////////////////////////////////////////////////////////////////////
@ -5680,6 +5840,13 @@ function GENERAL_GRAPH_DIAMETER (graphName, options) {
// --SECTION-- MODULE EXPORTS
// -----------------------------------------------------------------------------
exports.REMOVE_DOCUMENT = REMOVE_DOCUMENT;
exports.SAVE_DOCUMENT = SAVE_DOCUMENT;
exports.UPDATE_DOCUMENT = UPDATE_DOCUMENT;
exports.EXECUTE_REMOVE = EXECUTE_REMOVE;
exports.EXECUTE_SAVE = EXECUTE_SAVE;
exports.EXECUTE_UPDATE = EXECUTE_UPDATE;
exports.EXECUTE_REPLACE = EXECUTE_REPLACE;
exports.FCALL = FCALL;
exports.FCALL_USER = FCALL_USER;
exports.KEYS = KEYS;

View File

@ -209,6 +209,8 @@ ERROR_QUERY_FAIL_CALLED,1569,"FAIL(%s) called","Will be raised when the function
ERROR_QUERY_GEO_INDEX_MISSING,1570,"no suitable geo index found for geo restriction on '%s'","Will be raised when a geo restriction was specified but no suitable geo index is found to resolve it."
ERROR_QUERY_FULLTEXT_INDEX_MISSING,1571,"no suitable fulltext index found for fulltext query on '%s'","Will be raised when a fulltext query is performed on a collection without a suitable fulltext index."
ERROR_QUERY_INVALID_DATE_VALUE,1572,"invalid date value","Will be raised when a value cannot be converted to a date."
ERROR_QUERY_MULTI_MODIFY,1573,"multi-modify query", "Will be raised when an AQL query contains more than one data-modifying operation."
ERROR_QUERY_MODIFY_IN_SUBQUERY,1574,"modify in subquery", "Will be raised when an AQL query contains a data-modifying operation inside a subquery."
################################################################################
## AQL user functions

View File

@ -165,6 +165,8 @@ void TRI_InitialiseErrorMessages (void) {
REG_ERROR(ERROR_QUERY_GEO_INDEX_MISSING, "no suitable geo index found for geo restriction on '%s'");
REG_ERROR(ERROR_QUERY_FULLTEXT_INDEX_MISSING, "no suitable fulltext index found for fulltext query on '%s'");
REG_ERROR(ERROR_QUERY_INVALID_DATE_VALUE, "invalid date value");
REG_ERROR(ERROR_QUERY_MULTI_MODIFY, "multi-modify query");
REG_ERROR(ERROR_QUERY_MODIFY_IN_SUBQUERY, "modify in subquery");
REG_ERROR(ERROR_QUERY_FUNCTION_INVALID_NAME, "invalid user function name");
REG_ERROR(ERROR_QUERY_FUNCTION_INVALID_CODE, "invalid user function code");
REG_ERROR(ERROR_QUERY_FUNCTION_NOT_FOUND, "user function '%s()' not found");

View File

@ -395,6 +395,12 @@ extern "C" {
/// a suitable fulltext index.
/// - 1572: @LIT{invalid date value}
/// Will be raised when a value cannot be converted to a date.
/// - 1573: @LIT{multi-modify query}
/// "Will be raised when an AQL query contains more than one data-modifying
/// operation."
/// - 1574: @LIT{modify in subquery}
/// "Will be raised when an AQL query contains a data-modifying operation
/// inside a subquery."
/// - 1580: @LIT{invalid user function name}
/// Will be raised when a user function with an invalid name is registered.
/// - 1581: @LIT{invalid user function code}
@ -2142,6 +2148,28 @@ void TRI_InitialiseErrorMessages (void);
#define TRI_ERROR_QUERY_INVALID_DATE_VALUE (1572)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1573: ERROR_QUERY_MULTI_MODIFY
///
/// multi-modify query
///
/// "Will be raised when an AQL query contains more than one data-modifying
/// operation."
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_QUERY_MULTI_MODIFY (1573)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1574: ERROR_QUERY_MODIFY_IN_SUBQUERY
///
/// modify in subquery
///
/// "Will be raised when an AQL query contains a data-modifying operation
/// inside a subquery."
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_QUERY_MODIFY_IN_SUBQUERY (1574)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1580: ERROR_QUERY_FUNCTION_INVALID_NAME
///