diff --git a/arangod/V8Server/v8-query.cpp b/arangod/V8Server/v8-query.cpp index 13ccb0debd..be74e0e485 100644 --- a/arangod/V8Server/v8-query.cpp +++ b/arangod/V8Server/v8-query.cpp @@ -253,7 +253,7 @@ static int SetupExampleObject (v8::Handle const example, values[i] = TRI_ShapedJsonV8Object(isolate, val, shaper, false); - if (values[i] == 0) { + if (values[i] == nullptr) { CleanupExampleObject(shaper->_memoryZone, i, pids, values); return TRI_RESULT_ELEMENT_NOT_FOUND; } diff --git a/js/Makefile.files b/js/Makefile.files index e5731849ab..c723a47add 100644 --- a/js/Makefile.files +++ b/js/Makefile.files @@ -27,7 +27,9 @@ JAVASCRIPT_BROWSER = \ js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/arango-statement-common.js \ js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/graph-common.js \ js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/graph/traversal.js \ + js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/aql/explainer.js \ js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/aql/functions.js \ + js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/aql/queries.js \ js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/mimetypes.js \ js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/replication.js \ js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/simple-query-common.js \ diff --git a/js/apps/system/_admin/aardvark/APP/GruntFile.js b/js/apps/system/_admin/aardvark/APP/GruntFile.js index c1e54a839a..b0ff8e8210 100644 --- a/js/apps/system/_admin/aardvark/APP/GruntFile.js +++ b/js/apps/system/_admin/aardvark/APP/GruntFile.js @@ -64,7 +64,9 @@ "frontend/js/shell/browser.js", "frontend/js/config/dygraphConfig.js", "frontend/js/modules/underscore.js", + "frontend/js/modules/org/arangodb/aql/explainer.js", "frontend/js/modules/org/arangodb/aql/functions.js", + "frontend/js/modules/org/arangodb/aql/queries.js", "frontend/js/modules/org/arangodb/graph/traversal.js", "frontend/js/modules/org/arangodb/arango-collection-common.js", "frontend/js/modules/org/arangodb/arango-collection.js", diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/client/.client.js.swp b/js/apps/system/_admin/aardvark/APP/frontend/js/client/.client.js.swp new file mode 100644 index 0000000000..a4aac741a0 Binary files /dev/null and b/js/apps/system/_admin/aardvark/APP/frontend/js/client/.client.js.swp differ diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/aql/explainer.js b/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/aql/explainer.js new file mode 100644 index 0000000000..fd87cdcb6c --- /dev/null +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/aql/explainer.js @@ -0,0 +1,608 @@ +module.define("org/arangodb/aql/explainer", function(exports, module) { +/*jshint strict: false, maxlen: 300 */ +/*global require, exports */ + +var db = require("org/arangodb").db, + internal = require("internal"), + systemColors = internal.COLORS, + print = internal.print, + colors = { }; + +if (typeof internal.printBrowser === "function") { + print = internal.printBrowser; +} + +/* set colors for output */ +function setColors (useSystemColors) { + "use strict"; + + [ "COLOR_RESET", + "COLOR_CYAN", "COLOR_BLUE", "COLOR_GREEN", "COLOR_MAGENTA", "COLOR_YELLOW", "COLOR_RED", "COLOR_WHITE", + "COLOR_BOLD_CYAN", "COLOR_BOLD_BLUE", "COLOR_BOLD_GREEN", "COLOR_BOLD_MAGENTA", "COLOR_BOLD_YELLOW", + "COLOR_BOLD_RED", "COLOR_BOLD_WHITE" ].forEach(function(c) { + colors[c] = useSystemColors ? systemColors[c] : ""; + }); +} + +/* colorizer and output helper functions */ + +function passthru (v) { + "use strict"; + return v; +} + +function keyword (v) { + "use strict"; + return colors.COLOR_CYAN + v + colors.COLOR_RESET; +} + +function annotation (v) { + "use strict"; + return colors.COLOR_BLUE + v + colors.COLOR_RESET; +} + +function value (v) { + "use strict"; + return colors.COLOR_GREEN + v + colors.COLOR_RESET; +} + +function variable (v) { + "use strict"; + if (v[0] === "#") { + return colors.COLOR_MAGENTA + v + colors.COLOR_RESET; + } + return colors.COLOR_YELLOW + v + colors.COLOR_RESET; +} + +function func (v) { + "use strict"; + return colors.COLOR_GREEN + v + colors.COLOR_RESET; +} + +function collection (v) { + "use strict"; + return colors.COLOR_RED + v + colors.COLOR_RESET; +} + +function attribute (v) { + "use strict"; + return "`" + colors.COLOR_YELLOW + v + colors.COLOR_RESET + "`"; +} + +function header (v) { + "use strict"; + return colors.COLOR_MAGENTA + v + colors.COLOR_RESET; +} + +function section (v) { + "use strict"; + return colors.COLOR_BOLD_BLUE + v + colors.COLOR_RESET; +} + +function pad (n) { + "use strict"; + return new Array(n).join(" "); +} + +function wrap (str, width) { + "use strict"; + var re = ".{1," + width + "}(\\s|$)|\\S+?(\\s|$)"; + return str.match(new RegExp(re, "g")).join("\n"); +} + + +/* print functions */ + +/* print query string */ +function printQuery (query) { + "use strict"; + print(section("Query string:")); + print(" " + value(wrap(query, 100).replace(/\n/g, "\n ", query))); + print(); +} + +/* print write query modification flags */ +function printModificationFlags (flags) { + "use strict"; + if (flags === undefined) { + return; + } + print(section("Write query options:")); + var keys = Object.keys(flags), maxLen = "Option".length; + keys.forEach(function(k) { + if (k.length > maxLen) { + maxLen = k.length; + } + }); + print(" " + header("Option") + pad(1 + maxLen - "Option".length) + " " + header("Value")); + keys.forEach(function(k) { + print(" " + keyword(k) + pad(1 + maxLen - k.length) + " " + value(JSON.stringify(flags[k]))); + }); + print(); +} + +/* print optimizer rules */ +function printRules (rules) { + "use strict"; + print(section("Optimization rules applied:")); + if (rules.length === 0) { + print(" " + value("none")); + } + else { + var maxIdLen = String("Id").length; + print(" " + pad(1 + maxIdLen - String("Id").length) + header("Id") + " " + header("RuleName")); + for (var i = 0; i < rules.length; ++i) { + print(" " + pad(1 + maxIdLen - String(i + 1).length) + variable(String(i + 1)) + " " + keyword(rules[i])); + } + } + print(); +} + +/* print warnings */ +function printWarnings (warnings) { + "use strict"; + if (! Array.isArray(warnings) || warnings.length === 0) { + return; + } + + print(section("Warnings:")); + var maxIdLen = String("Code").length; + print(" " + pad(1 + maxIdLen - String("Code").length) + header("Code") + " " + header("Message")); + for (var i = 0; i < warnings.length; ++i) { + print(" " + pad(1 + maxIdLen - String(warnings[i].code).length) + variable(warnings[i].code) + " " + keyword(warnings[i].message)); + } + print(); +} + +/* print indexes used */ +function printIndexes (indexes) { + "use strict"; + print(section("Indexes used:")); + if (indexes.length === 0) { + print(" " + value("none")); + } + else { + var maxIdLen = String("Id").length; + var maxCollectionLen = String("Collection").length; + var maxUniqueLen = String("Unique").length; + var maxSparseLen = String("Sparse").length; + var maxTypeLen = String("Type").length; + var maxSelectivityLen = String("Selectivity Est.").length; + var maxFieldsLen = String("Fields").length; + indexes.forEach(function(index) { + var l = String(index.node).length; + if (l > maxIdLen) { + maxIdLen = l; + } + l = index.type.length; + if (l > maxTypeLen) { + maxTypeLen = l; + } + l = index.fields.map(passthru).join(", ").length; + if (l > maxFieldsLen) { + maxFieldsLen = l; + } + l = index.collection.length; + if (l > maxCollectionLen) { + maxCollectionLen = l; + } + }); + var line = " " + pad(1 + maxIdLen - String("Id").length) + header("Id") + " " + + header("Type") + pad(1 + maxTypeLen - "Type".length) + " " + + header("Collection") + pad(1 + maxCollectionLen - "Collection".length) + " " + + header("Unique") + pad(1 + maxUniqueLen - "Unique".length) + " " + + header("Sparse") + pad(1 + maxSparseLen - "Sparse".length) + " " + + header("Selectivity Est.") + " " + + header("Fields") + pad(1 + maxFieldsLen - "Fields".length) + " " + + header("Ranges"); + print(line); + + for (var i = 0; i < indexes.length; ++i) { + var uniqueness = (indexes[i].unique ? "true" : "false"); + var sparsity = (indexes[i].hasOwnProperty("sparse") ? (indexes[i].sparse ? "true" : "false") : "n/a"); + var fields = indexes[i].fields.map(attribute).join(", "); + var fieldsLen = indexes[i].fields.map(passthru).join(", ").length; + var ranges = "[ " + indexes[i].ranges + " ]"; + var selectivity = (indexes[i].hasOwnProperty("selectivityEstimate") ? + (indexes[i].selectivityEstimate * 100).toFixed(2) + " %" : + "n/a" + ); + line = " " + + pad(1 + maxIdLen - String(indexes[i].node).length) + variable(String(indexes[i].node)) + " " + + keyword(indexes[i].type) + pad(1 + maxTypeLen - indexes[i].type.length) + " " + + collection(indexes[i].collection) + pad(1 + maxCollectionLen - indexes[i].collection.length) + " " + + value(uniqueness) + pad(1 + maxUniqueLen - uniqueness.length) + " " + + value(sparsity) + pad(1 + maxSparseLen - sparsity.length) + " " + + pad(1 + maxSelectivityLen - selectivity.length) + value(selectivity) + " " + + fields + pad(1 + maxFieldsLen - fieldsLen) + " " + + ranges; + print(line); + } + } + print(); +} + +/* analzye and print execution plan */ +function processQuery (query, explain) { + "use strict"; + var nodes = { }, + parents = { }, + rootNode = null, + maxTypeLen = 0, + maxIdLen = String("Id").length, + maxEstimateLen = String("Est.").length, + plan = explain.plan; + + var recursiveWalk = function (n, level) { + n.forEach(function(node) { + nodes[node.id] = node; + if (level === 0 && node.dependencies.length === 0) { + rootNode = node.id; + } + if (node.type === "SubqueryNode") { + recursiveWalk(node.subquery.nodes, level + 1); + } + node.dependencies.forEach(function(d) { + if (! parents.hasOwnProperty(d)) { + parents[d] = [ ]; + } + parents[d].push(node.id); + }); + + if (String(node.id).length > maxIdLen) { + maxIdLen = String(node.id).length; + } + if (String(node.type).length > maxTypeLen) { + maxTypeLen = String(node.type).length; + } + if (String(node.estimatedNrItems).length > maxEstimateLen) { + maxEstimateLen = String(node.estimatedNrItems).length; + } + }); + }; + recursiveWalk(plan.nodes, 0); + + var references = { }, + collectionVariables = { }, + usedVariables = { }, + indexes = [ ], + modificationFlags, + isConst = true; + + var variableName = function (node) { + if (/^[0-9_]/.test(node.name)) { + return variable("#" + node.name); + } + + if (collectionVariables.hasOwnProperty(node.id)) { + usedVariables[node.name] = collectionVariables[node.id]; + } + return variable(node.name); + }; + + var buildExpression = function (node) { + isConst = isConst && ([ "value", "object", "object element", "array" ].indexOf(node.type) !== -1); + + switch (node.type) { + case "reference": + if (references.hasOwnProperty(node.name)) { + return buildExpression(references[node.name]) + "[*]"; + } + return variableName(node); + case "collection": + return collection(node.name) + " " + annotation("/* all collection documents */"); + case "value": + return value(JSON.stringify(node.value)); + case "object": + if (node.hasOwnProperty("subNodes")) { + return "{ " + node.subNodes.map(buildExpression).join(", ") + " }"; + } + return "{ }"; + case "object element": + return value(JSON.stringify(node.name)) + " : " + buildExpression(node.subNodes[0]); + case "array": + if (node.hasOwnProperty("subNodes")) { + return "[ " + node.subNodes.map(buildExpression).join(", ") + " ]"; + } + return "[ ]"; + case "unary not": + return "! " + buildExpression(node.subNodes[0]); + case "unary plus": + return "+ " + buildExpression(node.subNodes[0]); + case "unary minus": + return "- " + buildExpression(node.subNodes[0]); + case "attribute access": + return buildExpression(node.subNodes[0]) + "." + attribute(node.name); + case "indexed access": + return buildExpression(node.subNodes[0]) + "[" + buildExpression(node.subNodes[1]) + "]"; + case "range": + return buildExpression(node.subNodes[0]) + " .. " + buildExpression(node.subNodes[1]) + " " + annotation("/* range */"); + case "expand": + references[node.subNodes[0].subNodes[0].name] = node.subNodes[0].subNodes[1]; + return buildExpression(node.subNodes[1]); + case "user function call": + return func(node.name) + "(" + ((node.subNodes && node.subNodes[0].subNodes) || [ ]).map(buildExpression).join(", ") + ")" + " " + annotation("/* user-defined function */"); + case "function call": + return func(node.name) + "(" + ((node.subNodes && node.subNodes[0].subNodes) || [ ]).map(buildExpression).join(", ") + ")"; + case "plus": + return buildExpression(node.subNodes[0]) + " + " + buildExpression(node.subNodes[1]); + case "minus": + return buildExpression(node.subNodes[0]) + " - " + buildExpression(node.subNodes[1]); + case "times": + return buildExpression(node.subNodes[0]) + " * " + buildExpression(node.subNodes[1]); + case "division": + return buildExpression(node.subNodes[0]) + " / " + buildExpression(node.subNodes[1]); + case "modulus": + return buildExpression(node.subNodes[0]) + " % " + buildExpression(node.subNodes[1]); + case "compare not in": + return buildExpression(node.subNodes[0]) + " not in " + buildExpression(node.subNodes[1]); + case "compare in": + return buildExpression(node.subNodes[0]) + " in " + buildExpression(node.subNodes[1]); + case "compare ==": + return buildExpression(node.subNodes[0]) + " == " + buildExpression(node.subNodes[1]); + case "compare !=": + return buildExpression(node.subNodes[0]) + " != " + buildExpression(node.subNodes[1]); + case "compare >": + return buildExpression(node.subNodes[0]) + " > " + buildExpression(node.subNodes[1]); + case "compare >=": + return buildExpression(node.subNodes[0]) + " >= " + buildExpression(node.subNodes[1]); + case "compare <": + return buildExpression(node.subNodes[0]) + " < " + buildExpression(node.subNodes[1]); + case "compare <=": + return buildExpression(node.subNodes[0]) + " <= " + buildExpression(node.subNodes[1]); + case "logical or": + return buildExpression(node.subNodes[0]) + " || " + buildExpression(node.subNodes[1]); + case "logical and": + return buildExpression(node.subNodes[0]) + " && " + buildExpression(node.subNodes[1]); + case "ternary": + return buildExpression(node.subNodes[0]) + " ? " + buildExpression(node.subNodes[1]) + " : " + buildExpression(node.subNodes[2]); + default: + return "unhandled node type (" + node.type + ")"; + } + }; + + var buildBound = function (attr, operators, bound) { + var boundValue = bound.isConstant ? value(JSON.stringify(bound.bound)) : buildExpression(bound.bound); + return attribute(attr) + " " + operators[bound.include ? 1 : 0] + " " + boundValue; + }; + + var buildRanges = function (ranges) { + var results = [ ]; + ranges.forEach(function(range) { + var attr = range.attr; + + if (range.lowConst.hasOwnProperty("bound") && range.highConst.hasOwnProperty("bound") && + JSON.stringify(range.lowConst.bound) === JSON.stringify(range.highConst.bound)) { + range.equality = true; + } + + if (range.equality) { + if (range.lowConst.hasOwnProperty("bound")) { + results.push(buildBound(attr, [ "==", "==" ], range.lowConst)); + } + else if (range.hasOwnProperty("lows")) { + range.lows.forEach(function(bound) { + results.push(buildBound(attr, [ "==", "==" ], bound)); + }); + } + } + else { + if (range.lowConst.hasOwnProperty("bound")) { + results.push(buildBound(attr, [ ">", ">=" ], range.lowConst)); + } + if (range.highConst.hasOwnProperty("bound")) { + results.push(buildBound(attr, [ "<", "<=" ], range.highConst)); + } + if (range.hasOwnProperty("lows")) { + range.lows.forEach(function(bound) { + results.push(buildBound(attr, [ ">", ">=" ], bound)); + }); + } + if (range.hasOwnProperty("highs")) { + range.highs.forEach(function(bound) { + results.push(buildBound(attr, [ "<", "<=" ], bound)); + }); + } + } + }); + if (results.length > 1) { + return "(" + results.join(" && ") + ")"; + } + return results[0]; + }; + + + var label = function (node) { + switch (node.type) { + case "SingletonNode": + return keyword("ROOT"); + case "NoResultsNode": + return keyword("EMPTY") + " " + annotation("/* empty result set */"); + case "EnumerateCollectionNode": + collectionVariables[node.outVariable.id] = node.collection; + return keyword("FOR") + " " + variableName(node.outVariable) + " " + keyword("IN") + " " + collection(node.collection) + " " + annotation("/* full collection scan" + (node.random ? ", random order" : "") + " */"); + case "EnumerateListNode": + return keyword("FOR") + " " + variableName(node.outVariable) + " " + keyword("IN") + " " + variableName(node.inVariable) + " " + annotation("/* list iteration */"); + case "IndexRangeNode": + collectionVariables[node.outVariable.id] = node.collection; + var index = node.index; + index.ranges = node.ranges.map(buildRanges).join(" || "); + index.collection = node.collection; + index.node = node.id; + indexes.push(index); + return keyword("FOR") + " " + variableName(node.outVariable) + " " + keyword("IN") + " " + collection(node.collection) + " " + annotation("/* " + (node.reverse ? "reverse " : "") + node.index.type + " index scan") + annotation("*/"); + case "CalculationNode": + return keyword("LET") + " " + variableName(node.outVariable) + " = " + buildExpression(node.expression); + case "FilterNode": + return keyword("FILTER") + " " + variableName(node.inVariable); + case "AggregateNode": + return keyword("COLLECT") + " " + node.aggregates.map(function(node) { + return variableName(node.outVariable) + " = " + variableName(node.inVariable); + }).join(", ") + + (node.count ? " " + keyword("WITH COUNT") : "") + + (node.outVariable ? " " + keyword("INTO") + " " + variableName(node.outVariable) : "") + + (node.keepVariables ? " " + keyword("KEEP") + " " + node.keepVariables.map(function(variable) { return variableName(variable); }).join(", ") : ""); + case "SortNode": + return keyword("SORT") + " " + node.elements.map(function(node) { + return variableName(node.inVariable) + " " + keyword(node.ascending ? "ASC" : "DESC"); + }).join(", "); + case "LimitNode": + return keyword("LIMIT") + " " + value(JSON.stringify(node.offset)) + ", " + value(JSON.stringify(node.limit)); + case "ReturnNode": + return keyword("RETURN") + " " + variableName(node.inVariable); + case "SubqueryNode": + return keyword("LET") + " " + variableName(node.outVariable) + " = ... " + annotation("/* subquery */"); + case "InsertNode": + modificationFlags = node.modificationFlags; + return keyword("INSERT") + " " + variableName(node.inVariable) + " " + keyword("IN") + " " + collection(node.collection); + case "UpdateNode": + modificationFlags = node.modificationFlags; + if (node.hasOwnProperty("inKeyVariable")) { + return keyword("UPDATE") + " " + variableName(node.inKeyVariable) + " " + keyword("WITH") + " " + variableName(node.inDocVariable) + " " + keyword("IN") + " " + collection(node.collection); + } + return keyword("UPDATE") + " " + variableName(node.inDocVariable) + " " + keyword("IN") + " " + collection(node.collection); + case "ReplaceNode": + modificationFlags = node.modificationFlags; + if (node.hasOwnProperty("inKeyVariable")) { + return keyword("REPLACE") + " " + variableName(node.inKeyVariable) + " " + keyword("WITH") + " " + variableName(node.inDocVariable) + " " + keyword("IN") + " " + collection(node.collection); + } + return keyword("REPLACE") + " " + variableName(node.inDocVariable) + " " + keyword("IN") + " " + collection(node.collection); + case "UpsertNode": + modificationFlags = node.modificationFlags; + return keyword("UPSERT") + " " + variableName(node.inDocVariable) + " " + keyword("INSERT") + " " + variableName(node.insertVariable) + " " + keyword(node.isReplace ? "REPLACE" : "UPDATE") + variableName(node.updateVariable) + " " + keyword("IN") + " " + collection(node.collection); + case "RemoveNode": + modificationFlags = node.modificationFlags; + return keyword("REMOVE") + " " + variableName(node.inVariable) + " " + keyword("IN") + " " + collection(node.collection); + case "RemoteNode": + return keyword("REMOTE"); + case "DistributeNode": + return keyword("DISTRIBUTE"); + case "ScatterNode": + return keyword("SCATTER"); + case "GatherNode": + return keyword("GATHER"); + } + + return "unhandled node type (" + node.type + ")"; + }; + + var level = 0, subqueries = [ ]; + var indent = function (level, isRoot) { + return pad(1 + level + level) + (isRoot ? "* " : "- "); + }; + + var preHandle = function (node) { + usedVariables = { }; + isConst = true; + if (node.type === "SubqueryNode") { + subqueries.push(level); + } + }; + + var postHandle = function (node) { + if ([ "EnumerateCollectionNode", + "EnumerateListNode", + "IndexRangeNode", + "SubqueryNode" ].indexOf(node.type) !== -1) { + level++; + } + else if (node.type === "ReturnNode" && subqueries.length > 0) { + level = subqueries.pop(); + } + else if (node.type === "SingletonNode") { + level++; + } + }; + + var constNess = function () { + if (isConst) { + return " " + annotation("/* const assignment */"); + } + return ""; + }; + + var variablesUsed = function () { + var used = [ ]; + for (var a in usedVariables) { + if (usedVariables.hasOwnProperty(a)) { + used.push(variable(a) + " : " + collection(usedVariables[a])); + } + } + if (used.length > 0) { + return " " + annotation("/* collections used:") + " " + used.join(", ") + " " + annotation("*/"); + } + return ""; + }; + + var printNode = function (node) { + preHandle(node); + var line = " " + + pad(1 + maxIdLen - String(node.id).length) + variable(node.id) + " " + + keyword(node.type) + pad(1 + maxTypeLen - String(node.type).length) + " " + + pad(1 + maxEstimateLen - String(node.estimatedNrItems).length) + value(node.estimatedNrItems) + " " + + indent(level, node.type === "SingletonNode") + label(node); + + if (node.type === "CalculationNode") { + line += variablesUsed() + constNess(); + } + print(line); + postHandle(node); + }; + + printQuery(query); + + print(section("Execution plan:")); + + var line = " " + + pad(1 + maxIdLen - String("Id").length) + header("Id") + " " + + header("NodeType") + pad(1 + maxTypeLen - String("NodeType").length) + " " + + pad(1 + maxEstimateLen - String("Est.").length) + header("Est.") + " " + + header("Comment"); + print(line); + + + var walk = [ rootNode ]; + while (walk.length > 0) { + var id = walk.pop(); + var node = nodes[id]; + printNode(node); + if (parents.hasOwnProperty(id)) { + walk = walk.concat(parents[id]); + } + if (node.type === "SubqueryNode") { + walk = walk.concat([ node.subquery.nodes[0].id ]); + } + } + + print(); + + printIndexes(indexes); + printRules(plan.rules); + printModificationFlags(modificationFlags); + printWarnings(explain.warnings); +} + +/* the exposed function */ +function explain (data, options) { + "use strict"; + if (typeof data === "string") { + data = { query: data }; + } + if (! (data instanceof Object)) { + throw "ArangoStatement needs initial data"; + } + + options = options || { }; + setColors(options.colors === undefined ? true : options.colors); + + var stmt = db._createStatement(data); + var result = stmt.explain(options); + + print(); + processQuery(data.query, result); + print(); +} + +exports.explain = explain; + +}); diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/aql/queries.js b/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/aql/queries.js new file mode 100644 index 0000000000..e511d921b8 --- /dev/null +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/aql/queries.js @@ -0,0 +1,135 @@ +module.define("org/arangodb/aql/queries", function(exports, module) { +/*global require, exports */ + +//////////////////////////////////////////////////////////////////////////////// +/// @brief AQL query management +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2012 triagens GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is triAGENS GmbH, Cologne, Germany +/// +/// @author Jan Steemann +/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +var internal = require("internal"); +var arangosh = require("org/arangodb/arangosh"); + +// ----------------------------------------------------------------------------- +// --SECTION-- module "org/arangodb/aql/queries" +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief clears the slow query log +//////////////////////////////////////////////////////////////////////////////// + +exports.clearSlow = function () { + 'use strict'; + + var db = internal.db; + + var requestResult = db._connection.DELETE("/_api/query/slow", ""); + arangosh.checkRequestResult(requestResult); + + return requestResult; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief returns the slow queries +//////////////////////////////////////////////////////////////////////////////// + +exports.slow = function () { + 'use strict'; + + var db = internal.db; + + var requestResult = db._connection.GET("/_api/query/slow", ""); + arangosh.checkRequestResult(requestResult); + + return requestResult; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief returns the current queries +//////////////////////////////////////////////////////////////////////////////// + +exports.current = function () { + 'use strict'; + + var db = internal.db; + + var requestResult = db._connection.GET("/_api/query/current", ""); + arangosh.checkRequestResult(requestResult); + + return requestResult; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief configures the query tracking properties +//////////////////////////////////////////////////////////////////////////////// + +exports.properties = function (config) { + 'use strict'; + + var db = internal.db; + + var requestResult; + if (config === undefined) { + requestResult = db._connection.GET("/_api/query/properties"); + } + else { + requestResult = db._connection.PUT("/_api/query/properties", + JSON.stringify(config)); + } + + arangosh.checkRequestResult(requestResult); + + return requestResult; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief kills a query +//////////////////////////////////////////////////////////////////////////////// + +exports.kill = function (id) { + 'use strict'; + + if (typeof id === 'object' && + id.hasOwnProperty('id')) { + id = id.id; + } + + var db = internal.db; + + var requestResult = db._connection.DELETE("/_api/query/" + encodeURIComponent(id), ""); + arangosh.checkRequestResult(requestResult); + + return requestResult; +}; + +// ----------------------------------------------------------------------------- +// --SECTION-- END-OF-FILE +// ----------------------------------------------------------------------------- + +// Local Variables: +// mode: outline-minor +// outline-regexp: "/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\|/\\*jslint" +// End: + +});