Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrQueryManager.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrQueryManager.java (revision 2605) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrQueryManager.java (working copy) @@ -119,7 +119,6 @@ class JcrQueryManager implements QueryManager { * @throws InvalidQueryException if expression is invalid or language is unsupported * @throws RepositoryException if the session is no longer live */ - @SuppressWarnings( "deprecation" ) public Query createQuery( String expression, String language, Path storedAtPath ) throws InvalidQueryException, RepositoryException { @@ -144,9 +143,7 @@ class JcrQueryManager implements QueryManager { PlanHints hints = new PlanHints(); hints.showPlan = true; hints.hasFullTextSearch = true; // always include the score - if (Query.XPATH.equals(language)) { - hints.validateColumnExistance = false; - } + hints.validateColumnExistance = false; // see MODE-1055 return resultWith(expression, parser.getLanguage(), command, hints, storedAtPath); } catch (ParsingException e) { // The query is not well-formed and cannot be parsed ... Index: modeshape-jcr/src/main/java/org/modeshape/jcr/query/JcrQueryResult.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/query/JcrQueryResult.java (revision 2605) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/query/JcrQueryResult.java (working copy) @@ -567,7 +567,7 @@ public class JcrQueryResult implements QueryResult, org.modeshape.jcr.api.query. return iterator.jcrDouble(score); } } - return node.getProperty(columnName).getValue(); + return node.hasProperty(columnName) ? node.getProperty(columnName).getValue() : null; } /** @@ -695,7 +695,7 @@ public class JcrQueryResult implements QueryResult, org.modeshape.jcr.api.query. return iterator.jcrDouble(score); } } - return node.getProperty(columnName).getValue(); + return node.hasProperty(columnName) ? node.getProperty(columnName).getValue() : null; } /** Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JcrQueryManagerTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/JcrQueryManagerTest.java (revision 2605) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/JcrQueryManagerTest.java (working copy) @@ -24,7 +24,9 @@ package org.modeshape.jcr; import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNot.not; import static org.hamcrest.core.IsNull.notNullValue; +import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertThat; import java.io.InputStream; import java.net.URI; @@ -331,6 +333,66 @@ public class JcrQueryManagerTest { assertResultsHaveColumns(result, minimumColumnNames()); } + @FixFor( "MODE-1055" ) + @Test + public void shouldBeAbleToCreateAndExecuteJcrSql2QueryToFindAllNodesWithCriteria() throws RepositoryException { + Query query = session.getWorkspace().getQueryManager().createQuery("SELECT * FROM [nt:base] WHERE [car:year] < 2009", + Query.JCR_SQL2); + assertThat(query, is(notNullValue())); + QueryResult result = query.execute(); + assertThat(result, is(notNullValue())); + assertResults(query, result, 13); + assertResultsHaveColumns(result, minimumColumnNames()); + } + + @FixFor( "MODE-1055" ) + @Test + public void shouldReturnNullValuesForNonExistantPropertiesInSelectClauseOfJcrSql2Query() throws RepositoryException { + Query query = session.getWorkspace() + .getQueryManager() + .createQuery("SELECT bogus, laughable, [car:year] FROM [nt:base] WHERE [car:year] < 2009", + Query.JCR_SQL2); + assertThat(query, is(notNullValue())); + QueryResult result = query.execute(); + assertThat(result, is(notNullValue())); + assertResults(query, result, 13); + assertResultsHaveColumns(result, "bogus", "laughable", "car:year"); + RowIterator rows = result.getRows(); + while (rows.hasNext()) { + Row row = rows.nextRow(); + assertThat(row.getValue("bogus"), is(nullValue())); + assertThat(row.getValue("laughable"), is(nullValue())); + assertThat(row.getValue("car:year"), is(not(nullValue()))); + } + } + + @FixFor( "MODE-1055" ) + @Test + public void shouldNotMatchNodesWhenQueryUsesNonExistantPropertyInCriteriaInSelectClauseOfJcrSql2Query() + throws RepositoryException { + Query query = session.getWorkspace() + .getQueryManager() + .createQuery("SELECT bogus, laughable, [car:year] FROM [nt:base] WHERE argle < 2009", Query.JCR_SQL2); + assertThat(query, is(notNullValue())); + QueryResult result = query.execute(); + assertThat(result, is(notNullValue())); + assertResults(query, result, 0); + assertResultsHaveColumns(result, "bogus", "laughable", "car:year"); + } + + @FixFor( "MODE-1055" ) + @Test + public void shouldNotOrderByNonExistantPropertyInCriteriaInSelectClauseOfJcrSql2Query() throws RepositoryException { + Query query = session.getWorkspace() + .getQueryManager() + .createQuery("SELECT bogus, laughable, [car:year] FROM [nt:base] ORDER BY argle", Query.JCR_SQL2); + assertThat(query, is(notNullValue())); + QueryResult result = query.execute(); + assertThat(result, is(notNullValue())); + assertResults(query, result, 24); + assertResultsHaveColumns(result, "bogus", "laughable", "argle", "car:year"); + } + @Test public void shouldBeAbleToCreateAndExecuteJcrSql2QueryToFindAllCarNodes() throws RepositoryException { Query query = session.getWorkspace().getQueryManager().createQuery("SELECT * FROM [car:Car]", Query.JCR_SQL2); @@ -526,13 +588,18 @@ public class JcrQueryManagerTest { } @FixFor( "MODE-829" ) - @Test( expected = RepositoryException.class ) - public void shouldFailToExecuteJcrSql2QueryWithDescendantNodeJoinUsingNonExistantNameColumnOnTypeWithNoResidualProperties() + @Test + public void shouldReturnNoResultsForJcrSql2QueryWithDescendantNodeJoinUsingNonExistantNameColumnOnTypeWithNoResidualProperties() throws RepositoryException { String sql = "SELECT * FROM [nt:base] AS category JOIN [nt:base] AS cars ON ISDESCENDANTNODE(cars,category) WHERE ISCHILDNODE(category,'/Cars') AND cars.name = 'd2'"; Query query = session.getWorkspace().getQueryManager().createQuery(sql, Query.JCR_SQL2); assertThat(query, is(notNullValue())); - query.execute(); + QueryResult result = query.execute(); + assertThat(result, is(notNullValue())); + assertResults(query, result, 0); // no results, because it is a join on an invalid column + assertResultsHaveColumns(result, new String[] {"cars.mode:depth", "cars.mode:localName", "category.jcr:primaryType", + "category.jcr:score", "cars.jcr:score", "category.jcr:path", "cars.jcr:primaryType", "category.mode:localName", + "cars.jcr:path", "category.mode:depth", "cars.jcr:name", "category.jcr:name"}); } @FixFor( "MODE-869" )