public static String explainPlain(Session session, String queryExpression) throws RepositoryException { Query query = session.getWorkspace().getQueryManager().createQuery(queryExpression, "JCR-SQL2"); org.modeshape.jcr.api.query.Query msQuery = (org.modeshape.jcr.api.query.Query)query; // Get the query plan without executing it ... org.modeshape.jcr.api.query.QueryResult result = msQuery.explain(); String plan = result.getPlan(); return plan; }
@Override public void run() { JcrSession session = null; try { session = repository().login(); Query query = jcrSql2Query(session, "SELECT * FROM [mix:title]"); startLatch.await(); for (int i = 0; i != numQueriesEachThread; ++i) { // Compute a query plan that should use this index, UNLESS the index is currently undergoing rebuilding... validateQuery()./*rowCount(2L).useIndex("titleNodes")*/validate(query, query.execute()); } } catch (Exception e) { e.printStackTrace(); fail(e.getMessage()); } finally { printMessage("Completing thread"); if (session != null) session.logout(); stopLatch.countDown(); } } };
@FixFor( "MODE-2312" ) @Test public void shouldUseImplicitPathIndex() throws Exception { Node root = session().getRootNode(); Node newNode1 = root.addNode("nodeA"); newNode1.setProperty("foo", "X"); newNode1.addMixin("mix:referenceable"); Node newNode2 = root.addNode("nodeB"); newNode2.setProperty("foo", "Y"); session().save(); // print = true; // Compute a query plan that should use this index ... final String pathValue = newNode1.getPath(); Query query = jcrSql2Query("SELECT [jcr:path] FROM [nt:unstructured] WHERE [jcr:path] = '" + pathValue + "'"); validateQuery().rowCount(1L).useIndex(IndexPlanners.NODE_BY_PATH_INDEX_NAME).validate(query, query.execute()); query = jcrSql2Query("SELECT A.* FROM [nt:unstructured] AS A WHERE A.[jcr:path] = $pathValue"); query.bindValue("pathValue", valueFactory().createValue(pathValue)); validateQuery().rowCount(1L).useIndex(IndexPlanners.NODE_BY_PATH_INDEX_NAME).validate(query, query.execute()); }
bindExtraVariables(uriInfo, session.getValueFactory(), query); org.modeshape.jcr.api.query.QueryResult result = query.explain(); String plan = result.getPlan(); return new RestQueryPlanResult(plan, statement, language, query.getAbstractQueryModelRepresentation());
@Test @FixFor( "MODE-2515" ) public void shouldSupportQueryLimitWithMoreThan100Nodes() throws Exception { registerValueIndex("title", "mix:title", null, "*", "jcr:title", PropertyType.STRING); // Add a node that uses this type ... Node root = session().getRootNode(); int nodeCount = 102; for (int i = 0; i < nodeCount; i++) { Node book = root.addNode("book_" + (i+1)); book.addMixin("mix:title"); book.setProperty("jcr:title", "Title"); } session.save(); // Compute a query plan that should use this index ... Query query = jcrSql2Query("SELECT * FROM [mix:title] as book where book.[jcr:title] = 'Title'"); int limit = nodeCount - 1; query.setLimit(limit); validateQuery().rowCount(limit).useIndex("title").validate(query, query.execute()); limit = nodeCount / 2; query.setLimit(limit); validateQuery().rowCount(limit).useIndex("title").validate(query, query.execute()); }
@Test public void shouldUseSingleColumnStringIndexForQueryWithNoCriteriaOtherThanMixinViaFromClause() throws Exception { registerValueIndex("titleNodes", "mix:title", null, "*", "jcr:mixinTypes", PropertyType.NAME); // print = true; // Add a node that uses this type ... Node root = session().getRootNode(); Node book1 = root.addNode("myFirstBook"); book1.addMixin("mix:title"); book1.setProperty("jcr:title", "The Title"); Node book2 = root.addNode("mySecondBook"); book2.addMixin("mix:title"); book2.setProperty("jcr:title", "A Different Title"); // Create a node that is not a 'mix:title' and therefore won't be included in the SELECT clauses ... Node other = root.addNode("somethingElse"); other.setProperty("propA", "a value for property A"); other.setProperty("jcr:title", "The Title"); session.save(); // Compute a query plan that should use this index ... Query query = jcrSql2Query("SELECT * FROM [mix:title]"); validateQuery().rowCount(2L).useIndex("titleNodes").validate(query, query.execute()); }
public List<T> findWithExplainPlan(String queryExpression) { try { org.modeshape.jcr.api.query.Query query = (org.modeshape.jcr.api.query.Query) getSession().getWorkspace().getQueryManager().createQuery(queryExpression, "JCR-SQL2"); org.modeshape.jcr.api.query.QueryResult result = query.explain(); String plan = result.getPlan(); log.info(plan); return find(queryExpression); } catch (RepositoryException e) { throw new MetadataRepositoryException("Failure while finding entity ", e); } }
@FixFor( "MODE-2312" ) @Test public void shouldUseImplicitIdIndex() throws Exception { Node root = session().getRootNode(); Node newNode1 = root.addNode("nodeA"); newNode1.setProperty("foo", "X"); newNode1.addMixin("mix:referenceable"); Node newNode2 = root.addNode("nodeB"); newNode2.setProperty("foo", "Y"); session().save(); // print = true; // Compute a query plan that should use this index ... final String uuid = newNode1.getIdentifier(); Query query = jcrSql2Query("SELECT [jcr:path] FROM [nt:unstructured] WHERE [jcr:uuid] = '" + uuid + "'"); validateQuery().rowCount(1L).useIndex(IndexPlanners.NODE_BY_ID_INDEX_NAME).validate(query, query.execute()); query = jcrSql2Query("SELECT A.* FROM [nt:unstructured] AS A WHERE A.[jcr:uuid] = $uuidValue"); query.bindValue("uuidValue", valueFactory().createValue(uuid)); validateQuery().rowCount(1L).useIndex(IndexPlanners.NODE_BY_ID_INDEX_NAME).validate(query, query.execute()); }
@Test public void shouldUseSingleColumnStringIndexForQueryWithNoCriteriaOtherThanPrimaryTypeViaFromClause() throws Exception { registerValueIndex("unstructuredNodes", "nt:unstructured", null, "*", "jcr:primaryType", PropertyType.NAME); // print = true; // Add a node that uses this type ... Node root = session().getRootNode(); Node book1 = root.addNode("myFirstBook"); book1.addMixin("mix:title"); book1.setProperty("jcr:title", "The Title"); Node book2 = root.addNode("mySecondBook"); book2.addMixin("mix:title"); book2.setProperty("jcr:title", "A Different Title"); // Create a node that is not a 'mix:title' and therefore won't be included in the SELECT clauses ... Node other = root.addNode("somethingElse"); other.setProperty("propA", "a value for property A"); other.setProperty("jcr:title", "The Title"); session.save(); // Compute a query plan that should use this index ... Query query = jcrSql2Query("SELECT * FROM [nt:unstructured]"); validateQuery().rowCount(3L).useIndex("unstructuredNodes").validate(query, query.execute()); }
@Override public String explain( String query, String language ) throws RepositoryException { logger.trace("Explaining query: {0}", query); // Create the query ... final org.modeshape.jcr.api.query.Query jcrQuery = (org.modeshape.jcr.api.query.Query)getLocalSession().getSession().getWorkspace().getQueryManager().createQuery(query, language); return jcrQuery.explain().getPlan(); }
query.bindValue("author", session.getValueFactory().createValue("author1")); validateQuery() .useNoIndexes() .rowCount(1) .hasNodesAtPaths("/book1") .validate(query, query.execute()); query.bindValue("author", session.getValueFactory().createValue("author2")); final List<String> expectedPaths = new ArrayList<>(Arrays.asList("/book1", "/book2")); validateQuery() .validate(query, query.execute()); assertTrue("Not all paths found: " + expectedPaths, expectedPaths.isEmpty());
@Test public void shouldNotUseSingleColumnStringIndexInQueryAgainstSuperType() throws Exception { registerValueIndex("descriptionIndex", "mix:title", "Index for the 'jcr:title' property on mix:title", "*", "jcr:title", PropertyType.STRING); // print = true; // Add a node that uses this type ... Node root = session().getRootNode(); Node book1 = root.addNode("myFirstBook"); book1.addMixin("mix:title"); book1.setProperty("jcr:title", "The Title"); Node book2 = root.addNode("mySecondBook"); book2.addMixin("mix:title"); book2.setProperty("jcr:title", "A Different Title"); // Create a node that is not a 'mix:title' and therefore won't be included in the query ... Node other = root.addNode("somethingElse"); other.setProperty("propA", "a value for property A"); other.setProperty("jcr:title", "The Title"); session.save(); // Compute a query plan that will NOT use this index, since the selector doesn't match the index's node type. // If we would use this index, the index doesn't know about non-mix:title nodes like the 'other' node ... Query query = jcrSql2Query("SELECT * FROM [nt:base] WHERE [jcr:title] = 'The Title'"); validateQuery().rowCount(2L).validate(query, query.execute()); // Compute a query plan that will NOT use this index, since the selector doesn't match the index's node type. // If we would use this index, the index doesn't know about non-mix:title nodes like the 'other' node ... query = jcrSql2Query("SELECT * FROM [nt:base] WHERE [jcr:title] LIKE '% Title'"); validateQuery().rowCount(3L).validate(query, query.execute()); }
@Override public String explain( String query, String language ) throws RepositoryException { logger.trace("Explaining query: {0}", query); // Create the query ... final org.modeshape.jcr.api.query.Query jcrQuery = (org.modeshape.jcr.api.query.Query)getLocalSession().getSession().getWorkspace().getQueryManager().createQuery(query, language); return jcrQuery.explain().getPlan(); }
query.bindValue("sysName", valueFactory().createValue(newNode1.getIdentifier())); validateQuery().rowCount(1L).useIndex("refIndex").validate(query, query.execute()); query.bindValue("sysName", valueFactory().createValue(newNode1.getIdentifier())); validateQuery().rowCount(1L).useIndex("refIndex").validate(query, query.execute()); query.bindValue("sysName", valueFactory().createValue("X")); validateQuery().rowCount(1L).useIndex("sysIndex").validate(query, query.execute()); query.bindValue("sysName", valueFactory().createValue("X")); validateQuery().rowCount(1L).considerIndexes("refIndex", "sysIndex").validate(query, query.execute());
@Test public void shouldUseSingleColumnDateIndexInQueryAgainstSameNodeType() throws Exception { registerValueIndex("dateIndex", "mix:lastModified", "Date value index", "*", "jcr:lastModified", PropertyType.DATE); // print = true; // Add a node that uses this type ... Node root = session().getRootNode(); Node obj1 = root.addNode("notionalObjectA"); obj1.addMixin("mix:lastModified"); Node obj2 = root.addNode("notionalObjectB"); obj2.addMixin("mix:lastModified"); // Create a node that is not a 'notion:typed' and therefore won't be included in the query ... Node other = root.addNode("somethingElse"); other.setProperty("jcr:lastModified", Calendar.getInstance()); session.save(); // Issues some queries that should use this index ... Query query = jcrSql2Query("SELECT * FROM [mix:lastModified] WHERE [jcr:lastModified] > CAST('2012-10-21T00:00:00.000' AS DATE)"); validateQuery().rowCount(2L).validate(query, query.execute()); query = jcrSql2Query("SELECT * FROM [mix:lastModified] WHERE [jcr:lastModified] < CAST('2999-10-21T00:00:00.000' AS DATE)"); validateQuery().rowCount(2L).validate(query, query.execute()); // Issue a query that does not use this index ... query = jcrSql2Query("SELECT * FROM [nt:unstructured] WHERE [jcr:lastModified] > CAST('2012-10-21T00:00:00.000' AS DATE)"); validateQuery().rowCount(3L).validate(query, query.execute()); }
@FixFor( "MODE-1901" ) @Test public void shouldExplainQueryWithoutExecutingQuery() throws RepositoryException { String sql = "SELECT * FROM [nt:file]"; org.modeshape.jcr.api.query.Query query = session.getWorkspace().getQueryManager().createQuery(sql, Query.JCR_SQL2); org.modeshape.jcr.api.query.QueryResult result = query.explain(); validateQuery().rowCount(0).warnings(0).onlyQueryPlan().validate(query, result); }
@FixFor( "MODE-2307" ) @Test public void shouldUseSingleColumnStringIndexForQueryWithJoin() throws Exception { registerNodeType("nt:typeWithReference"); registerNodeType("nt:typeWithSysName"); registerValueIndex("refIndex", "nt:typeWithReference", null, "*", "referenceId", PropertyType.STRING); registerValueIndex("sysIndex", "nt:typeWithSysName", null, "*", "sysName", PropertyType.STRING); registerNodeTypeIndex("typesIndex", "nt:base", null, "*", "jcr:primaryType", PropertyType.STRING); // print = true; Node root = session().getRootNode(); Node newNode1 = root.addNode("nodeWithSysName", "nt:typeWithSysName"); newNode1.setProperty("sysName", "X"); newNode1.addMixin("mix:referenceable"); Node newNode2 = root.addNode("nodeWithReference", "nt:typeWithReference"); newNode2.setProperty("referenceId", newNode1.getIdentifier()); session.save(); // Compute a query plan that should use this index ... Query query = jcrSql2Query("SELECT A.* FROM [nt:typeWithReference] AS A " + "JOIN [nt:typeWithSysName] AS B ON A.referenceId = B.[jcr:uuid] " // + "WHERE B.sysName = $sysName"); query.bindValue("sysName", valueFactory().createValue("X")); validateQuery().rowCount(1L).considerIndexes("sysIndex", "refIndex", "typesIndex").validate(query, query.execute()); }
@Test public void shouldUseSingleColumnDateAsLongIndexInQueryAgainstSameNodeType() throws Exception { registerValueIndex("dateIndex", "mix:lastModified", "Date value index", "*", "jcr:lastModified", PropertyType.LONG); // print = true; // Add a node that uses this type ... Node root = session().getRootNode(); Node obj1 = root.addNode("notionalObjectA"); obj1.addMixin("mix:lastModified"); Node obj2 = root.addNode("notionalObjectB"); obj2.addMixin("mix:lastModified"); // Create a node that is not a 'notion:typed' and therefore won't be included in the query ... Node other = root.addNode("somethingElse"); other.setProperty("jcr:lastModified", Calendar.getInstance()); session.save(); // Issues some queries that should use this index ... Query query = jcrSql2Query("SELECT * FROM [mix:lastModified] WHERE [jcr:lastModified] > CAST('2012-10-21T00:00:00.000' AS DATE)"); validateQuery().rowCount(2L).validate(query, query.execute()); query = jcrSql2Query("SELECT * FROM [mix:lastModified] WHERE [jcr:lastModified] < CAST('2999-10-21T00:00:00.000' AS DATE)"); validateQuery().rowCount(2L).validate(query, query.execute()); // Issue a query that does not use this index ... query = jcrSql2Query("SELECT * FROM [nt:unstructured] WHERE [jcr:lastModified] > CAST('2012-10-21T00:00:00.000' AS DATE)"); validateQuery().rowCount(3L).validate(query, query.execute()); }
validateQuery().rowCount(2L).useIndex("pathIndex").validate(query, query.execute()); query.bindValue("value", session().getValueFactory().createValue("value1")); validateQuery().rowCount(2L).useIndex("pathIndex").validate(query, query.execute()); validateQuery().rowCount(2L).useIndex("pathIndex").validate(query, query.execute()); query.bindValue("value", session().getValueFactory().createValue("value1")); validateQuery().rowCount(2L).useIndex("pathIndex").validate(query, query.execute()); validateQuery().rowCount(1L).useIndex("titleIndex").validate(query, query.execute()); validateQuery().rowCount(1L).useIndex("titleIndex").validate(query, query.execute());
final QueryManager queryManager = session.getWorkspace().getQueryManager(); final Query query = queryManager.createQuery(sql, Query.JCR_SQL2); final QueryResult result = query.execute();