use of org.datanucleus.store.query.QueryCompilerSyntaxException in project datanucleus-core by datanucleus.
the class JPQLParser method parseVariables.
/* (non-Javadoc)
* @see org.datanucleus.query.compiler.Parser#parseVariables(java.lang.String)
*/
public Node[][] parseVariables(String expression) {
lexer = new Lexer(expression, paramPrefixes, false);
List nodes = new ArrayList();
do {
processPrimary();
if (stack.isEmpty()) {
throw new QueryCompilerSyntaxException("expected identifier", lexer.getIndex(), lexer.getInput());
}
if (!processIdentifier()) {
throw new QueryCompilerSyntaxException("expected identifier", lexer.getIndex(), lexer.getInput());
}
Node nodeVariable = stack.pop();
Node nodeType = stack.pop();
nodes.add(new Node[] { nodeType, nodeVariable });
} while (lexer.parseString(";"));
return (Node[][]) nodes.toArray(new Node[nodes.size()][2]);
}
use of org.datanucleus.store.query.QueryCompilerSyntaxException in project datanucleus-core by datanucleus.
the class JPQLParser method processCreator.
/**
* Method to parse "new a.b.c(param1[,param2], ...)" and create a Node of type CREATOR.
* The Node at the top of the stack after this call will have any arguments defined in its "properties".
* @return whether method syntax was found.
*/
private boolean processCreator() {
if (lexer.parseStringIgnoreCase("NEW ")) {
// "new MyClass(arg1, arg2)"
int size = stack.size();
if (!processMethod()) {
if (!processIdentifier()) {
throw new QueryCompilerSyntaxException("Identifier expected", lexer.getIndex(), lexer.getInput());
}
// run function on literals or identifiers e.g. "primary.runMethod(arg)"
while (lexer.parseChar('.')) {
if (processMethod()) {
// "a.method(...)"
} else if (processIdentifier()) {
// "a.field"
} else {
throw new QueryCompilerSyntaxException("Identifier expected", lexer.getIndex(), lexer.getInput());
}
}
}
while (stack.size() - 1 > size) {
Node top = stack.pop();
Node peek = stack.peek();
peek.insertChildNode(top);
}
Node node = stack.pop();
Node newNode = new Node(NodeType.CREATOR);
newNode.insertChildNode(node);
stack.push(newNode);
return true;
}
return false;
}
use of org.datanucleus.store.query.QueryCompilerSyntaxException in project datanucleus-core by datanucleus.
the class JPQLParser method processInExpression.
/**
* Convenience handler to parse an IN expression.
* Expression is typically of the form "{expression} IN (expr1 [,expr2 [,expr3]] | subquery)".
* Can generate a node tree like
* <pre>({expression} == expr1) || ({expression} == expr2) || ({expression} == expr3)</pre>
* depending on the precise situation.
* @param not Whether this is an expression "NOT IN"
*/
private void processInExpression(boolean not) {
// The left hand side expression
Node inputNode = stack.pop();
boolean usesType = false;
if (inputNode.getNodeType() == NodeType.TYPE) {
usesType = true;
}
if (!lexer.parseChar('(')) {
// "{expr} IN value" : Subquery/Parameter
processPrimary();
Node subqueryNode = stack.pop();
Node inNode;
if (usesType) {
// "TYPE(p) IN :collectionClasses". Convert TYPE into "(p instanceof :collectionClasses)"
inNode = new Node(NodeType.OPERATOR, "instanceof");
inNode.appendChildNode(inputNode.getFirstChild());
inNode.appendChildNode(subqueryNode);
if (not) {
Node notNode = new Node(NodeType.OPERATOR, "!");
notNode.appendChildNode(inNode);
inNode = notNode;
}
} else {
inNode = new Node(NodeType.OPERATOR, not ? "NOT IN" : "IN");
inNode.appendChildNode(inputNode);
inNode.appendChildNode(subqueryNode);
}
stack.push(inNode);
return;
}
List<Node> valueNodes = new ArrayList();
do {
// "IN ((literal|parameter) [, (literal|parameter)])"
processPrimary();
if (stack.peek() == null) {
throw new QueryCompilerSyntaxException("Expected literal|parameter but got " + lexer.remaining(), lexer.getIndex(), lexer.getInput());
}
// Generate node for comparison with this value
Node valueNode = stack.pop();
valueNodes.add(valueNode);
lexer.skipWS();
} while (lexer.parseChar(','));
if (!lexer.parseChar(')')) {
throw new QueryCompilerSyntaxException("Expected: ')' but got " + lexer.remaining(), lexer.getIndex(), lexer.getInput());
} else if (valueNodes.isEmpty()) {
throw new QueryCompilerSyntaxException("IN expression had zero arguments!");
}
if (usesType) {
// "TYPE(a) in (b1,b2,b3)". Convert TYPE into "a instanceof (b1,b2,b3)"
Node inNode = new Node(NodeType.OPERATOR, "instanceof");
inNode.appendChildNode(inputNode.getFirstChild());
for (Node valueNode : valueNodes) {
inNode.appendChildNode(valueNode);
}
if (not) {
Node notNode = new Node(NodeType.OPERATOR, "!");
notNode.appendChildNode(inNode);
inNode = notNode;
}
stack.push(inNode);
return;
}
// Create the returned Node representing this IN expression
Node inNode = null;
Node firstValueNode = valueNodes.get(0);
if (valueNodes.size() == 1 && firstValueNode.getNodeType() != NodeType.LITERAL) {
// Compile as (input IN val)
// Note that we exclude LITERAL single args from here since they can be represented using ==, and also RDBMS needs that currently TODO Fix RDBMS query processor
inNode = new Node(NodeType.OPERATOR, not ? "NOT IN" : "IN");
inNode.appendChildNode(inputNode);
inNode.appendChildNode(valueNodes.get(0));
} else {
// TODO Would be nice to do as (input IN (val1, val2, ...)) but that implies changes in datastore query processors
for (Node valueNode : valueNodes) {
Node compareNode = new Node(NodeType.OPERATOR, not ? "!=" : "==");
compareNode.appendChildNode(inputNode);
compareNode.appendChildNode(valueNode);
if (inNode == null) {
inNode = compareNode;
} else {
Node newInNode = new Node(NodeType.OPERATOR, not ? "&&" : "||");
newInNode.appendChildNode(inNode);
newInNode.appendChildNode(compareNode);
inNode = newInNode;
}
}
}
stack.push(inNode);
}
use of org.datanucleus.store.query.QueryCompilerSyntaxException in project datanucleus-core by datanucleus.
the class JPQLParser method processPrimary.
/**
* Parses the primary. First look for a literal (e.g. "text"), then an identifier(e.g. variable).
* In the next step, call a function, if executing a function, on the literal or the identifier found.
*/
protected void processPrimary() {
String subqueryKeyword = null;
Node subqueryNode = null;
// Process all syntax that cannot chain off subfield references from
if (lexer.parseStringIgnoreCase("SOME ")) {
subqueryKeyword = "SOME";
// subquery variable
processExpression();
subqueryNode = stack.pop();
} else if (lexer.parseStringIgnoreCase("ALL ")) {
subqueryKeyword = "ALL";
// subquery variable
processExpression();
subqueryNode = stack.pop();
} else if (lexer.parseStringIgnoreCase("ANY ")) {
subqueryKeyword = "ANY";
// subquery variable
processExpression();
subqueryNode = stack.pop();
} else if (lexer.parseStringIgnoreCase("EXISTS ")) {
subqueryKeyword = "EXISTS";
// subquery variable
processExpression();
subqueryNode = stack.pop();
}
if (subqueryKeyword != null && subqueryNode != null) {
Node subNode = new Node(NodeType.SUBQUERY, subqueryKeyword);
subNode.appendChildNode(subqueryNode);
stack.push(subNode);
return;
}
if (!strict) {
// Series of user-convenience methods that are not part of strict JPQL
if (lexer.parseStringIgnoreCase("COUNT(*)")) {
// Convert to a method call of COUNTSTAR
Node node = new Node(NodeType.INVOKE, "COUNTSTAR");
stack.push(node);
return;
} else if (// Some people put "()" in JPQL
lexer.parseStringIgnoreCase("CURRENT_DATE()")) {
// Convert to a method call of CURRENT_DATE
Node node = new Node(NodeType.INVOKE, "CURRENT_DATE");
stack.push(node);
return;
} else if (// Some people put "()" in JPQL
lexer.parseStringIgnoreCase("CURRENT_TIMESTAMP()")) {
// Convert to a method call
Node node = new Node(NodeType.INVOKE, "CURRENT_TIMESTAMP");
stack.push(node);
return;
} else if (// Some people put "()" in JPQL
lexer.parseStringIgnoreCase("CURRENT_TIME()")) {
// Convert to a method call
Node node = new Node(NodeType.INVOKE, "CURRENT_TIME");
stack.push(node);
return;
}
}
if (lexer.parseStringIgnoreCase("CURRENT_DATE")) {
// Convert to a method call
Node node = new Node(NodeType.INVOKE, "CURRENT_DATE");
stack.push(node);
return;
} else if (lexer.parseStringIgnoreCase("CURRENT_TIMESTAMP")) {
// Convert to a method call
Node node = new Node(NodeType.INVOKE, "CURRENT_TIMESTAMP");
stack.push(node);
return;
} else if (lexer.parseStringIgnoreCase("CURRENT_TIME")) {
// Convert to a method call
Node node = new Node(NodeType.INVOKE, "CURRENT_TIME");
stack.push(node);
return;
} else if (lexer.parseStringIgnoreCase("CASE ")) {
processCaseExpression();
return;
} else if (lexer.parseStringIgnoreCase("DISTINCT ")) {
// Aggregates can have "count(DISTINCT field1)"
Node distinctNode = new Node(NodeType.OPERATOR, "DISTINCT");
processExpression();
Node identifierNode = stack.pop();
distinctNode.appendChildNode(identifierNode);
stack.push(distinctNode);
return;
} else if (lexer.peekStringIgnoreCase("TREAT(")) {
// So we don't get interpreted as a method. Processed later
} else if (// TODO Can we chain fields/methods off a KEY ?
processKey()) {
return;
} else if (// TODO Can we chain fields/methods off a VALUE ?
processValue()) {
return;
} else if (processEntry()) {
return;
} else if (processCreator() || processLiteral() || processMethod()) {
return;
}
int sizeBeforeBraceProcessing = stack.size();
boolean braceProcessing = false;
if (lexer.parseChar('(')) {
// "({expr1})"
processExpression();
if (!lexer.parseChar(')')) {
throw new QueryCompilerSyntaxException("expected ')'", lexer.getIndex(), lexer.getInput());
}
if (!lexer.parseChar('.')) {
// TODO If we have a cast, then apply to the current node (with the brackets)
return;
}
// Has follow on expression "({expr1}).{expr2}" so continue
braceProcessing = true;
}
// We will have an identifier (variable, parameter, or field of candidate class)
if (processTreat()) {
} else if (processMethod()) {
} else if (processIdentifier()) {
} else {
throw new QueryCompilerSyntaxException("Method/Identifier expected", lexer.getIndex(), lexer.getInput());
}
// Save the stack size just before this component for use later in squashing all nodes
// down to a single Node in the stack with all others chained off from it
int size = stack.size();
if (braceProcessing) {
size = sizeBeforeBraceProcessing + 1;
}
// -> node (IDENTIFIER) with child (IDENTIFIER), with child (IDENTIFIER), with child (IDENTIFIER)
while (lexer.parseChar('.')) {
if (processMethod()) {
// "a.method()" Note this is invalid in JPQL, where they have FUNCTIONs, but we allow it
} else if (processIdentifier()) {
// "a.field"
} else {
throw new QueryCompilerSyntaxException("Identifier expected", lexer.getIndex(), lexer.getInput());
}
}
// +--- Node[IDENTIFIER, c]
while (// Nodes added
stack.size() > size) {
Node top = stack.pop();
Node peek = stack.peek();
Node lastDescendant = getLastDescendantNodeForNode(peek);
if (lastDescendant != null) {
lastDescendant.appendChildNode(top);
} else {
// The peek node has multiple children, so cannot just put the top Node after the last child
Node primNode = new Node(NodeType.PRIMARY);
primNode.appendChildNode(peek);
primNode.appendChildNode(top);
// Remove "peek" node and replace with primNode
stack.pop();
stack.push(primNode);
}
}
}
use of org.datanucleus.store.query.QueryCompilerSyntaxException in project tests by datanucleus.
the class JPQLCompilerTest method testFromInExpressionErroneousPrimary.
/**
* Tests for from clause with an "IN(...) alias" expression with an invalid primary.
*/
public void testFromInExpressionErroneousPrimary() {
JavaQueryCompiler compiler = null;
try {
compiler = new JPQLCompiler(nucCtx, nucCtx.getClassLoaderResolver(null), Department.class.getName() + " d," + "IN(d.products) n", null, null, null, null, null, null, null, null, null, null);
compiler.compile(new HashMap(), null);
fail("Was expecting QueryCompilerSyntaxException but compilation worked");
} catch (QueryCompilerSyntaxException qcse) {
// Expected
}
}
Aggregations