You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2013/04/12 18:44:26 UTC

svn commit: r1467342 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ oak-core/src/main/java/org/apache/jackrabbit/oak/query/ oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ oak-core/src/main/re...

Author: jukka
Date: Fri Apr 12 16:44:25 2013
New Revision: 1467342

URL: http://svn.apache.org/r1467342
Log:
OAK-323: Column names aren't reported properly for "select * from [nodeType]" queries

Extend query parser to use proper type information to resolve wildcard columns

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ColumnImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
    jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt
    jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_explain.txt
    jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_index.txt
    jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt
    jackrabbit/oak/trunk/oak-jcr/pom.xml
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/qom/QomTest.java
    jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexQueryTest.java
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java Fri Apr 12 16:44:25 2013
@@ -62,9 +62,10 @@ public interface NodeTypeConstants exten
     // Precompiled Oak type information fields
     String OAK_SUPERTYPES = "oak:supertypes";
     String OAK_SUBTYPES = "oak:subtypes";
-    String OAK_NAMED_PROPERTIES = "oak:namedProperties";
     String OAK_MANDATORY_PROPERTIES = "oak:mandatoryProperties";
     String OAK_MANDATORY_CHILD_NODES = "oak:mandatoryChildNodes";
+    String OAK_NAMED_SINGLE_VALUED_PROPERTIES =
+            "oak:namedSingleValuedProperties";
     String OAK_RESIDUAL_CHILD_NODE_DEFINITIONS =
             "oak:residualChildNodeDefinitions";
     String OAK_NAMED_CHILD_NODE_DEFINITIONS =

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java Fri Apr 12 16:44:25 2013
@@ -47,7 +47,7 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_MANDATORY_CHILD_NODES;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_MANDATORY_PROPERTIES;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_CHILD_NODE_DEFINITIONS;
-import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_PROPERTIES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_SINGLE_VALUED_PROPERTIES;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_PROPERTY_DEFINITIONS;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_PROPERTY_DEFINITIONS;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_RESIDUAL_CHILD_NODE_DEFINITIONS;
@@ -164,9 +164,9 @@ class RegistrationEditor extends Default
                 supertype.getProperty(JCR_NODETYPENAME).getValue(NAME);
         addNameToList(type, OAK_SUPERTYPES, supername);
         mergeNameList(type, supertype, OAK_SUPERTYPES);
-        mergeNameList(type, supertype, OAK_NAMED_PROPERTIES);
         mergeNameList(type, supertype, OAK_MANDATORY_PROPERTIES);
         mergeNameList(type, supertype, OAK_MANDATORY_CHILD_NODES);
+        mergeNameList(type, supertype, OAK_NAMED_SINGLE_VALUED_PROPERTIES);
         mergeSubtree(type, supertype, OAK_NAMED_PROPERTY_DEFINITIONS, 2);
         mergeSubtree(type, supertype, OAK_RESIDUAL_PROPERTY_DEFINITIONS, 1);
         mergeSubtree(type, supertype, OAK_NAMED_CHILD_NODE_DEFINITIONS, 2);
@@ -221,9 +221,9 @@ class RegistrationEditor extends Default
         type.setProperty(JCR_PRIMARYTYPE, "oak:nodeType", NAME);
         type.removeProperty(OAK_SUPERTYPES);
         type.setProperty(OAK_SUBTYPES, empty, NAMES);
-        type.setProperty(OAK_NAMED_PROPERTIES, empty, NAMES);
         type.setProperty(OAK_MANDATORY_PROPERTIES, empty, NAMES);
         type.setProperty(OAK_MANDATORY_CHILD_NODES, empty, NAMES);
+        type.setProperty(OAK_NAMED_SINGLE_VALUED_PROPERTIES, empty, NAMES);
         type.removeNode(OAK_NAMED_PROPERTY_DEFINITIONS);
         type.removeNode(OAK_RESIDUAL_PROPERTY_DEFINITIONS);
         type.removeNode(OAK_NAMED_CHILD_NODE_DEFINITIONS);
@@ -258,8 +258,9 @@ class RegistrationEditor extends Default
         // - jcr:name (NAME) protected 
         PropertyState name = definition.getProperty(JCR_NAME);
         NodeBuilder definitions;
+        String propertyName = null;
         if (name != null) {
-            String propertyName = name.getValue(NAME);
+            propertyName = name.getValue(NAME);
             String escapedName = propertyName;
             if (JCR_PRIMARYTYPE.equals(escapedName)) {
                 escapedName = "oak:primaryType";
@@ -302,6 +303,8 @@ class RegistrationEditor extends Default
             } else {
                 key = key + "S";
             }
+        } else if (propertyName != null) {
+            addNameToList(type, OAK_NAMED_SINGLE_VALUED_PROPERTIES, propertyName);
         }
 
         definitions.setNode(key, definition);

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java Fri Apr 12 16:44:25 2013
@@ -16,6 +16,10 @@
  */
 package org.apache.jackrabbit.oak.query;
 
+import static com.google.common.collect.ImmutableSet.of;
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
+
 import java.text.ParseException;
 import java.util.List;
 import java.util.Map;
@@ -35,8 +39,6 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.ImmutableSet;
-
 /**
  * The query engine implementation.
  */
@@ -46,53 +48,19 @@ public abstract class QueryEngineImpl im
     static final String SQL = "sql";
     static final String XPATH = "xpath";
     static final String JQOM = "JCR-JQOM";
-    
+
     static final String NO_LITERALS = "-noLiterals";
 
+    private static final Set<String> SUPPORTED_LANGUAGES = of(
+            SQL2,  SQL2  + NO_LITERALS,
+            SQL,   SQL   + NO_LITERALS,
+            XPATH, XPATH + NO_LITERALS,
+            JQOM);
+
     static final Logger LOG = LoggerFactory.getLogger(QueryEngineImpl.class);
 
     private final QueryIndexProvider indexProvider;
 
-    // TODO: Turn into a standalone class
-    private final QueryParser parser = new QueryParser() {
-        @Override
-        public Set<String> getSupportedLanguages() {
-            return ImmutableSet.of(
-                    SQL2, SQL, XPATH, JQOM,
-                    SQL2 + NO_LITERALS,
-                    SQL + NO_LITERALS,
-                    XPATH + NO_LITERALS);
-        }
-        @Override
-        public Query parse(String statement, String language)
-                throws ParseException {
-            LOG.debug("Parsing {} statement: {}", language, statement);
-            SQL2Parser parser = new SQL2Parser();
-            if (language.endsWith(NO_LITERALS)) {
-                language = language.substring(0, language.length() - NO_LITERALS.length());
-                parser.setAllowNumberLiterals(false);
-                parser.setAllowTextLiterals(false);
-            }
-            if (SQL2.equals(language) || JQOM.equals(language)) {
-                return parser.parse(statement);
-            } else if (SQL.equals(language)) {
-                parser.setSupportSQL1(true);
-                return parser.parse(statement);
-            } else if (XPATH.equals(language)) {
-                XPathToSQL2Converter converter = new XPathToSQL2Converter();
-                String sql2 = converter.convert(statement);
-                LOG.debug("XPath > SQL2: {}", sql2);
-                try {
-                    return parser.parse(sql2);
-                } catch (ParseException e) {
-                    throw new ParseException(statement + " converted to SQL-2 " + e.getMessage(), 0);
-                }
-            } else {
-                throw new ParseException("Unsupported language: " + language, 0);
-            }
-        }
-    };
-
     public QueryEngineImpl(QueryIndexProvider indexProvider) {
         this.indexProvider = indexProvider;
     }
@@ -113,7 +81,7 @@ public abstract class QueryEngineImpl im
 
     @Override
     public Set<String> getSupportedQueryLanguages() {
-        return parser.getSupportedLanguages();
+        return SUPPORTED_LANGUAGES;
     }
 
     /**
@@ -131,7 +99,33 @@ public abstract class QueryEngineImpl im
     }
 
     private Query parseQuery(String statement, String language) throws ParseException {
-        return parser.parse(statement, language);
+        LOG.debug("Parsing {} statement: {}", language, statement);
+        NodeState root = getRootState();
+        NodeState system = root.getChildNode(JCR_SYSTEM);
+        NodeState types = system.getChildNode(JCR_NODE_TYPES);
+        SQL2Parser parser = new SQL2Parser(types);
+        if (language.endsWith(NO_LITERALS)) {
+            language = language.substring(0, language.length() - NO_LITERALS.length());
+            parser.setAllowNumberLiterals(false);
+            parser.setAllowTextLiterals(false);
+        }
+        if (SQL2.equals(language) || JQOM.equals(language)) {
+            return parser.parse(statement);
+        } else if (SQL.equals(language)) {
+            parser.setSupportSQL1(true);
+            return parser.parse(statement);
+        } else if (XPATH.equals(language)) {
+            XPathToSQL2Converter converter = new XPathToSQL2Converter();
+            String sql2 = converter.convert(statement);
+            LOG.debug("XPath > SQL2: {}", sql2);
+            try {
+                return parser.parse(sql2);
+            } catch (ParseException e) {
+                throw new ParseException(statement + " converted to SQL-2 " + e.getMessage(), 0);
+            }
+        } else {
+            throw new ParseException("Unsupported language: " + language, 0);
+        }
     }
     
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java Fri Apr 12 16:44:25 2013
@@ -16,6 +16,14 @@
  */
 package org.apache.jackrabbit.oak.query;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Maps.newHashMap;
+import static org.apache.jackrabbit.JcrConstants.NT_BASE;
+import static org.apache.jackrabbit.oak.api.Type.NAMES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_SINGLE_VALUED_PROPERTIES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_SUBTYPES;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
@@ -35,14 +43,20 @@ import org.apache.jackrabbit.oak.query.a
 import org.apache.jackrabbit.oak.query.ast.SourceImpl;
 import org.apache.jackrabbit.oak.query.ast.StaticOperandImpl;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableSet;
+
 import javax.jcr.PropertyType;
 import java.math.BigDecimal;
 import java.text.ParseException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * The SQL2 parser can convert a JCR-SQL2 query to a query. The 'old' SQL query
@@ -61,6 +75,8 @@ public class SQL2Parser {
     private static final int KEYWORD = 1, IDENTIFIER = 2, PARAMETER = 3, END = 4, VALUE = 5;
     private static final int MINUS = 12, PLUS = 13, OPEN = 14, CLOSE = 15;
 
+    private final NodeState types;
+
     // The query as an array of characters and character types
     private String statement;
     private char[] statementChars;
@@ -78,7 +94,7 @@ public class SQL2Parser {
     private HashMap<String, BindVariableValueImpl> bindVariables;
 
     // The list of selectors of this query
-    private ArrayList<SelectorImpl> selectors;
+    private final Map<String, SelectorImpl> selectors = newHashMap();
 
     // SQL injection protection: if disabled, literals are not allowed
     private boolean allowTextLiterals = true;
@@ -92,7 +108,8 @@ public class SQL2Parser {
      * Create a new parser. A parser can be re-used, but it is not thread safe.
      *
      */
-    public SQL2Parser() {
+    public SQL2Parser(NodeState types) {
+        this.types = checkNotNull(types);
     }
 
     /**
@@ -107,7 +124,7 @@ public class SQL2Parser {
         // http://docs.jboss.org/modeshape/latest/manuals/reference/html/jcr-query-and-search.html
 
         initialize(query);
-        selectors = new ArrayList<SelectorImpl>();
+        selectors.clear();
         expected = new ArrayList<String>();
         bindVariables = new HashMap<String, BindVariableValueImpl>();
         read();
@@ -177,11 +194,30 @@ public class SQL2Parser {
 
     private SelectorImpl parseSelector() throws ParseException {
         String nodeTypeName = readName();
+
+        Set<String> matchingTypes = null;
+        if (!NT_BASE.equals(nodeTypeName)) {
+            ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+            NodeState type = types.getChildNode(nodeTypeName);
+            if (type.exists()) {
+                builder.add(nodeTypeName);
+                PropertyState subtypes = type.getProperty(OAK_SUBTYPES);
+                if (subtypes != null) {
+                    for (String subname : subtypes.getValue(NAMES)) {
+                        builder.add(subname);
+                    }
+                }
+            } else {
+                throw getSyntaxError("unknown node type");
+            }
+            matchingTypes = builder.build();
+        }
+
         if (readIf("AS")) {
             String selectorName = readName();
-            return factory.selector(nodeTypeName, selectorName);
+            return factory.selector(nodeTypeName, selectorName, matchingTypes);
         } else {
-            return factory.selector(nodeTypeName, nodeTypeName);
+            return factory.selector(nodeTypeName, nodeTypeName, matchingTypes);
         }
     }
 
@@ -201,7 +237,7 @@ public class SQL2Parser {
 
     private SourceImpl parseSource() throws ParseException {
         SelectorImpl selector = parseSelector();
-        selectors.add(selector);
+        selectors.put(selector.getSelectorName(), selector);
         SourceImpl source = selector;
         while (true) {
             JoinType joinType;
@@ -218,7 +254,7 @@ public class SQL2Parser {
             }
             read("JOIN");
             selector = parseSelector();
-            selectors.add(selector);
+            selectors.put(selector.getSelectorName(), selector);
             read("ON");
             JoinConditionImpl on = parseJoinCondition();
             source = factory.join(source, selector, joinType, on);
@@ -709,21 +745,25 @@ public class SQL2Parser {
         } else {
             do {
                 ColumnOrWildcard column = new ColumnOrWildcard();
-                column.propertyName = readName();
-                if (readIf(".")) {
-                    column.selectorName = column.propertyName;
-                    if (readIf("*")) {
-                        column.propertyName = null;
+                if (readIf("*")) {
+                    column.propertyName = null;
+                } else {
+                    column.propertyName = readName();
+                    if (readIf(".")) {
+                        column.selectorName = column.propertyName;
+                        if (readIf("*")) {
+                            column.propertyName = null;
+                        } else {
+                            column.propertyName = readName();
+                            if (readIf("AS")) {
+                                column.columnName = readName();
+                            }
+                        }
                     } else {
-                        column.propertyName = readName();
                         if (readIf("AS")) {
                             column.columnName = readName();
                         }
                     }
-                } else {
-                    if (readIf("AS")) {
-                        column.columnName = readName();
-                    }
                 }
                 list.add(column);
             } while (readIf(","));
@@ -735,25 +775,20 @@ public class SQL2Parser {
         ArrayList<ColumnImpl> columns = new ArrayList<ColumnImpl>();
         for (ColumnOrWildcard c : list) {
             if (c.propertyName == null) {
-                for (SelectorImpl selector : selectors) {
-                    if (c.selectorName == null
-                            || c.selectorName
-                                    .equals(selector.getSelectorName())) {
-                        ColumnImpl column = factory.column(selector
-                                .getSelectorName(), null, null);
-                        columns.add(column);
-                    }
-                }
+                addWildcardColumns(columns, c.selectorName);
             } else {
-                ColumnImpl column;
-                if (c.selectorName != null) {
-                    column = factory.column(c.selectorName, c.propertyName, c.columnName);
-                } else if (c.columnName != null) {
-                    column = factory.column(getOnlySelectorName(), c.propertyName, c.columnName);
-                } else {
-                    column = factory.column(getOnlySelectorName(), c.propertyName, c.propertyName);
+                String selectorName = c.selectorName;
+                if (selectorName == null) {
+                    selectorName = getOnlySelectorName();
+                }
+
+                String columnName = c.columnName;
+                if (columnName == null) {
+                    columnName = c.propertyName;
                 }
-                columns.add(column);
+
+                columns.add(factory.column(
+                        selectorName, c.propertyName, columnName));
             }
         }
         ColumnImpl[] array = new ColumnImpl[columns.size()];
@@ -761,6 +796,42 @@ public class SQL2Parser {
         return array;
     }
 
+    private void addWildcardColumns(
+            Collection<ColumnImpl> columns, String selectorName)
+            throws ParseException {
+        if (selectorName == null) {
+            for (SelectorImpl selector : selectors.values()) {
+                addWildcardColumns(columns, selector, selectors.size() > 1);
+            }
+        } else {
+            SelectorImpl selector = selectors.get(selectorName);
+            if (selector != null) {
+                addWildcardColumns(columns, selector, true);
+            } else {
+                throw getSyntaxError("Unknown selector: " + selectorName);
+            }
+        }
+    }
+
+    private void addWildcardColumns(
+            Collection<ColumnImpl> columns, SelectorImpl selector,
+            boolean includeSelectorName) {
+        String name = selector.getNodeTypeName();
+
+        PropertyState properties = types.getChildNode(name).getProperty(
+                OAK_NAMED_SINGLE_VALUED_PROPERTIES);
+        if (properties != null) {
+            String selectorName = selector.getSelectorName();
+            for (String property : properties.getValue(NAMES)) {
+                String columnName = property;
+                if (includeSelectorName) {
+                    columnName = selectorName + "." + property;
+                }
+                columns.add(factory.column(selectorName, property, columnName));
+            }
+        }
+    }
+
     private boolean readIf(String token) throws ParseException {
         if (isToken(token)) {
             read();
@@ -1152,7 +1223,7 @@ public class SQL2Parser {
         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();
+        return selectors.values().iterator().next().getSelectorName();
     }
 
     public static String escapeStringLiteral(String value) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java Fri Apr 12 16:44:25 2013
@@ -13,6 +13,8 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
+import java.util.Set;
+
 import org.apache.jackrabbit.oak.api.PropertyValue;
 
 /**
@@ -128,8 +130,10 @@ public class AstElementFactory {
         return new SameNodeJoinConditionImpl(selector1Name, selector2Name, selector2Path);
     }
 
-    public SelectorImpl selector(String nodeTypeName, String selectorName) {
-        return new SelectorImpl(nodeTypeName, selectorName);
+    public SelectorImpl selector(
+            String nodeTypeName, String selectorName,
+            Set<String> matchingTypes) {
+        return new SelectorImpl(nodeTypeName, selectorName, matchingTypes);
     }
 
     public UpperCaseImpl upperCase(DynamicOperandImpl operand) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ColumnImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ColumnImpl.java?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ColumnImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ColumnImpl.java Fri Apr 12 16:44:25 2013
@@ -18,8 +18,9 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import org.apache.jackrabbit.oak.api.PropertyValue;
-import org.apache.jackrabbit.oak.spi.query.PropertyValues;
 
 /**
  * A result column expression.
@@ -30,9 +31,9 @@ public class ColumnImpl extends AstEleme
     private SelectorImpl selector;
 
     public ColumnImpl(String selectorName, String propertyName, String columnName) {
-        this.selectorName = selectorName;
-        this.propertyName = propertyName;
-        this.columnName = columnName;
+        this.selectorName = checkNotNull(selectorName);
+        this.propertyName = checkNotNull(propertyName);
+        this.columnName = checkNotNull(columnName);
     }
     
     public String getColumnName() {
@@ -46,23 +47,11 @@ public class ColumnImpl extends AstEleme
 
     @Override
     public String toString() {
-        if (propertyName != null) {
-            return quote(selectorName) + '.' + quote(propertyName) + 
-                    " as " + quote(columnName);
-        } else {
-            return quote(selectorName) + ".*";
-        }
+        return quote(selectorName) + '.' + quote(propertyName)
+                + " as " + quote(columnName);
     }
 
     public PropertyValue currentProperty() {
-        if (propertyName == null || propertyName.equals("*")) {
-            // TODO for SELECT * FROM queries, currently return the path (for testing only)
-            String p = selector.currentPath();
-            if (p == null) {
-                return null;
-            }
-            return PropertyValues.newString(p);
-        }
         return selector.currentProperty(propertyName);
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java Fri Apr 12 16:44:25 2013
@@ -25,6 +25,7 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.query.ast.ComparisonImpl.LikePattern;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
@@ -38,14 +39,33 @@ import static org.apache.jackrabbit.oak.
 public class FullTextSearchImpl extends ConstraintImpl {
 
     private final String selectorName;
+    private final String relativePath;
     private final String propertyName;
     private final StaticOperandImpl fullTextSearchExpression;
     private SelectorImpl selector;
 
-    public FullTextSearchImpl(String selectorName, String propertyName,
+    public FullTextSearchImpl(
+            String selectorName, String propertyName,
             StaticOperandImpl fullTextSearchExpression) {
         this.selectorName = selectorName;
-        this.propertyName = propertyName;
+
+        int slash = -1;
+        if (propertyName != null) {
+            slash = propertyName.lastIndexOf('/');
+        }
+        if (slash == -1) {
+            this.relativePath = null;
+        } else {
+            this.relativePath = propertyName.substring(0, slash);
+            propertyName = propertyName.substring(slash + 1);
+        }
+
+        if (propertyName == null || "*".equals(propertyName)) {
+            this.propertyName = null;
+        } else {
+            this.propertyName = propertyName;
+        }
+
         this.fullTextSearchExpression = fullTextSearchExpression;
     }
 
@@ -63,13 +83,16 @@ public class FullTextSearchImpl extends 
         StringBuilder builder = new StringBuilder();
         builder.append("contains(");
         builder.append(quote(selectorName));
-        if (propertyName != null) {
-            builder.append('.');
-            builder.append(quote(propertyName));
-            builder.append(", ");
-        } else {
-            builder.append(".*, ");
+        builder.append('.');
+        String propertyName = this.propertyName;
+        if (propertyName == null) {
+            propertyName = "*";
+        }
+        if (relativePath != null) {
+            propertyName = relativePath + "/" + propertyName;
         }
+        builder.append(quote(propertyName));
+        builder.append(", ");
         builder.append(getFullTextSearchExpression());
         builder.append(')');
         return builder.toString();
@@ -78,19 +101,33 @@ public class FullTextSearchImpl extends 
     @Override
     public boolean evaluate() {
         StringBuilder buff = new StringBuilder();
-        if (propertyName != null) {
+        if (relativePath == null && propertyName != null) {
             PropertyValue p = selector.currentProperty(propertyName);
             if (p == null) {
                 return false;
             }
             appendString(buff, p);
         } else {
-            Tree tree = getTree(selector.currentPath());
+            String path = selector.currentPath();
+            if (relativePath != null) {
+                path = PathUtils.concat(path, relativePath);
+            }
+
+            Tree tree = getTree(path);
             if (tree == null) {
                 return false;
             }
-            for (PropertyState p : tree.getProperties()) {
+
+            if (propertyName != null) {
+                PropertyState p = tree.getProperty(propertyName);
+                if (p == null) {
+                    return false;
+                }
                 appendString(buff, PropertyValues.create(p));
+            } else {
+                for (PropertyState p : tree.getProperties()) {
+                    appendString(buff, PropertyValues.create(p));
+                }
             }
         }
         // TODO fulltext conditions: need a way to disable evaluation

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java Fri Apr 12 16:44:25 2013
@@ -18,23 +18,19 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.oak.api.Type.NAME;
+import static org.apache.jackrabbit.oak.api.Type.NAMES;
 
-import javax.annotation.CheckForNull;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NoSuchNodeTypeException;
-import javax.jcr.nodetype.NodeTypeManager;
+import java.util.Set;
 
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
-import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
 import org.apache.jackrabbit.oak.query.Query;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
@@ -44,9 +40,6 @@ import org.apache.jackrabbit.oak.spi.que
 import org.apache.jackrabbit.oak.spi.query.QueryIndex;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-
 /**
  * A selector within a query.
  */
@@ -55,20 +48,18 @@ public class SelectorImpl extends Source
     // TODO possibly support using multiple indexes (using index intersection / index merge)
     protected QueryIndex index;
 
-    private final String nodeTypeName, selectorName;
-    private Cursor cursor;
-    private IndexRow currentRow;
-    private int scanCount;
+    private final String nodeTypeName;
+
+    private final String selectorName;
 
     /**
-     * Names of all matching node type names encountered so far.
+     * Names of matching node types, or {@code null} if all types match.
      */
     private final Set<String> matchingTypes;
 
-    /**
-     * Names of all <em>non-matching</em> node type names encountered so far.
-     */
-    private final Set<String> nonMatchingTypes;
+    private Cursor cursor;
+    private IndexRow currentRow;
+    private int scanCount;
 
     /**
      * The selector condition can be evaluated when the given selector is
@@ -79,19 +70,16 @@ public class SelectorImpl extends Source
      */
     private ConstraintImpl selectorCondition;
 
-    public SelectorImpl(String nodeTypeName, String selectorName) {
-        this.nodeTypeName = nodeTypeName;
-        this.selectorName = selectorName;
-
-        if (JcrConstants.NT_BASE.equals(nodeTypeName)) {
-            matchingTypes = null;
-            nonMatchingTypes = null;
-        } else {
-            matchingTypes = Sets.newHashSet();
-            matchingTypes.add(nodeTypeName);
-            nonMatchingTypes = Sets.newHashSet();
-            nonMatchingTypes.add(JcrConstants.NT_BASE);
-        }
+    public SelectorImpl(
+            String nodeTypeName, String selectorName,
+            Set<String> matchingTypes) {
+        this.nodeTypeName = checkNotNull(nodeTypeName);
+        this.selectorName = checkNotNull(selectorName);
+        this.matchingTypes = matchingTypes;
+    }
+
+    public String getNodeTypeName() {
+        return nodeTypeName;
     }
 
     public String getSelectorName() {
@@ -151,7 +139,6 @@ public class SelectorImpl extends Source
     private Filter createFilter(boolean preparing) {
         FilterImpl f = new FilterImpl(this, query.getStatement());
         f.setPreparing(preparing);
-        validateNodeType();
         f.setNodeType(nodeTypeName);
         if (joinCondition != null) {
             joinCondition.restrict(f);
@@ -172,30 +159,6 @@ public class SelectorImpl extends Source
 
         return f;
     }
-    
-    private void validateNodeType() {
-        if (!JcrConstants.NT_BASE.equals(nodeTypeName)) {
-            try {
-                // Check both the syntactic validity of the type name
-                // and the existence of the named type in one call
-                getNodeTypeManager().getNodeType(nodeTypeName);
-            } catch (NoSuchNodeTypeException e) {
-                // TODO: QueryManagerImpl.executeQuery() expects an
-                // IllegalArgumentException to signal an invalid query.
-                // This is a bit troublesome since any method could throw
-                // that exception as a result of some internal programming
-                // error or some other inconsistency that has nothing to
-                // do with the validity of the query. A better solution
-                // would be to use some checked exception or explicit
-                // return value to signal whether the query is valid or not.
-                throw new IllegalArgumentException(
-                        "Unknown node type: " + nodeTypeName, e);
-            } catch (RepositoryException e) {
-                throw new RuntimeException(
-                        "Unable to evaluate node type constraints", e);
-            }
-        }
-    }
 
     @Override
     public boolean next() {
@@ -225,63 +188,30 @@ public class SelectorImpl extends Source
     }
 
     private boolean evaluateTypeMatch(Tree tree) {
-        if (JcrConstants.NT_BASE.equals(nodeTypeName)) {
+        if (matchingTypes == null) {
             return true; // shortcut for a common case
         }
 
-        Set<String> types = Sets.newHashSet();
-
-        PropertyState primary = tree.getProperty(JcrConstants.JCR_PRIMARYTYPE);
-        if (primary != null && primary.getType() == Type.NAME) {
-            String name = primary.getValue(Type.NAME);
+        PropertyState primary = tree.getProperty(JCR_PRIMARYTYPE);
+        if (primary != null && primary.getType() == NAME) {
+            String name = primary.getValue(NAME);
             if (matchingTypes.contains(name)) {
                 return true;
-            } else if (!nonMatchingTypes.contains(name)) {
-                types.add(name);
             }
         }
 
-        PropertyState mixins = tree.getProperty(JcrConstants.JCR_MIXINTYPES);
-        if (mixins != null && mixins.getType() == Type.NAMES) {
-            for (String name : mixins.getValue(Type.NAMES)) {
+        PropertyState mixins = tree.getProperty(JCR_MIXINTYPES);
+        if (mixins != null && mixins.getType() == NAMES) {
+            for (String name : mixins.getValue(NAMES)) {
                 if (matchingTypes.contains(name)) {
                     return true;
-                } else if (!nonMatchingTypes.contains(name)) {
-                    types.add(name);
-                }
-            }
-        }
-
-        if (!types.isEmpty()) {
-            try {
-                NodeTypeManager manager = getNodeTypeManager();
-                for (String type : types) {
-                    if (manager.getNodeType(type).isNodeType(nodeTypeName)) {
-                        matchingTypes.add(type);
-                        return true;
-                    } else {
-                        nonMatchingTypes.add(type);
-                        // continue iterating
-                    }
                 }
-            } catch (RepositoryException e) {
-                throw new RuntimeException(
-                        "Unable to evaluate node type constraints", e);
             }
         }
 
         return false; // no matches found
     }
 
-    private NodeTypeManager getNodeTypeManager() {
-        return new ReadOnlyNodeTypeManager() {
-            @Override @CheckForNull
-            protected Tree getTypes() {
-                return getTree(NodeTypeConstants.NODE_TYPES_PATH);
-            }
-        };
-    }
-
     /**
      * Get the current absolute path (including workspace name)
      *
@@ -333,16 +263,6 @@ public class SelectorImpl extends Source
             }
             return PropertyValues.newString(local);
         }
-        if (propertyName.equals("*")) {
-            // TODO currently all property values are converted to strings - 
-            // this doesn't play well with the idea that the types may be different
-            List<String> values = new ArrayList<String>();
-            for (PropertyState p : t.getProperties()) {
-                Iterables.addAll(values, p.getValue(Type.STRINGS));
-            }
-            // "*"
-            return PropertyValues.newString(values);
-        } 
         return PropertyValues.create(t.getProperty(propertyName));
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd Fri Apr 12 16:44:25 2013
@@ -428,9 +428,9 @@
 [oak:nodeType] > nt:nodeType
   - oak:supertypes (NAME) protected multiple autocreated
   - oak:subtypes (NAME) protected multiple autocreated
-  - oak:namedProperties (NAME) protected multiple autocreated
   - oak:mandatoryProperties (NAME) protected multiple autocreated
   - oak:mandatoryChildNodes (NAME) protected multiple autocreated
+  - oak:namedSingleValuedProperties (NAME) protected multiple autocreated
   + oak:namedPropertyDefinitions (oak:namedPropertyDefinitions) = oak:namedPropertyDefinitions protected mandatory
   + oak:residualPropertyDefinitions (oak:propertyDefinitions) = oak:propertyDefinitions protected mandatory
   + oak:namedChildNodeDefinitions (oak:namedChildNodeDefinitions) = oak:namedChildNodeDefinitions protected mandatory

Modified: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt Fri Apr 12 16:44:25 2013
@@ -28,10 +28,10 @@
 commit / + "test": { "a": { "x": "1", "yes": { } }, "b": { "yes" : { } }, "c": { "x": "1", "no" : { } }}
 
 xpath test//yes/..[@x]
-/test/a, null, /test/a
+/test/a, null, null
 
-select b.[jcr:path] as [jcr:path], b.[jcr:score] as [jcr:score], b.* from [nt:base] as a inner join [nt:base] as b on ischildnode(a, b) where name(a) = 'yes' and isdescendantnode(a, '/test') and b.[x] is not null
-/test/a, null, /test/a
+select b.[jcr:path] as [jcr:path], b.[jcr:score] as [jcr:score] from [nt:base] as a inner join [nt:base] as b on ischildnode(a, b) where name(a) = 'yes' and isdescendantnode(a, '/test') and b.[x] is not null
+/test/a, null
 
 commit / - "test"
 
@@ -39,7 +39,7 @@ commit / - "test"
 
 commit / + "test": { "space space": { "x": "1" }}
 
-select * from [nt:base] where issamenode([/test/space space])
+select [jcr:path] from [nt:base] where issamenode([/test/space space])
 /test/space space
 
 commit / - "test"
@@ -48,44 +48,44 @@ commit / - "test"
 
 commit / + "test": { "a": { "name": ["Hello", "World" ] }, "b": { "name" : "Hello" }}
 
-select * from [nt:base] where name = 'Hello'
+select [jcr:path] from [nt:base] where name = 'Hello'
 /test/a
 /test/b
 
-select * from [nt:base] where name = 'World'
+select [jcr:path] from [nt:base] where name = 'World'
 /test/a
 
-select * from [nt:base] where isdescendantnode('/test') and name = 'World'
+select [jcr:path] from [nt:base] where isdescendantnode('/test') and name = 'World'
 /test/a
 
 commit / - "test"
 
 # expected error on two selectors with the same name
 
-select * from [nt:base] as p inner join [nt:base] as p on ischildnode(p, p) where p.[jcr:path] = '/'
-java.text.ParseException: select * from [nt:base] as p inner join [nt:base] as p on ischildnode(p, p) where p.[jcr:path] = '/': Two selectors with the same name: p
+select [jcr:path] from [nt:base] as p inner join [nt:base] as p on ischildnode(p, p) where p.[jcr:path] = '/'
+java.text.ParseException: select [jcr:path] from [nt:base] as p inner join [nt:base] as p on ischildnode(p, p) where p.[jcr:path] = '/': Two selectors with the same name: p
 
 # combining 'not' and 'and'
 
 commit / + "test": { "a": { "id": "10" }, "b": { "id" : "20" }}
 
-select * from [nt:base] where id is not null and not id = '100' and id <> '20'
+select [jcr:path] from [nt:base] where id is not null and not id = '100' and id <> '20'
 /test/a
 
-select * from [nt:base] where id < '1000'
+select [jcr:path] from [nt:base] where id < '1000'
 /test/a
 
-select * from [nt:base] where id is not null and not (id = '100' and id <> '20')
+select [jcr:path] from [nt:base] where id is not null and not (id = '100' and id <> '20')
 /test/a
 /test/b
 
-select * from [nt:base] where id = '10'
+select [jcr:path] from [nt:base] where id = '10'
 /test/a
 
-select [jcr:path], * from [nt:base] where id = '10'
-/test/a, /test/a
+select [jcr:path], id from [nt:base] where id = '10'
+/test/a, 10
 
-select * from [nt:base] where id > '10'
+select [jcr:path] from [nt:base] where id > '10'
 /test/b
 
 commit / - "test"
@@ -94,10 +94,10 @@ commit / - "test"
 
 commit / + "test": { "name": "hello world" }
 
-select * from [nt:base] where contains(name, 'hello')
+select [jcr:path] from [nt:base] where contains(name, 'hello')
 /test
 
-select * from [nt:base] where contains(*, 'hello')
+select [jcr:path] from [nt:base] where contains(*, 'hello')
 /test
 
 commit / - "test"
@@ -116,29 +116,29 @@ commit / - "test"
 
 commit / + "test": { "jcr:resource": {}, "resource": { "x" : {}}}
 
-select * from [nt:base] where id = -1
+select [jcr:path] from [nt:base] where id = -1
 
-select * from [nt:base] as b where isdescendantnode(b, '/test')
+select [jcr:path] from [nt:base] as b where isdescendantnode(b, '/test')
 /test/jcr:resource
 /test/resource
 /test/resource/x
 
-select * from [nt:base] as b where ischildnode(b, '/test')
+select [jcr:path] from [nt:base] as b where ischildnode(b, '/test')
 /test/jcr:resource
 /test/resource
 
-select * from [nt:base] as b where issamenode(b, '/test')
+select [jcr:path] from [nt:base] as b where issamenode(b, '/test')
 /test
 
-select * from [nt:base] where name() = 'resource'
+select [jcr:path] from [nt:base] where name() = 'resource'
 /test/resource
 
-select * from [nt:base] as b where localname(b) = 'resource'
+select [jcr:path] from [nt:base] as b where localname(b) = 'resource'
 /jcr:system/jcr:nodeTypes/nt:resource
 /test/jcr:resource
 /test/resource
 
-select * from [nt:base] as x where isdescendantnode(x, '/test')
+select [jcr:path] from [nt:base] as x where isdescendantnode(x, '/test')
 /test/jcr:resource
 /test/resource
 /test/resource/x
@@ -149,27 +149,27 @@ commit / + "parents": { "p0": {"id": "0"
 commit / + "children": { "c1": {"p": "1"}, "c2": {"p": "1"}, "c3": {"p": "2"}, "c4": {"p": "3"}}
 
 # relative property
-select * from [nt:base] where [c1/p] = '1'
+select [jcr:path] from [nt:base] where [c1/p] = '1'
 /children
 
-select * from [nt:base] as p where p.[jcr:path] = '/parents'
+select [jcr:path] from [nt:base] as p where p.[jcr:path] = '/parents'
 /parents
 
-select * from [nt:base] as [p] where [p].[jcr:path] = '/parents'
+select [jcr:path] from [nt:base] as [p] where [p].[jcr:path] = '/parents'
 /parents
 
-select * from [nt:base] as p inner join [nt:base] as p2 on ischildnode(p2, p) where p.[jcr:path] = '/'
+select p.[jcr:path], p2.[jcr:path] from [nt:base] as p inner join [nt:base] as p2 on ischildnode(p2, p) where p.[jcr:path] = '/'
 /, /children
 /, /jcr:system
 /, /oak:index
 /, /parents
 
-select * from [nt:base] as p inner join [nt:base] as p2 on isdescendantnode(p2, p) where p.[jcr:path] = '/parents'
+select p.[jcr:path], p2.[jcr:path] from [nt:base] as p inner join [nt:base] as p2 on isdescendantnode(p2, p) where p.[jcr:path] = '/parents'
 /parents, /parents/p0
 /parents, /parents/p1
 /parents, /parents/p2
 
-select * from [nt:base] as p inner join [nt:base] as p2 on issamenode(p2, p) where p.[jcr:path] = '/parents'
+select p.[jcr:path], p2.[jcr:path] from [nt:base] as p inner join [nt:base] as p2 on issamenode(p2, p) where p.[jcr:path] = '/parents'
 /parents, /parents
 
 select id from [nt:base] where id is not null
@@ -182,27 +182,27 @@ select id from [nt:base] where id is not
 1
 0
 
-select * from [nt:base] as c right outer join [nt:base] as p on p.id = c.p where p.id is not null and not isdescendantnode(p, '/jcr:system')
+select c.[jcr:path], p.[jcr:path] from [nt:base] as c right outer join [nt:base] as p on p.id = c.p where p.id is not null and not isdescendantnode(p, '/jcr:system')
 /children/c1, /parents/p1
 /children/c2, /parents/p1
 /children/c3, /parents/p2
 null, /parents/p0
 
-select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null
+select p.[jcr:path], c.[jcr:path] from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null
 /parents/p0, null
 /parents/p1, /children/c1
 /parents/p1, /children/c2
 /parents/p2, /children/c3
 
-select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and c.p is null
+select p.[jcr:path], c.[jcr:path] from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and c.p is null
 /parents/p0, null
 
-select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and c.p is not null
+select p.[jcr:path], c.[jcr:path] from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and c.p is not null
 /parents/p1, /children/c1
 /parents/p1, /children/c2
 /parents/p2, /children/c3
 
-select * from [nt:base] as p inner join [nt:base] as c on p.id = c.p
+select p.[jcr:path], c.[jcr:path] from [nt:base] as p inner join [nt:base] as c on p.id = c.p
 /parents/p1, /children/c1
 /parents/p1, /children/c2
 /parents/p2, /children/c3
@@ -214,27 +214,27 @@ commit / + "testRoot": {}
 commit /testRoot + "test": { "hello": { "x": "1" }, "world": { "x": "2" } }
 commit /testRoot + "test2": { "id":"1", "x": "2" }
 
-select * from [nt:base] where isdescendantnode('/testRoot')
+select [jcr:path] from [nt:base] where isdescendantnode('/testRoot')
 /testRoot/test
 /testRoot/test/hello
 /testRoot/test/world
 /testRoot/test2
 
-select * from [nt:base] where id = '1'
+select [jcr:path] from [nt:base] where id = '1'
 /testRoot/test2
 
-select * from [nt:base] where id = '1' and x = '2'
+select [jcr:path] from [nt:base] where id = '1' and x = '2'
 /testRoot/test2
 
-select * from [nt:base] where id = '1' or x = '2'
+select [jcr:path] from [nt:base] where id = '1' or x = '2'
 /testRoot/test/world
 /testRoot/test2
 
-select * from [nt:base] where not (id = '1' or x = '2') and isdescendantnode('/testRoot')
+select [jcr:path] from [nt:base] where not (id = '1' or x = '2') and isdescendantnode('/testRoot')
 /testRoot/test
 /testRoot/test/hello
 
-select * from [nt:base] where x is null and isdescendantnode('/testRoot')
+select [jcr:path] from [nt:base] where x is null and isdescendantnode('/testRoot')
 /testRoot/test
 
 commit /testRoot - "test"
@@ -253,43 +253,43 @@ Hallo
 hello
 World!
 
-select * from [nt:base] where length(name) = 5
+select [jcr:path] from [nt:base] where length(name) = 5
 /testRoot/test
 /testRoot/test3
 
-select * from [nt:base] where upper(name) = 'HELLO'
+select [jcr:path] from [nt:base] where upper(name) = 'HELLO'
 /testRoot/test
 
-select * from [nt:base] where lower(name) = 'world!'
+select [jcr:path] from [nt:base] where lower(name) = 'world!'
 /testRoot/test2
 
-select * from [nt:base] where name like 'W%'
+select [jcr:path] from [nt:base] where name like 'W%'
 /testRoot/test2
 
-select * from [nt:base] where name like '%o_%'
+select [jcr:path] from [nt:base] where name like '%o_%'
 /testRoot/test2
 
-select * from [nt:base] where name like '__llo'
+select [jcr:path] from [nt:base] where name like '__llo'
 /testRoot/test
 /testRoot/test3
 
-select * from [nt:base] where upper(name) like 'H_LLO'
+select [jcr:path] from [nt:base] where upper(name) like 'H_LLO'
 /testRoot/test
 /testRoot/test3
 
-select * from [nt:base] where upper(name) like 'H\_LLO'
+select [jcr:path] from [nt:base] where upper(name) like 'H\_LLO'
 
-select * from [nt:base] where upper(name) like '10%'
+select [jcr:path] from [nt:base] where upper(name) like '10%'
 /testRoot/test4
 /testRoot/test5
 
-select * from [nt:base] where upper(name) like '10\%'
+select [jcr:path] from [nt:base] where upper(name) like '10\%'
 /testRoot/test4
 
 # errors
 
-select * from [nt:base] where name =+ 'Hello'
-java.text.ParseException: Query: select * from [nt:base] where name =+ 'Hello(*)'; expected: Illegal operation: + Hello
+select [jcr:path] from [nt:base] where name =+ 'Hello'
+java.text.ParseException: Query: select [jcr:path] from [nt:base] where name =+ 'Hello(*)'; expected: Illegal operation: + Hello
 
-select * from [nt:base] where name => 'Hello'
-java.text.ParseException: Query: select * from [nt:base] where name =>(*)'Hello'; expected: (, ., =, <>, <, >, <=, >=, LIKE, IS, NOT
+select [jcr:path] from [nt:base] where name => 'Hello'
+java.text.ParseException: Query: select [jcr:path] from [nt:base] where name =>(*)'Hello'; expected: (, ., =, <>, <, >, <=, >=, LIKE, IS, NOT

Modified: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_explain.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_explain.txt?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_explain.txt (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_explain.txt Fri Apr 12 16:44:25 2013
@@ -36,7 +36,7 @@ explain select * from [nt:base] where pr
 explain select b.[jcr:path] as [jcr:path], b.[jcr:score] as [jcr:score], b.* from [nt:base] as a inner join [nt:base] as b on ischildnode(a, b) where name(a) = 'yes' and isdescendantnode(a, '/test') and b.[x] is not null
 [nt:base] as [a] /* traverse "/test//*" where (name([a]) = cast('yes' as string)) and (isdescendantnode([a], [/test])) */ inner join [nt:base] as [b] /* traverse "/path/from/the/join" where [b].[x] is not null */ on ischildnode([a], [b])
 
-select * from [nt:base] where property([*], 'REFERENCE') = CAST('123' AS REFERENCE)
+select [jcr:path] from [nt:base] where property([*], 'REFERENCE') = CAST('123' AS REFERENCE)
 /test/a
 
 commit /oak:index + "indexes": { "type": "property" }
@@ -48,10 +48,10 @@ explain select * from [nt:base] where pr
 explain select * from [nt:base] where property(id, 'REFERENCE') = CAST('123' AS REFERENCE)
 [nt:base] as [nt:base] /* prefixIndex "ref:123" where property([nt:base].[id], 'reference') = cast('123' as reference) */
 
-select * from [nt:base] where property([*], 'REFERENCE') = CAST('123' AS REFERENCE)
+select [jcr:path] from [nt:base] where property([*], 'REFERENCE') = CAST('123' AS REFERENCE)
 /test/a
 
-select * from [nt:base] where property(id, 'REFERENCE') = CAST('123' AS REFERENCE)
+select [jcr:path] from [nt:base] where property(id, 'REFERENCE') = CAST('123' AS REFERENCE)
 /test/a
 
 commit / - "test"
@@ -64,21 +64,21 @@ commit /oak:index/indexes + "property@id
 
 # combining 'not' and 'and'
 
-select * from [nt:base] where id is not null and not id = '100' and id <> '20'
+select [jcr:path] from [nt:base] where id is not null and not id = '100' and id <> '20'
 /test/a
 
-select * from [nt:base] where id is not null and not (id = '100' and id <> '20')
+select [jcr:path] from [nt:base] where id is not null and not (id = '100' and id <> '20')
 /test/a
 /test/b
 
 explain select * from [nt:base] where id = '10'
 [nt:base] as [nt:base] /* propertyIndex "id [10..10]" where [nt:base].[id] = cast('10' as string) */
 
-select * from [nt:base] where id = '10'
+select [jcr:path] from [nt:base] where id = '10'
 /test/a
 
-select [jcr:path], * from [nt:base] where id = '10'
-/test/a, /test/a
+select [jcr:path] from [nt:base] where id = '10'
+/test/a
 
 explain select * from [nt:base] where id > '10'
 [nt:base] as [nt:base] /* traverse "*" where [nt:base].[id] > cast('10' as string) */

Modified: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_index.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_index.txt?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_index.txt (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_index.txt Fri Apr 12 16:44:25 2013
@@ -39,11 +39,11 @@ explain select * from [nt:base] as a inn
 
 commit / + "test": { "jcr:uuid": "xyz", "a": { "jcr:uuid": "123" } }
 
-select * from [nt:base] where [jcr:uuid] is not null
+select [jcr:path] from [nt:base] where [jcr:uuid] is not null
 /test
 /test/a
 
-select * from [nt:base] where [jcr:uuid] = 'xyz'
+select [jcr:path] from [nt:base] where [jcr:uuid] = 'xyz'
 /test
 
 commit / - "test"

Modified: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt Fri Apr 12 16:44:25 2013
@@ -27,7 +27,7 @@ commit / + "testRoot": { }
 commit /testRoot + "parents": { "p0": {"id": "0"}, "p1": {"id": "1"}, "p2": {"id": "2"}}
 commit /testRoot + "children": { "c1": {"p": "1"}, "c2": {"p": "1"}, "c3": {"p": "2"}, "c4": {"p": "3"}}
 
-select * from [nt:base] as c right outer join [nt:base] as p on p.id = c.p where p.id is not null and isdescendantnode(p, '/testRoot') and isdescendantnode(c, '/testRoot')
+select c.[jcr:path], p.[jcr:path] from [nt:base] as c right outer join [nt:base] as p on p.id = c.p where p.id is not null and isdescendantnode(p, '/testRoot') and isdescendantnode(c, '/testRoot')
 /testRoot/children/c1, /testRoot/parents/p1
 /testRoot/children/c2, /testRoot/parents/p1
 /testRoot/children/c3, /testRoot/parents/p2
@@ -37,7 +37,7 @@ c, 30
 p, 10
 query, 3
 
-select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and isdescendantnode(p, '/testRoot') and isdescendantnode(c, '/testRoot')
+select p.[jcr:path], c.[jcr:path] from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and isdescendantnode(p, '/testRoot') and isdescendantnode(c, '/testRoot')
 /testRoot/parents/p1, /testRoot/children/c1
 /testRoot/parents/p1, /testRoot/children/c2
 /testRoot/parents/p2, /testRoot/children/c3

Modified: jackrabbit/oak/trunk/oak-jcr/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/pom.xml?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-jcr/pom.xml Fri Apr 12 16:44:25 2013
@@ -222,9 +222,6 @@
       org.apache.jackrabbit.test.api.query.SQLJoinTest#testJoinNtBase                                <!-- OAK-474 -->
       org.apache.jackrabbit.test.api.query.SQLJoinTest#testJoinFilterPrimaryType                     <!-- OAK-474 -->
       org.apache.jackrabbit.test.api.query.SQLJoinTest#testJoinSNS                                   <!-- OAK-474 -->
-      org.apache.jackrabbit.test.api.query.SimpleSelectionTest#testSingleProperty                    <!-- OAK-323 -->
-      org.apache.jackrabbit.test.api.query.qom.ColumnTest#testExpandColumnsForNodeType               <!-- OAK-323 -->
-      org.apache.jackrabbit.test.api.query.GetPropertyNamesTest#testGetPropertyNames                 <!-- OAK-323 -->
       org.apache.jackrabbit.test.api.observation.EventTest#testGetUserId
       org.apache.jackrabbit.test.api.observation.NodeMovedTest#testMoveNode
       org.apache.jackrabbit.test.api.observation.NodeMovedTest#testMoveTree

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java Fri Apr 12 16:44:25 2013
@@ -18,6 +18,7 @@
  */
 package org.apache.jackrabbit.oak.jcr.query;
 
+import static com.google.common.collect.Sets.newHashSet;
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 import static org.junit.Assert.assertFalse;
@@ -46,6 +47,7 @@ import org.apache.jackrabbit.commons.ite
 import org.apache.jackrabbit.oak.jcr.AbstractRepositoryTest;
 import org.junit.Test;
 
+
 /**
  * Tests the query feature.
  */
@@ -108,11 +110,9 @@ public class QueryTest extends AbstractR
 
         q = qm.createQuery("//*[@id=1]", Query.XPATH);
         r = q.execute();
-        columns = r.getColumnNames();
-        assertEquals(3, columns.length);
-        assertEquals("jcr:path", columns[0]);
-        assertEquals("jcr:score", columns[1]);
-        assertEquals("*", columns[2]);
+        assertEquals(
+                newHashSet("jcr:path", "jcr:score", "jcr:primaryType"),
+                newHashSet(r.getColumnNames()));
     }
 
     @Test

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/qom/QomTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/qom/QomTest.java?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/qom/QomTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/qom/QomTest.java Fri Apr 12 16:44:25 2013
@@ -400,7 +400,7 @@ public class QomTest extends AbstractRep
 
     @Test
     public void createQuery() throws RepositoryException {
-        Selector s = f.selector("nodeTypeName", "x");
+        Selector s = f.selector("nt:file", "x");
         BindVariableValue b = f.bindVariable("var");
         Constraint c = f.propertyExistence("x", "c");
         PropertyValue p = f.propertyValue("x", "propertyName");

Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexQueryTest.java?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexQueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexQueryTest.java Fri Apr 12 16:44:25 2013
@@ -71,7 +71,7 @@ public class LuceneIndexQueryTest extend
         root.commit();
 
         Iterator<String> result = executeQuery(
-                "select * from [nt:base] where isdescendantnode('/test')",
+                "select [jcr:path] from [nt:base] where isdescendantnode('/test')",
                 "JCR-SQL2").iterator();
         assertTrue(result.hasNext());
         assertEquals("/test/a", result.next());
@@ -87,7 +87,7 @@ public class LuceneIndexQueryTest extend
         root.commit();
 
         Iterator<String> result = executeQuery(
-                "select * from [nt:base] where isdescendantnode('/test') and name='World'",
+                "select [jcr:path] from [nt:base] where isdescendantnode('/test') and name='World'",
                 "JCR-SQL2").iterator();
         assertTrue(result.hasNext());
         assertEquals("/test/a", result.next());
@@ -105,7 +105,7 @@ public class LuceneIndexQueryTest extend
         root.commit();
 
         Iterator<String> result = executeQuery(
-                "select * from [nt:base] as p inner join [nt:base] as p2 on ischildnode(p2, p) where p.[jcr:path] = '/'",
+                "select p.[jcr:path], p2.[jcr:path] from [nt:base] as p inner join [nt:base] as p2 on ischildnode(p2, p) where p.[jcr:path] = '/'",
                 "JCR-SQL2").iterator();
         assertTrue(result.hasNext());
         assertEquals("/, /children", result.next());

Modified: jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTest.java?rev=1467342&r1=1467341&r2=1467342&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTest.java Fri Apr 12 16:44:25 2013
@@ -89,7 +89,7 @@ public class SolrIndexQueryTest extends 
         root.commit();
 
         Iterator<String> result = executeQuery(
-                "select * from [nt:base] where isdescendantnode('/test')",
+                "select [jcr:path] from [nt:base] where isdescendantnode('/test')",
                 "JCR-SQL2").iterator();
         assertTrue(result.hasNext());
         assertEquals("/test/a", result.next());
@@ -105,7 +105,7 @@ public class SolrIndexQueryTest extends 
         root.commit();
 
         Iterator<String> result = executeQuery(
-                "select * from [nt:base] where isdescendantnode('/test') and name='World'",
+                "select [jcr:path] from [nt:base] where isdescendantnode('/test') and name='World'",
                 "JCR-SQL2").iterator();
         assertTrue(result.hasNext());
         assertEquals("/test/a", result.next());
@@ -123,7 +123,7 @@ public class SolrIndexQueryTest extends 
         root.commit();
 
         Iterator<String> result = executeQuery(
-                "select * from [nt:base] as p inner join [nt:base] as p2 on ischildnode(p2, p) where p.[jcr:path] = '/'",
+                "select p.[jcr:path], p2.[jcr:path] from [nt:base] as p inner join [nt:base] as p2 on ischildnode(p2, p) where p.[jcr:path] = '/'",
                 "JCR-SQL2").iterator();
         assertTrue(result.hasNext());
         assertEquals("/, /children", result.next());