You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2009/05/07 12:09:36 UTC

svn commit: r772583 - /jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql2/Parser.java

Author: thomasm
Date: Thu May  7 10:09:35 2009
New Revision: 772583

URL: http://svn.apache.org/viewvc?rev=772583&view=rev
Log:
JCR-1104: JSR 283 support / SQL2 parser (upgrade to the current spec)

Modified:
    jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql2/Parser.java

Modified: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql2/Parser.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql2/Parser.java?rev=772583&r1=772582&r2=772583&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql2/Parser.java (original)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql2/Parser.java Thu May  7 10:09:35 2009
@@ -100,7 +100,6 @@
      * @return the query object model
      * @throws RepositoryException if parsing failed
      */
-    // Page 125
     public QueryObjectModel createQueryObjectModel(String query) throws RepositoryException {
         initialize(query);
         selectors = new ArrayList<Selector>();
@@ -124,18 +123,16 @@
         return factory.createQuery(source, constraint, orderings, columnArray);
     }
 
-    // Page 127
     private Selector parseSelector() throws RepositoryException {
         String nodeTypeName = readName();
         if (readIf("AS")) {
             String selectorName = readName();
             return factory.selector(nodeTypeName, selectorName);
         } else {
-            return factory.selector(nodeTypeName, null /* TODO */);
+            return factory.selector(nodeTypeName, nodeTypeName);
         }
     }
 
-    // Page 128
     private String readName() throws RepositoryException {
         if (readIf("[")) {
             if (currentTokenType == VALUE) {
@@ -163,7 +160,6 @@
         }
     }
 
-    // Page 129
     private Source parseSource() throws RepositoryException {
         Selector selector = parseSelector();
         selectors.add(selector);
@@ -191,7 +187,6 @@
         return source;
     }
 
-    // Page 130
     private JoinCondition parseJoinCondition() throws RepositoryException {
         boolean identifier = currentTokenType == IDENTIFIER;
         String name = readName();
@@ -204,7 +199,8 @@
                 if (readIf(",")) {
                     c = factory.sameNodeJoinCondition(selector1, selector2, readPath());
                 } else {
-                    c = factory.sameNodeJoinCondition(selector1, selector2, null /* TODO */);
+                    // TODO verify "." is correct
+                    c = factory.sameNodeJoinCondition(selector1, selector2, ".");
                 }
             } else if ("ISCHILDNODE".equals(name)) {
                 String childSelector = readName();
@@ -230,7 +226,6 @@
         }
     }
 
-    // Page 136
     private Constraint parseConstraint() throws RepositoryException {
         Constraint a = parseAnd();
         while (readIf("OR")) {
@@ -247,7 +242,6 @@
         return a;
     }
 
-    // Page 138
     private Constraint parseCondition() throws RepositoryException {
         Constraint a;
         if (readIf("NOT")) {
@@ -266,7 +260,7 @@
             } else if (readIf(".")) {
                 a = parseCondition(factory.propertyValue(identifier, readName()));
             } else {
-                a = parseCondition(factory.propertyValue(identifier, null /* TODO */));
+                a = parseCondition(factory.propertyValue(getOnlySelectorName(), identifier));
             }
         } else {
             throw getSyntaxError();
@@ -274,7 +268,6 @@
         return a;
     }
 
-    // Page 141
     private Constraint parseCondition(DynamicOperand left) throws RepositoryException {
         Constraint c;
         if (readIf("=")) {
@@ -295,7 +288,7 @@
             boolean not = readIf("NOT");
             read("NULL");
             if (!(left instanceof PropertyValue)) {
-                this.getSyntaxError("propertyName (NOT NULL is only supported for properties)");
+                throw getSyntaxError("propertyName (NOT NULL is only supported for properties)");
             }
             PropertyValue p = (PropertyValue) left;
             c = getPropertyExistence(p);
@@ -324,14 +317,9 @@
     }
 
     private PropertyExistence getPropertyExistence(PropertyValue p) throws InvalidQueryException, RepositoryException {
-        if (p.getSelectorName() == null) {
-            return factory.propertyExistence(p.getPropertyName(), null /* TODO */);
-        } else {
-            return factory.propertyExistence(p.getSelectorName(), p.getPropertyName());
-        }
+        return factory.propertyExistence(p.getSelectorName(), p.getPropertyName());
     }
 
-    // Page 144
     private Constraint parseConditionFuntionIf(String functionName) throws RepositoryException {
         Constraint c;
         if ("CONTAINS".equals(functionName)) {
@@ -348,28 +336,28 @@
                 }
             } else {
                 read(",");
-                c = factory.fullTextSearch(name, readString(), null /* TODO */);
+                c = factory.fullTextSearch(getOnlySelectorName(), name, readString());
             }
         } else if ("ISSAMENODE".equals(functionName)) {
             String name = readName();
             if (readIf(",")) {
                 c = factory.sameNode(name, readPath());
             } else {
-                c = factory.sameNode(name, null /* TODO */);
+                c = factory.sameNode(getOnlySelectorName(), name);
             }
         } else if ("ISCHILDNODE".equals(functionName)) {
             String name = readName();
             if (readIf(",")) {
                 c = factory.childNode(name, readPath());
             } else {
-                c = factory.childNode(name, null /* TODO */);
+                c = factory.childNode(getOnlySelectorName(), name);
             }
         } else if ("ISDESCENDANTNODE".equals(functionName)) {
             String name = readName();
             if (readIf(",")) {
                 c = factory.descendantNode(name, readPath());
             } else {
-                c = factory.descendantNode(name, null /* TODO */);
+                c = factory.descendantNode(getOnlySelectorName(), name);
             }
         } else {
             return null;
@@ -378,12 +366,10 @@
         return c;
     }
 
-    // Page 148
     private String readPath() throws RepositoryException {
         return readName();
     }
 
-    // Page 149
     private DynamicOperand parseDynamicOperand() throws RepositoryException {
         boolean identifier = currentTokenType == IDENTIFIER;
         String name = readName();
@@ -400,19 +386,19 @@
             op = factory.length(parsePropertyValue(readName()));
         } else if ("NAME".equals(functionName)) {
             if (isToken(")")) {
-                op = factory.nodeName(null /* TODO */);
+                op = factory.nodeName(getOnlySelectorName());
             } else {
                 op = factory.nodeName(readName());
             }
         } else if ("LOCALNAME".equals(functionName)) {
             if (isToken(")")) {
-                op = factory.nodeLocalName(null /* TODO */);
+                op = factory.nodeLocalName(getOnlySelectorName());
             } else {
                 op = factory.nodeLocalName(readName());
             }
         } else if ("SCORE".equals(functionName)) {
             if (isToken(")")) {
-                op = factory.fullTextSearchScore(null /* TODO */);
+                op = factory.fullTextSearchScore(getOnlySelectorName());
             } else {
                 op = factory.fullTextSearchScore(readName());
             }
@@ -421,22 +407,20 @@
         } else if ("UPPER".equals(functionName)) {
             op = factory.upperCase(parseDynamicOperand());
         } else {
-            throw getSyntaxError("LENGTH, NAME, LOCALNAME, SCORE, LOWER, or UPPER");
+            throw getSyntaxError("LENGTH, NAME, LOCALNAME, SCORE, LOWER, UPPER, or CAST");
         }
         read(")");
         return op;
     }
 
-    // Page 150
     private PropertyValue parsePropertyValue(String name) throws RepositoryException {
         if (readIf(".")) {
             return factory.propertyValue(name, readName());
         } else {
-            return factory.propertyValue(name, null /* TODO */);
+            return factory.propertyValue(getOnlySelectorName(), name);
         }
     }
 
-    // Page 155
     private StaticOperand parseStaticOperand() throws RepositoryException {
         if (currentTokenType == PLUS) {
             read();
@@ -445,13 +429,22 @@
             if (currentTokenType != VALUE) {
                 throw getSyntaxError("number");
             }
-            if (currentValue.getType() == PropertyType.LONG) {
+            int valueType = currentValue.getType();
+            switch (valueType) {
+            case PropertyType.LONG:
                 currentValue = valueFactory.createValue(-currentValue.getLong());
-            } else if (currentValue.getType() == PropertyType.DOUBLE) {
+                break;
+            case PropertyType.DOUBLE:
                 currentValue = valueFactory.createValue(-currentValue.getDouble());
-            } else {
-                // TODO decimal
-                throw getSyntaxError("number");
+                break;
+            case PropertyType.BOOLEAN:
+                currentValue = valueFactory.createValue(!currentValue.getBoolean());
+                break;
+            case PropertyType.DECIMAL:
+                currentValue = valueFactory.createValue(currentValue.getDecimal().negate());
+                break;
+            default:
+                throw getSyntaxError("Illegal operation: -" + currentValue);
             }
         }
         if (currentTokenType == VALUE) {
@@ -473,12 +466,64 @@
         } else if (readIf("FALSE")) {
             Literal literal = factory.literal(valueFactory.createValue(false));
             return literal;
+        } else if (readIf("CAST")) {
+            read("(");
+            StaticOperand op = parseStaticOperand();
+            if (!(op instanceof Literal)) {
+                throw getSyntaxError("literal");
+            }
+            Literal literal = (Literal) op;
+            Value value = literal.getLiteralValue();
+            read("AS");
+            value = parseCastAs(value);
+            read(")");
+            literal = factory.literal(value);
+            return literal;
         } else {
             throw getSyntaxError("static operand");
         }
     }
+    
+    private Value parseCastAs(Value value) throws RepositoryException {
+        if (readIf("STRING")) {
+            return valueFactory.createValue(value.getString());
+        } else if(readIf("BINARY")) {
+            // TODO getBinary
+            return valueFactory.createValue(value.getString());
+        } else if(readIf("DATE")) {
+            // TODO getDate
+            return valueFactory.createValue(value.getString());
+        } else if(readIf("LONG")) {
+            // TODO getLong
+            return valueFactory.createValue(value.getString());
+        } else if(readIf("DOUBLE")) {
+            // TODO getDouble
+            return valueFactory.createValue(value.getString());
+        } else if(readIf("DECIMAL")) {
+            // TODO getDecimal
+            return valueFactory.createValue(value.getString());
+        } else if(readIf("BOOLEAN")) {
+            return valueFactory.createValue(value.getBoolean());
+        } else if(readIf("NAME")) {
+            // TODO getName
+            return valueFactory.createValue(value.getString());
+        } else if(readIf("PATH")) {
+            // TODO getPath
+            return valueFactory.createValue(value.getString());
+        } else if(readIf("REFERENCE")) {
+            // TODO getReference
+            return valueFactory.createValue(value.getString());
+        } else if(readIf("WEAKREFERENCE")) {
+            // TODO getWeakReference
+            return valueFactory.createValue(value.getString());
+        } else if(readIf("URI")) {
+            // TODO getURI
+            return valueFactory.createValue(value.getString());
+        } else {
+            throw getSyntaxError("data type (STRING|BINARY|...)");
+        }
+    }
 
-    // Page 157
     private Ordering[] parseOrder() throws RepositoryException {
         ArrayList<Ordering> orderList = new ArrayList<Ordering>();
         do {
@@ -497,7 +542,6 @@
         return orderings;
     }
 
-    // Page 159
     private ArrayList<ColumnOrWildcard> parseColumns() throws RepositoryException {
         ArrayList<ColumnOrWildcard> list = new ArrayList<ColumnOrWildcard>();
         if (readIf("*")) {
@@ -545,9 +589,9 @@
                 if (c.selectorName != null) {
                     column = factory.column(c.selectorName, c.propertyName, c.columnName);
                 } else if (c.columnName != null) {
-                    column = factory.column(c.propertyName, c.columnName, null /* TODO */);
+                    column = factory.column(getOnlySelectorName(), c.propertyName, c.columnName);
                 } else {
-                    column = factory.column(c.propertyName, null /* TODO */, null /* TODO */);
+                    column = factory.column(getOnlySelectorName(), c.propertyName, c.propertyName);
                 }
                 columns.add(column);
             }
@@ -727,7 +771,6 @@
         char[] chars = statementChars;
         char c = chars[i++];
         currentToken = "";
-        String result;
         switch (type) {
         case CHAR_NAME:
             while (true) {
@@ -745,29 +788,6 @@
             currentTokenType = IDENTIFIER;
             parseIndex = i;
             return;
-        case CHAR_QUOTED:
-            result = null;
-            while (true) {
-                for (int begin = i;; i++) {
-                    if (chars[i] == '\"') {
-                        if (result == null) {
-                            result = statement.substring(begin, i);
-                        } else {
-                            result += statement.substring(begin - 1, i);
-                        }
-                        break;
-                    }
-                }
-                if (chars[++i] != '\"') {
-                    break;
-                }
-                i++;
-            }
-            currentToken = result;
-            parseIndex = i;
-            currentTokenQuoted = true;
-            currentTokenType = IDENTIFIER;
-            return;
         case CHAR_SPECIAL_2:
             if (types[i] == CHAR_SPECIAL_2) {
                 i++;
@@ -810,7 +830,7 @@
                         break;
                     }
                     checkLiterals(false);
-                    currentValue = valueFactory.createValue((int) number);
+                    currentValue = valueFactory.createValue((long) number);
                     currentTokenType = VALUE;
                     currentToken = "0";
                     parseIndex = i;
@@ -834,28 +854,10 @@
             readDecimal(i - 1, i);
             return;
         case CHAR_STRING:
-            result = null;
-            while (true) {
-                for (int begin = i;; i++) {
-                    if (chars[i] == '\'') {
-                        if (result == null) {
-                            result = statement.substring(begin, i);
-                        } else {
-                            result += statement.substring(begin - 1, i);
-                        }
-                        break;
-                    }
-                }
-                if (chars[++i] != '\'') {
-                    break;
-                }
-                i++;
-            }
-            currentToken = "'";
-            checkLiterals(false);
-            currentValue = valueFactory.createValue(result);
-            parseIndex = i;
-            currentTokenType = VALUE;
+            readString(i, '\'');
+            return;
+        case CHAR_QUOTED:
+            readString(i, '\"');
             return;
         case CHAR_END:
             currentToken = "";
@@ -866,6 +868,32 @@
             throw getSyntaxError();
         }
     }
+    
+    private void readString(int i, char end) throws RepositoryException {
+        char[] chars = statementChars;
+        String result = null;
+        while (true) {
+            for (int begin = i;; i++) {
+                if (chars[i] == end) {
+                    if (result == null) {
+                        result = statement.substring(begin, i);
+                    } else {
+                        result += statement.substring(begin - 1, i);
+                    }
+                    break;
+                }
+            }
+            if (chars[++i] != end) {
+                break;
+            }
+            i++;
+        }
+        currentToken = "'";
+        checkLiterals(false);
+        currentValue = valueFactory.createValue(result);
+        parseIndex = i;
+        currentTokenType = VALUE;
+    }
 
     private void checkLiterals(boolean text) throws InvalidQueryException {
         if (text && !allowTextLiterals || (!text && !allowNumberLiterals)) {
@@ -904,8 +932,11 @@
             throw new InvalidQueryException("Data conversion error converting " + sub + " to BigDecimal: " + e);
         }
         checkLiterals(false);
-        // TODO BigDecimal or double?
+        
+        // TODO createValue(BigDecimal) is not yet implemented
+        // currentValue = valueFactory.createValue(bd);
         currentValue = valueFactory.createValue(bd.doubleValue());
+        
         currentTokenType = VALUE;
     }
 
@@ -942,5 +973,18 @@
         private String propertyName;
         private String columnName;
     }
+    
+    /**
+     * Get the selector name if only one selector exists in the query.
+     * If more than one selector exists, an exception is thrown.
+     * 
+     * @return the selector name
+     */
+    private String getOnlySelectorName() throws RepositoryException {
+        if (selectors.size() > 1) {
+            throw getSyntaxError("Need to specify the selector name because the query contains more than one selector.");
+        }
+        return selectors.get(0).getSelectorName();
+    }
 
 }