Author: thomasm Date: Mon Jul 16 08:46:48 2012 New Revision: 1361938 URL: http://svn.apache.org/viewvc?rev=1361938&view=rev Log: OAK-181 Observation / indexing: don't create events for index updates - store the index content in a child node
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTree.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreeLeaf.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreeNode.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreePage.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PrefixIndex.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PrefixIndexTest.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PropertyIndexTest.java jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTree.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTree.java?rev=1361938&r1=1361937&r2=1361938&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTree.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTree.java Mon Jul 16 08:46:48 2012 @@ -37,11 +37,7 @@ public class BTree { this.indexer = indexer; this.name = name; this.unique = unique; - if (!indexer.nodeExists(name)) { - JsopBuilder jsop = new JsopBuilder(); - jsop.tag('+').key(name).object().endObject(); - indexer.commit(jsop.toString()); - } + indexer.createNodes(PathUtils.concat(name, Indexer.INDEX_CONTENT)); } public void setMinSize(int minSize) { @@ -127,7 +123,7 @@ public class BTree { void bufferSetArray(String path, String propertyName, String[] data) { JsopBuilder jsop = new JsopBuilder(); - path = PathUtils.concat(name, path); + path = PathUtils.concat(name, Indexer.INDEX_CONTENT, path); jsop.tag('^').key(PathUtils.concat(path, propertyName)); if (data == null) { jsop.value(null); @@ -151,7 +147,7 @@ public class BTree { void bufferDelete(String path) { JsopBuilder jsop = new JsopBuilder(); - jsop.tag('-').value(PathUtils.concat(name, path)); + jsop.tag('-').value(PathUtils.concat(name, Indexer.INDEX_CONTENT, path)); jsop.newline(); indexer.buffer(jsop.toString()); } @@ -164,7 +160,7 @@ public class BTree { indexer.modified(this, page, false); } - public void moveCache(String oldPath) { + void moveCache(String oldPath) { indexer.moveCache(this, oldPath); } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreeLeaf.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreeLeaf.java?rev=1361938&r1=1361937&r2=1361938&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreeLeaf.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreeLeaf.java Mon Jul 16 08:46:48 2012 @@ -79,8 +79,20 @@ class BTreeLeaf extends BTreePage { void writeCreate() { verify(); tree.modified(this); + tree.buffer(getJsop()); + } + + private void verify() { + if (values.length != keys.length) { + throw new IllegalArgumentException( + "Number of values doesn't match number of keys: " + + Arrays.toString(values) + " " + Arrays.toString(keys)); + } + } + + private String getJsop() { JsopBuilder jsop = new JsopBuilder(); - jsop.tag('+').key(PathUtils.concat(tree.getName(), getPath())).object(); + jsop.tag('+').key(PathUtils.concat(tree.getName(), Indexer.INDEX_CONTENT, getPath())).object(); jsop.key("keys").array(); for (String k : keys) { jsop.value(k); @@ -93,15 +105,12 @@ class BTreeLeaf extends BTreePage { jsop.endArray(); jsop.endObject(); jsop.newline(); - tree.buffer(jsop.toString()); + return jsop.toString(); } - void verify() { - if (values.length != keys.length) { - throw new IllegalArgumentException( - "Number of values doesn't match number of keys: " + - Arrays.toString(values) + " " + Arrays.toString(keys)); - } + @Override + public String toString() { + return "leaf: " + getJsop(); } } \ No newline at end of file Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreeNode.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreeNode.java?rev=1361938&r1=1361937&r2=1361938&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreeNode.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreeNode.java Mon Jul 16 08:46:48 2012 @@ -70,8 +70,8 @@ class BTreeNode extends BTreePage { n2.writeCreate(); for (String c : n2.children) { tree.bufferMove( - PathUtils.concat(tree.getName(), getPath(), c), - PathUtils.concat(tree.getName(), getParentPath(), siblingName, c) + PathUtils.concat(tree.getName(), Indexer.INDEX_CONTENT, getPath(), c), + PathUtils.concat(tree.getName(), Indexer.INDEX_CONTENT, getParentPath(), siblingName, c) ); } tree.moveCache(getPath()); @@ -108,30 +108,7 @@ class BTreeNode extends BTreePage { void writeCreate() { verify(); tree.modified(this); - JsopBuilder jsop = new JsopBuilder(); - jsop.tag('+').key(PathUtils.concat(tree.getName(), getPath())).object(); - jsop.key("keys").array(); - for (String k : keys) { - jsop.value(k); - } - jsop.endArray(); - jsop.key("values").array(); - for (String v : values) { - jsop.value(v); - } - jsop.endArray(); - // could just use child node list, but then - // new children need to be ordered at the right position, - // and we would need a way to distinguish empty lists - // from a leaf - jsop.key("children").array(); - for (String d : children) { - jsop.value(d); - } - jsop.endArray(); - jsop.endObject(); - jsop.newline(); - tree.buffer(jsop.toString()); + tree.buffer(getJsop()); } void delete(int pos) { @@ -157,7 +134,7 @@ class BTreeNode extends BTreePage { return children.length == 0; } - void verify() { + private void verify() { if (values.length != keys.length) { throw new IllegalArgumentException( "Number of values doesn't match number of keys: " + @@ -172,4 +149,36 @@ class BTreeNode extends BTreePage { } } + private String getJsop() { + JsopBuilder jsop = new JsopBuilder(); + jsop.tag('+').key(PathUtils.concat(tree.getName(), Indexer.INDEX_CONTENT, getPath())).object(); + jsop.key("keys").array(); + for (String k : keys) { + jsop.value(k); + } + jsop.endArray(); + jsop.key("values").array(); + for (String v : values) { + jsop.value(v); + } + jsop.endArray(); + // could just use child node list, but then + // new children need to be ordered at the right position, + // and we would need a way to distinguish empty lists + // from a leaf + jsop.key("children").array(); + for (String d : children) { + jsop.value(d); + } + jsop.endArray(); + jsop.endObject(); + jsop.newline(); + return jsop.toString(); + } + + @Override + public String toString() { + return "node: " + getJsop(); + } + } \ No newline at end of file Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreePage.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreePage.java?rev=1361938&r1=1361937&r2=1361938&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreePage.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTreePage.java Mon Jul 16 08:46:48 2012 @@ -44,15 +44,16 @@ abstract class BTreePage { void setParent(BTreeNode newParent, String newName, boolean parentIsNew) { if (newParent != null) { String oldPath = getPath(); + String temp = PathUtils.concat(Indexer.INDEX_CONTENT, "temp"); tree.bufferMove( - PathUtils.concat(tree.getName(), getPath()), - "temp"); + PathUtils.concat(tree.getName(), Indexer.INDEX_CONTENT, getPath()), + temp); if (parentIsNew) { newParent.writeCreate(); } tree.bufferMove( - "temp", - PathUtils.concat(tree.getName(), getParentPath(), newName)); + temp, + PathUtils.concat(tree.getName(), Indexer.INDEX_CONTENT, getParentPath(), newName)); parent = newParent; name = newName; tree.moveCache(oldPath); Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java?rev=1361938&r1=1361937&r2=1361938&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java Mon Jul 16 08:46:48 2012 @@ -42,9 +42,19 @@ import java.util.Map.Entry; */ public class Indexer implements QueryIndexProvider { - // TODO discuss where to store index config data + /** + * The root node of the index definition (configuration) nodes. + */ + // TODO OAK-178 discuss where to store index config data public static final String INDEX_CONFIG_ROOT = "/jcr:system/indexes"; + /** + * For each index, the index content is stored relative to the index + * definition below this node. There is also such a node just below the + * index definition node, to store the last revision and for temporary data. + */ + public static final String INDEX_CONTENT = ":data"; + /** * The node name prefix of a prefix index. */ @@ -109,7 +119,7 @@ public class Indexer implements QueryInd return new Indexer(mk); } - public String getIndexRootNode() { + String getIndexRootNode() { return indexRootNode; } @@ -124,50 +134,37 @@ public class Indexer implements QueryInd indexRootNodeDepth = PathUtils.getDepth(indexRootNode); revision = mk.getHeadRevision(); readRevision = revision; - if (!mk.nodeExists(indexRootNode, revision)) { - JsopBuilder jsop = new JsopBuilder(); - String p = "/"; - for (String e : PathUtils.elements(indexRootNode)) { - p = PathUtils.concat(p, e); - if (!mk.nodeExists(p, revision)) { - jsop.tag('+').key(PathUtils.relativize("/", p)).object().endObject().newline(); - } - } - revision = mk.commit("/", jsop.toString(), revision, null); - } else { - String node = mk.getNodes(indexRootNode, revision, 0, 0, Integer.MAX_VALUE, null); + boolean exists = mk.nodeExists(indexRootNode, revision); + createNodes(INDEX_CONTENT); + if (exists) { + String node = mk.getNodes(indexRootNode, revision, 1, 0, Integer.MAX_VALUE, null); JsopTokenizer t = new JsopTokenizer(node); + NodeMap map = new NodeMap(); t.read('{'); - HashMap<String, String> map = new HashMap<String, String>(); - do { - String key = t.readString(); - t.read(':'); - t.read(); - String value = t.getToken(); - map.put(key, value); - } while (t.matches(',')); - String rev = map.get("rev"); + NodeImpl n = NodeImpl.parse(map, t, 0); + String rev = JsopTokenizer.decodeQuoted(n.getNode(INDEX_CONTENT).getProperty("rev")); if (rev != null) { readRevision = rev; } - for (String k : map.keySet()) { - PropertyIndex prop = PropertyIndex.fromNodeName(this, k); - if (prop != null) { - indexes.put(prop.getIndexNodeName(), prop); - propertyIndexes.put(prop.getPropertyName(), prop); - queryIndexList = null; - } - PrefixIndex pref = PrefixIndex.fromNodeName(this, k); - if (pref != null) { - indexes.put(pref.getIndexNodeName(), pref); - prefixIndexes.put(pref.getPrefix(), pref); - queryIndexList = null; - } - } + for (int i = 0; i < n.getChildNodeCount(); i++) { + String k = n.getChildNodeName(i); + PropertyIndex prop = PropertyIndex.fromNodeName(this, k); + if (prop != null) { + indexes.put(prop.getIndexNodeName(), prop); + propertyIndexes.put(prop.getPropertyName(), prop); + queryIndexList = null; + } + PrefixIndex pref = PrefixIndex.fromNodeName(this, k); + if (pref != null) { + indexes.put(pref.getIndexNodeName(), pref); + prefixIndexes.put(pref.getPrefix(), pref); + queryIndexList = null; + } + } } } - public void removePropertyIndex(String property, boolean unique) { + private void removePropertyIndex(String property, boolean unique) { PropertyIndex index = propertyIndexes.remove(property); indexes.remove(index.getIndexNodeName()); queryIndexList = null; @@ -186,7 +183,7 @@ public class Indexer implements QueryInd return index; } - public void removePrefixIndex(String prefix) { + private void removePrefixIndex(String prefix) { PrefixIndex index = prefixIndexes.remove(prefix); indexes.remove(index.getIndexNodeName()); queryIndexList = null; @@ -210,6 +207,20 @@ public class Indexer implements QueryInd return mk.nodeExists(PathUtils.concat(indexRootNode, name), revision); } + void createNodes(String path) { + String rev = mk.getHeadRevision(); + JsopBuilder jsop = new JsopBuilder(); + String p = "/"; + path = PathUtils.concat(indexRootNode, path); + for (String e : PathUtils.elements(path)) { + p = PathUtils.concat(p, e); + if (!mk.nodeExists(p, rev)) { + jsop.tag('+').key(PathUtils.relativize("/", p)).object().endObject().newline(); + } + } + revision = mk.commit("/", jsop.toString(), rev, null); + } + void commit(String jsop) { revision = mk.commit(indexRootNode, jsop, revision, null); } @@ -221,7 +232,7 @@ public class Indexer implements QueryInd private String getPath(BTree tree, BTreeNode parent, String name) { String p = parent == null ? name : PathUtils.concat(parent.getPath(), name); - String indexRoot = PathUtils.concat(indexRootNode, tree.getName()); + String indexRoot = PathUtils.concat(indexRootNode, tree.getName(), INDEX_CONTENT); return PathUtils.concat(indexRoot, p); } @@ -288,7 +299,7 @@ public class Indexer implements QueryInd void modified(BTree tree, BTreePage page, boolean deleted) { String indexRoot = PathUtils.concat(indexRootNode, tree.getName()); - String p = PathUtils.concat(indexRoot, page.getPath()); + String p = PathUtils.concat(indexRoot, INDEX_CONTENT, page.getPath()); if (deleted) { modified.remove(p); } else { @@ -296,9 +307,9 @@ public class Indexer implements QueryInd } } - public void moveCache(BTree tree, String oldPath) { + void moveCache(BTree tree, String oldPath) { String indexRoot = PathUtils.concat(indexRootNode, tree.getName()); - String o = PathUtils.concat(indexRoot, oldPath); + String o = PathUtils.concat(indexRoot, INDEX_CONTENT, oldPath); HashMap<String, BTreePage> moved = new HashMap<String, BTreePage>(); for (Entry<String, BTreePage> e : modified.entrySet()) { if (e.getKey().startsWith(o)) { @@ -309,12 +320,12 @@ public class Indexer implements QueryInd modified.remove(s); } for (BTreePage p : moved.values()) { - String n = PathUtils.concat(indexRoot, p.getPath()); + String n = PathUtils.concat(indexRoot, INDEX_CONTENT, p.getPath()); modified.put(n, p); } } - void commitChanges() { + private void commitChanges() { if (buffer != null) { String jsop = buffer.toString(); // System.out.println(jsop); @@ -372,21 +383,19 @@ public class Indexer implements QueryInd * @param toRevision the new index revision * @return the new head revision */ - public String updateEnd(String toRevision) { + String updateEnd(String toRevision) { readRevision = toRevision; JsopBuilder jsop = new JsopBuilder(); - jsop.tag('^').key("rev").value(readRevision); + jsop.tag('^').key(PathUtils.concat(INDEX_CONTENT, "rev")).value(readRevision); buffer(jsop.toString()); try { commitChanges(); } catch (MicroKernelException e) { if (!mk.nodeExists(indexRootNode, revision)) { // the index node itself was removed, which is - // unexpected but possible - re-create it - init = false; - init(); - } else { - throw e; + // unexpected but possible + // this will cause all indexes to be removed, so + // it can be ignored here } } return revision; @@ -399,7 +408,7 @@ public class Indexer implements QueryInd * @param t the changes * @param lastRevision */ - public void updateIndex(String rootPath, JsopReader t, String lastRevision) { + void updateIndex(String rootPath, JsopReader t, String lastRevision) { while (true) { int r = t.read(); if (r == JsopReader.END) { Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PrefixIndex.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PrefixIndex.java?rev=1361938&r1=1361937&r2=1361938&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PrefixIndex.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PrefixIndex.java Mon Jul 16 08:46:48 2012 @@ -20,6 +20,7 @@ import java.util.Iterator; import org.apache.jackrabbit.mk.json.JsopReader; import org.apache.jackrabbit.mk.json.JsopTokenizer; import org.apache.jackrabbit.mk.simple.NodeImpl; +import org.apache.jackrabbit.oak.commons.PathUtils; /** * An index for all values with a given prefix. @@ -98,10 +99,11 @@ public class PrefixIndex implements Inde private void addOrRemove(String path, String propertyName, String value, boolean add) { String v = value.substring(prefix.length()); + String p = PathUtils.concat(path, propertyName); if (add) { - tree.add(v, path + "/" + propertyName); + tree.add(v, p); } else { - tree.remove(v, path + "/" + propertyName); + tree.remove(v, p); } } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java?rev=1361938&r1=1361937&r2=1361938&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java Mon Jul 16 08:46:48 2012 @@ -32,7 +32,7 @@ public class PropertyIndex implements In private final BTree tree; private final String propertyName; - public PropertyIndex(Indexer indexer, String propertyName, boolean unique) { + PropertyIndex(Indexer indexer, String propertyName, boolean unique) { this.indexer = indexer; this.propertyName = propertyName; this.tree = new BTree(indexer, Indexer.TYPE_PROPERTY + propertyName + @@ -40,7 +40,7 @@ public class PropertyIndex implements In tree.setMinSize(10); } - public static PropertyIndex fromNodeName(Indexer indexer, String nodeName) { + static PropertyIndex fromNodeName(Indexer indexer, String nodeName) { if (!nodeName.startsWith(Indexer.TYPE_PROPERTY)) { return null; } Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PrefixIndexTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PrefixIndexTest.java?rev=1361938&r1=1361937&r2=1361938&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PrefixIndexTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PrefixIndexTest.java Mon Jul 16 08:46:48 2012 @@ -38,7 +38,9 @@ public class PrefixIndexTest { // meta data String meta = mk.getNodes(Indexer.INDEX_CONFIG_ROOT, head, 1, 0, -1, null); - Assert.assertEquals("{\":childNodeCount\":1,\"prefix@d:\":{\":childNodeCount\":0}}", meta); + + Assert.assertEquals("{\":childNodeCount\":2,\"prefix@d:\":" + + "{\":childNodeCount\":1,\":data\":{}},\":data\":{\":childNodeCount\":0}}", meta); Assert.assertEquals("", getPathList(index, "d:1", head)); @@ -70,7 +72,7 @@ public class PrefixIndexTest { Assert.assertEquals("/test7/b", getPathList(index, "d:4", head)); } - private String getPathList(PrefixIndex index, String value, String revision) { + private static String getPathList(PrefixIndex index, String value, String revision) { StringBuilder buff = new StringBuilder(); int i = 0; for (Iterator<String> it = index.getPaths(value, revision); it.hasNext();) { Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PropertyIndexTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PropertyIndexTest.java?rev=1361938&r1=1361937&r2=1361938&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PropertyIndexTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PropertyIndexTest.java Mon Jul 16 08:46:48 2012 @@ -37,7 +37,8 @@ public class PropertyIndexTest { // meta data String meta = mk.getNodes(Indexer.INDEX_CONFIG_ROOT, head, 1, 0, -1, null); - Assert.assertEquals("{\":childNodeCount\":1,\"property@id,unique\":{\":childNodeCount\":0}}", meta); + Assert.assertEquals("{\":childNodeCount\":2,\":data\":{\":childNodeCount\":0}," + + "\"property@id,unique\":{\":childNodeCount\":1,\":data\":{}}}", meta); String oldHead = head; Modified: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt?rev=1361938&r1=1361937&r2=1361938&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt (original) +++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt Mon Jul 16 08:46:48 2012 @@ -112,6 +112,7 @@ select * from [nt:base] as x where isdes / /jcr:system /jcr:system/indexes +/jcr:system/indexes/:data /test /test/jcr:resource /test/resource @@ -190,6 +191,7 @@ select * from [nt:base] / /jcr:system /jcr:system/indexes +/jcr:system/indexes/:data /test /test/hello /test/world @@ -209,6 +211,7 @@ select * from [nt:base] where not (id = / /jcr:system /jcr:system/indexes +/jcr:system/indexes/:data /test /test/hello @@ -216,6 +219,7 @@ select * from [nt:base] where x is null / /jcr:system /jcr:system/indexes +/jcr:system/indexes/:data /test commit / - "test" @@ -236,6 +240,7 @@ World! null null null +null select * from [nt:base] where length(name) = 5 /test