You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2008/12/10 21:03:08 UTC

svn commit: r725407 - in /jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc: JCRBlob.java JCRColumn.java JCRConnection.java JCRDriver.java JCRResultSet.java JCRView.java

Author: jukka
Date: Wed Dec 10 12:03:08 2008
New Revision: 725407

URL: http://svn.apache.org/viewvc?rev=725407&view=rev
Log:
jdbc2jcr: Initial support for view configuration through special jdbc:view nodes in the target repository.

Added:
    jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRBlob.java   (with props)
    jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRColumn.java   (with props)
    jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRView.java   (with props)
Modified:
    jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRConnection.java
    jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRDriver.java
    jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRResultSet.java

Added: jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRBlob.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRBlob.java?rev=725407&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRBlob.java (added)
+++ jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRBlob.java Wed Dec 10 12:03:08 2008
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.jdbc;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.sql.Blob;
+import java.sql.SQLException;
+
+import javax.jcr.Node;
+
+class JCRBlob implements Blob {
+
+    private final JCRColumn column;
+
+    private final Node node;
+
+    public JCRBlob(JCRColumn column, Node node) {
+        this.column = column;
+        this.node = node;
+    }
+
+    //------------------------------------------------< Supported operations >
+
+    public InputStream getBinaryStream() throws SQLException {
+        return column.getStream(node);
+    }
+
+    public long length() throws SQLException {
+        return column.getLength(node);
+    }
+
+    //----------------------------------------------< Unsupported operations >
+
+    public byte[] getBytes(long pos, int length) throws SQLException {
+        throw new SQLFeatureNotSupportedException("Blob.getBytes");
+    }
+
+    public long position(byte[] pattern, long start) throws SQLException {
+        throw new SQLFeatureNotSupportedException("Blob.position");
+    }
+
+    public long position(Blob pattern, long start) throws SQLException {
+        throw new SQLFeatureNotSupportedException("Blob.position");
+    }
+
+    public OutputStream setBinaryStream(long pos) throws SQLException {
+        throw new SQLFeatureNotSupportedException("Blob.setBinaryStream");
+    }
+
+    public int setBytes(long pos, byte[] bytes) throws SQLException {
+        throw new SQLFeatureNotSupportedException("Blob.setBytes");
+    }
+
+    public int setBytes(long pos, byte[] bytes, int offset, int len)
+            throws SQLException {
+        throw new SQLFeatureNotSupportedException("Blob.setBytes");
+    }
+
+    public void truncate(long len) throws SQLException {
+        throw new SQLFeatureNotSupportedException("Blob.truncate");
+    }
+
+}

Propchange: jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRBlob.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRColumn.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRColumn.java?rev=725407&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRColumn.java (added)
+++ jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRColumn.java Wed Dec 10 12:03:08 2008
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.jdbc;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.sql.SQLException;
+import java.util.Calendar;
+
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+
+class JCRColumn {
+
+    private final String name;
+
+    private final String path;
+
+    private final int type;
+
+    private final boolean nullable;
+
+    private final boolean isPath;
+
+    private final boolean isName;
+
+    public JCRColumn(String name, String path, int type, boolean nullable) {
+        this.name = name;
+        this.path = path;
+        this.type = type;
+        this.nullable = nullable;
+        this.isPath = path.equals("jcr:path()");
+        this.isName = path.equals("jcr:name()");
+    }
+
+    //-----------------------------------------------------< Column metadata >
+
+    public String getColumnName() {
+        return name;
+    }
+
+    public int getColumnType() {
+        return type;
+    }
+
+    public boolean isNullable() {
+        return nullable;
+    }
+
+    //---------------------------------------------------< Column operations >
+
+    public String getString(Node node) throws SQLException {
+        try {
+            return getValue(node).getString();
+        } catch (PathNotFoundException e) {
+            return "";
+        } catch (ValueFormatException e) {
+            return "";
+        } catch (RepositoryException e) {
+            throw new SQLExceptionWithCause(
+                    "Failed to access property: " + path, e);
+        }
+    }
+
+    public boolean getBoolean(Node node) throws SQLException {
+        try {
+            return getValue(node).getBoolean();
+        } catch (PathNotFoundException e) {
+            return false;
+        } catch (ValueFormatException e) {
+            return false;
+        } catch (RepositoryException e) {
+            throw new SQLExceptionWithCause(
+                    "Failed to access property: " + path, e);
+        }
+    }
+
+    public long getLong(Node node) throws SQLException {
+        try {
+            return getValue(node).getLong();
+        } catch (PathNotFoundException e) {
+            return 0;
+        } catch (ValueFormatException e) {
+            return 0;
+        } catch (RepositoryException e) {
+            throw new SQLExceptionWithCause(
+                    "Failed to access property: " + path, e);
+        }
+    }
+
+    public double getDouble(Node node) throws SQLException {
+        try {
+            return getValue(node).getDouble();
+        } catch (PathNotFoundException e) {
+            return 0.0;
+        } catch (ValueFormatException e) {
+            return 0.0;
+        } catch (RepositoryException e) {
+            throw new SQLExceptionWithCause(
+                    "Failed to access property: " + path, e);
+        }
+    }
+
+    public Calendar getDate(Node node) throws SQLException {
+        try {
+            return getValue(node).getDate();
+        } catch (PathNotFoundException e) {
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTimeInMillis(0);
+            return calendar;
+        } catch (ValueFormatException e) {
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTimeInMillis(0);
+            return calendar;
+        } catch (RepositoryException e) {
+            throw new SQLExceptionWithCause(
+                    "Failed to access property: " + path, e);
+        }
+    }
+
+    public InputStream getStream(Node node) throws SQLException {
+        try {
+            return getValue(node).getStream();
+        } catch (PathNotFoundException e) {
+            return new ByteArrayInputStream(new byte[0]);
+        } catch (RepositoryException e) {
+            throw new SQLExceptionWithCause(
+                    "Failed to access property: " + path, e);
+        }
+    }
+
+    public long getLength(Node node) throws SQLException {
+        try {
+            if (isPath) {
+                return node.getPath().getBytes("UTF-8").length;
+            } else if (isName) {
+                return node.getName().getBytes("UTF-8").length;
+            } else {
+                Property property = node.getProperty(path);
+                if (property.getDefinition().isMultiple()) {
+                    long[] lengths = property.getLengths();
+                    if (lengths.length > 0) {
+                        return lengths[0];
+                    } else {
+                        return 0;
+                    }
+                } else {
+                    return property.getLength();
+                }
+            }
+        } catch (PathNotFoundException e) {
+            return 0;
+        } catch (RepositoryException e) {
+            throw new SQLExceptionWithCause(
+                    "Failed to access property: " + path, e);
+        } catch (UnsupportedEncodingException e) {
+            throw new SQLExceptionWithCause(
+                    "UTF-8 is not supported", e);
+        }
+    }
+
+    private Value getValue(Node node) throws RepositoryException {
+        if (isPath) {
+            return createValue(node, node.getPath());
+        } else if (isName) {
+            return createValue(node, node.getName());
+        } else {
+            Property property = node.getProperty(path);
+            if (property.getDefinition().isMultiple()) {
+                Value[] values = property.getValues();
+                if (values.length > 0) {
+                    return values[0];
+                } else {
+                    throw new PathNotFoundException(
+                            "Empty multivalued property: " + path);
+                }
+            } else {
+                return property.getValue();
+            }
+        }
+    }
+
+    private Value createValue(Node node, String value)
+            throws RepositoryException {
+        return node.getSession().getValueFactory().createValue(value);
+    }
+
+}

Propchange: jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRColumn.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRConnection.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRConnection.java?rev=725407&r1=725406&r2=725407&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRConnection.java (original)
+++ jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRConnection.java Wed Dec 10 12:03:08 2008
@@ -20,27 +20,130 @@
 import java.io.IOException;
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
 
 import org.apache.commons.dbcp.DelegatingConnection;
 import org.apache.commons.io.FileUtils;
 
 class JCRConnection extends DelegatingConnection {
 
+    private static final Map<String, JCRConnection> connections =
+        new HashMap<String, JCRConnection>();
+
+    public synchronized static JCRConnection getConnection(String key)
+            throws SQLException {
+        JCRConnection connection = connections.get(key);
+        if (connection != null) {
+            return connection;
+        } else {
+            throw new SQLException("Connection not found: " + key);
+        }
+    }
+
+    private synchronized static void addConnection(JCRConnection connection) {
+        connections.put(connection.tmp.getPath(), connection);
+    }
+
+    private synchronized static void removeConnection(JCRConnection connection) {
+        connections.remove(connection.tmp.getPath());
+    }
+
     private final File tmp;
 
-    public JCRConnection(Connection connection, File tmp) {
+    private final Session session;
+
+    private final Map<String, JCRView> views = new HashMap<String, JCRView>();
+
+    public JCRConnection(Connection connection, File tmp) throws SQLException {
         super(connection);
         this.tmp = tmp;
+
+        try {
+            session = Fixture.getRepository().login();
+
+            createViews();
+        } catch (RepositoryException e) {
+            throw new SQLExceptionWithCause(
+                    "Unable to access the JCR content repository", e);
+        }
+
+        addConnection(this);
     }
 
+    private void createViews() throws SQLException {
+        Statement statement = getDelegate().createStatement();
+        try {
+            String jdbc = session.getNamespacePrefix("jdbc");
+            QueryManager manager = session.getWorkspace().getQueryManager();
+            Query query = manager.createQuery(
+                    "//element(*," + jdbc + ":view)", Query.XPATH);
+            NodeIterator nodes = query.execute().getNodes();
+            while (nodes.hasNext()) {
+                Node node = nodes.nextNode();
+                try {
+                    createView(statement, node);
+                } catch (RepositoryException e) {
+                    // TODO: log warning
+                }
+            }
+        } catch (RepositoryException e) {
+            throw new SQLExceptionWithCause(
+                    "Failed to initialize JCR views", e);
+        } finally {
+            statement.close();
+        }
+    }
+
+    private void createView(Statement statement, Node node)
+            throws SQLException, RepositoryException {
+        String name = node.getName();
+        String query = node.getProperty("jdbc:query").getString();
+        String columns = node.getProperty("columns").getString();
+        statement.executeUpdate(
+                "CREATE FUNCTION jcr_sql( statement VARCHAR(1000) )"
+                + " RETURNS TABLE ("
+                + " jcr_path VARCHAR(1000)"
+                + " ) LANGUAGE JAVA"
+                + " PARAMETER STYLE DERBY_JDBC_RESULT_SET"
+                + " NO SQL EXTERNAL NAME"
+                + " 'org.apache.jackrabbit.jdbc.JCRResultSet.jcrSQL'");
+        statement.executeUpdate(
+                "CREATE VIEW nt_base AS SELECT * FROM TABLE"
+                + " (jcr_sql('SELECT jcr:path FROM nt:base')) nodes");
+    }
+
+    public JCRView getView(String key) throws SQLException {
+        JCRView view = views.get(key);
+        if (view != null) {
+            return view;
+        } else {
+            throw new SQLException("JCR view not found: " + key);
+        }
+    }
+
+    //-----------------------------------------------------------< ResultSet >
+
     public void close() throws SQLException {
-        super.close();
+        removeConnection(this);
+
         try {
+            session.logout();
             FileUtils.deleteDirectory(tmp);
         } catch (IOException e) {
             throw new SQLExceptionWithCause(
                     "Error removing temporary directory", e);
         }
+
+        super.close();
     }
 
 }

Modified: jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRDriver.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRDriver.java?rev=725407&r1=725406&r2=725407&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRDriver.java (original)
+++ jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRDriver.java Wed Dec 10 12:03:08 2008
@@ -21,7 +21,6 @@
 import java.sql.Connection;
 import java.sql.DriverPropertyInfo;
 import java.sql.SQLException;
-import java.sql.Statement;
 import java.util.Properties;
 
 import org.apache.derby.jdbc.EmbeddedDriver;
@@ -39,22 +38,6 @@
             Connection connection =
                 super.connect("jdbc:derby:" + tmp.getPath(), properties);
 
-            Statement statement = connection.createStatement();
-            try {
-                statement.executeUpdate(
-                        "CREATE FUNCTION jcr_sql( statement VARCHAR(1000) )"
-                        + " RETURNS TABLE ("
-                        + " jcr_path VARCHAR(1000)"
-                        + " ) LANGUAGE JAVA"
-                        + " PARAMETER STYLE DERBY_JDBC_RESULT_SET"
-                        + " NO SQL EXTERNAL NAME"
-                        + " 'org.apache.jackrabbit.jdbc.JCRResultSet.jcrSQL'");
-                statement.executeUpdate(
-                        "CREATE VIEW nt_base AS SELECT * FROM TABLE"
-                        + " (jcr_sql('SELECT jcr:path FROM nt:base')) nodes");
-            } finally {
-                statement.close();
-            }
             return new JCRConnection(connection, tmp);
         } catch (IOException e) {
             throw new SQLExceptionWithCause(

Modified: jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRResultSet.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRResultSet.java?rev=725407&r1=725406&r2=725407&view=diff
==============================================================================
--- jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRResultSet.java (original)
+++ jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRResultSet.java Wed Dec 10 12:03:08 2008
@@ -1,9 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.jackrabbit.jdbc;
 
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.Reader;
-import java.io.UnsupportedEncodingException;
 import java.math.BigDecimal;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -22,161 +36,113 @@
 import java.util.Calendar;
 import java.util.Map;
 
-import javax.jcr.PropertyType;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
 import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.RowIterator;
 
 public class JCRResultSet implements ResultSet {
 
-    private final Session session;
-
-    private final RowIterator rows;
-
-    private final String[] names;
-
-    private Value[] values = null;
-
-    public static ResultSet jcrQuery(String statement, String language)
-            throws RepositoryException {
-        return new JCRResultSet(statement, language);
+    public static ResultSet jcrQuery(String connectionKey, String viewKey)
+        throws SQLException {
+        JCRConnection connection = JCRConnection.getConnection(connectionKey);
+        JCRView view = connection.getView(viewKey);
+        return new JCRResultSet(view);
     }
 
-    public static ResultSet jcrXPath(String statement)
-            throws RepositoryException {
-        return jcrQuery(statement, Query.XPATH);
-    }
+    private final JCRView view;
 
-    public static ResultSet jcrSQL(String statement)
-            throws RepositoryException {
-        return jcrQuery(statement, Query.SQL);
-    }
+    private final NodeIterator nodes;
 
-    private JCRResultSet(String statement, String language)
-            throws RepositoryException {
-        session = Fixture.getRepository().login();
+    private Node node = null;
 
-        QueryManager manager = session.getWorkspace().getQueryManager();
-        Query query = manager.createQuery(statement, language);
-        QueryResult result = query.execute();
-        rows = result.getRows();
-        names = result.getColumnNames();
+    private JCRResultSet(JCRView view) throws SQLException {
+        try {
+            this.view = view;
+            this.nodes = view.executeQuery();
+        } catch (RepositoryException e) {
+            throw new SQLExceptionWithCause("JCR query failure", e);
+        }
     }
 
-    public void close() throws SQLException {
-        session.logout();
+    public ResultSetMetaData getMetaData() {
+        return view;
     }
 
     public boolean next() throws SQLException {
-        if (rows.hasNext()) {
-            try {
-                values = rows.nextRow().getValues();
-            } catch (RepositoryException e) {
-                SQLException exception =
-                    new SQLException("Unable to retrieve a row");
-                exception.initCause(e);
-                throw exception;
-            }
+        if (nodes.hasNext()) {
+            node = nodes.nextNode();
             return true;
         } else {
-            values = null;
+            node = null;
             return false;
         }
     }
 
+    public int findColumn(String columnLabel) throws SQLException {
+        return view.findColumn(columnLabel);
+    }
 
-    public boolean first() throws SQLException {
-        throw new SQLFeatureNotSupportedException("ResultSet.first");
+    public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
+        return view.getBigDecimal(node, columnIndex);
     }
 
-    public boolean absolute(int row) throws SQLException {
-        throw new SQLFeatureNotSupportedException("ResultSet.absolute");
+    public Blob getBlob(int columnIndex) throws SQLException {
+        return view.getBlob(node, columnIndex);
     }
 
-    public void afterLast() throws SQLException {
-        throw new SQLFeatureNotSupportedException("ResultSet.afterLast");
+    public boolean getBoolean(int columnIndex) throws SQLException {
+        return view.getBoolean(node, columnIndex);
     }
 
-    public void beforeFirst() throws SQLException {
-        throw new SQLFeatureNotSupportedException("ResultSet.beforeFirst");
+    public double getDouble(int columnIndex) throws SQLException {
+        return view.getDouble(node, columnIndex);
     }
 
-    public void cancelRowUpdates() throws SQLException {
+    public long getLong(int columnIndex) throws SQLException {
+        return view.getLong(node, columnIndex);
     }
 
-    public void clearWarnings() throws SQLException {
+    public Object getObject(int columnIndex) throws SQLException {
+        return getString(columnIndex); // TODO: more types
     }
 
-    public void deleteRow() throws SQLException {
-        throw new SQLFeatureNotSupportedException("ResultSet.deleteRow");
+    public String getString(int columnIndex) throws SQLException {
+        return view.getString(node, columnIndex);
     }
 
-    public int findColumn(String columnLabel) throws SQLException {
-        for (int i = 0; i < names.length; i++) {
-            if (names[i].equals(columnLabel)) {
-                return i + 1;
-            }
-        }
-        throw new SQLException("Column not found: " + columnLabel);
+    public Timestamp getTimestamp(int columnIndex) throws SQLException {
+        return new Timestamp(view.getDate(node, columnIndex).getTimeInMillis());
     }
 
-    public Array getArray(int columnIndex) throws SQLException {
-        throw new SQLFeatureNotSupportedException("ResultSet.getArray");
+    //--------------------------------------------------< Derived operations >
+
+    public boolean relative(int rows) throws SQLException {
+        while (rows-- > 0) {
+            if (!next()) {
+                return false;
+            }
+        }
+        if (rows < 0) {
+            throw new SQLFeatureNotSupportedException("ResultSet.relative(< 0)");
+        }
+        return node != null;
     }
 
     public Array getArray(String columnLabel) throws SQLException {
         return getArray(findColumn(columnLabel));
     }
 
-    public InputStream getAsciiStream(int columnIndex) throws SQLException {
-        throw new SQLFeatureNotSupportedException("ResultSet.getAsciiStream");
-    }
-
     public InputStream getAsciiStream(String columnLabel) throws SQLException {
         return getAsciiStream(findColumn(columnLabel));
     }
 
-    private SQLException newSQLException(String message, Throwable cause) {
-        SQLException exception = new SQLException(message);
-        exception.initCause(cause);
-        return exception;
-    }
-
-    private Value getValue(int column) throws SQLException {
-        if (values == null) {
-            throw new SQLException("No current row");
-        } else if (column < 1 && column > values.length) {
-            throw new SQLException("Invalid column: " + column);
-        } else {
-            return values[column - 1];
-        }
-    }
-
-    public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
-        Value value = getValue(columnIndex);
-        try {
-            if (value.getType() == PropertyType.LONG) {
-                return new BigDecimal(value.getLong());
-            } else {
-                return new BigDecimal(value.getDouble());
-            }
-        } catch (RepositoryException e) {
-            throw newSQLException("Invalid value: " + value, e);
-        }
-    }
-
     public BigDecimal getBigDecimal(String columnLabel) throws SQLException {
         return getBigDecimal(findColumn(columnLabel));
     }
 
     public BigDecimal getBigDecimal(int columnIndex, int scale)
             throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
+        return getBigDecimal(columnIndex);
     }
 
     public BigDecimal getBigDecimal(String columnLabel, int scale)
@@ -185,36 +151,17 @@
     }
 
     public InputStream getBinaryStream(int columnIndex) throws SQLException {
-        Value value = getValue(columnIndex);
-        try {
-            return value.getStream();
-        } catch (RepositoryException e) {
-            throw newSQLException("Invalid value: " + value, e);
-        }
+        return getBlob(columnIndex).getBinaryStream();
     }
 
     public InputStream getBinaryStream(String columnLabel) throws SQLException {
         return getBinaryStream(findColumn(columnLabel));
     }
 
-    public Blob getBlob(int columnIndex) throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
     public Blob getBlob(String columnLabel) throws SQLException {
         return getBlob(findColumn(columnLabel));
     }
 
-    public boolean getBoolean(int columnIndex) throws SQLException {
-        Value value = getValue(columnIndex);
-        try {
-            return value.getBoolean();
-        } catch (RepositoryException e) {
-            throw newSQLException("Invalid value: " + value, e);
-        }
-    }
-
     public boolean getBoolean(String columnLabel) throws SQLException {
         return getBoolean(findColumn(columnLabel));
     }
@@ -228,54 +175,23 @@
     }
 
     public byte[] getBytes(int columnIndex) throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
+        return getBlob(columnIndex).getBytes(0, Integer.MAX_VALUE);
     }
 
     public byte[] getBytes(String columnLabel) throws SQLException {
         return getBytes(findColumn(columnLabel));
     }
 
-    public Reader getCharacterStream(int columnIndex) throws SQLException {
-        Value value = getValue(columnIndex);
-        try {
-            return new InputStreamReader(value.getStream(), "UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            throw newSQLException("UTF-8 is not supported", e);
-        } catch (RepositoryException e) {
-            throw newSQLException("Invalid value: " + value, e);
-        }
-    }
-
     public Reader getCharacterStream(String columnLabel) throws SQLException {
         return getCharacterStream(findColumn(columnLabel));
     }
 
-    public Clob getClob(int columnIndex) throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
     public Clob getClob(String columnLabel) throws SQLException {
         return getClob(findColumn(columnLabel));
     }
 
-    public int getConcurrency() throws SQLException {
-        return CONCUR_READ_ONLY;
-    }
-
-    public String getCursorName() throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
     public Date getDate(int columnIndex) throws SQLException {
-        Value value = getValue(columnIndex);
-        try {
-            return new Date(value.getDate().getTimeInMillis());
-        } catch (RepositoryException e) {
-            throw newSQLException("Invalid value: " + value, e);
-        }
+        return new Date(getTimestamp(columnIndex).getTime());
     }
 
     public Date getDate(String columnLabel) throws SQLException {
@@ -283,37 +199,17 @@
     }
 
     public Date getDate(int columnIndex, Calendar cal) throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
+        return getDate(columnIndex);
     }
 
     public Date getDate(String columnLabel, Calendar cal) throws SQLException {
         return getDate(findColumn(columnLabel), cal);
     }
 
-    public double getDouble(int columnIndex) throws SQLException {
-        Value value = getValue(columnIndex);
-        try {
-            return value.getDouble();
-        } catch (RepositoryException e) {
-            throw newSQLException("Invalid value: " + value, e);
-        }
-    }
-
     public double getDouble(String columnLabel) throws SQLException {
         return getDouble(findColumn(columnLabel));
     }
 
-    public int getFetchDirection() throws SQLException {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
-    public int getFetchSize() throws SQLException {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
     public float getFloat(int columnIndex) throws SQLException {
         return (float) getDouble(columnIndex);
     }
@@ -322,11 +218,6 @@
         return getFloat(findColumn(columnLabel));
     }
 
-    public int getHoldability() throws SQLException {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
     public int getInt(int columnIndex) throws SQLException {
         return (int) getLong(columnIndex);
     }
@@ -335,55 +226,25 @@
         return getInt(findColumn(columnLabel));
     }
 
-    public long getLong(int columnIndex) throws SQLException {
-        Value value = getValue(columnIndex);
-        try {
-            return value.getLong();
-        } catch (RepositoryException e) {
-            throw newSQLException("Invalid value: " + value, e);
-        }
-    }
-
     public long getLong(String columnLabel) throws SQLException {
         return getLong(findColumn(columnLabel));
     }
 
-    public ResultSetMetaData getMetaData() throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public Reader getNCharacterStream(int columnIndex) throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
     public Reader getNCharacterStream(String columnLabel) throws SQLException {
         return getNCharacterStream(findColumn(columnLabel));
     }
 
-    public String getNString(int columnIndex) throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
     public String getNString(String columnLabel) throws SQLException {
         return getNString(findColumn(columnLabel));
     }
 
-    public Object getObject(int columnIndex) throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
     public Object getObject(String columnLabel) throws SQLException {
         return getObject(findColumn(columnLabel));
     }
 
     public Object getObject(int columnIndex, Map<String, Class<?>> map)
             throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
+        return getObject(columnIndex);
     }
 
     public Object getObject(String columnLabel, Map<String, Class<?>> map)
@@ -391,20 +252,6 @@
         return getObject(findColumn(columnLabel), map);
     }
 
-    public Ref getRef(int columnIndex) throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public Ref getRef(String columnLabel) throws SQLException {
-        return getRef(findColumn(columnLabel));
-    }
-
-    public int getRow() throws SQLException {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
     public short getShort(int columnIndex) throws SQLException {
         return (short) getLong(columnIndex);
     }
@@ -413,31 +260,12 @@
         return getShort(findColumn(columnLabel));
     }
 
-    public Statement getStatement() throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public String getString(int columnIndex) throws SQLException {
-        Value value = getValue(columnIndex);
-        try {
-            return value.getString();
-        } catch (RepositoryException e) {
-            throw newSQLException("Invalid value: " + value, e);
-        }
-    }
-
     public String getString(String columnLabel) throws SQLException {
         return getString(findColumn(columnLabel));
     }
 
     public Time getTime(int columnIndex) throws SQLException {
-        Value value = getValue(columnIndex);
-        try {
-            return new Time(value.getDate().getTimeInMillis());
-        } catch (RepositoryException e) {
-            throw newSQLException("Invalid value: " + value, e);
-        }
+        return new Time(getTimestamp(columnIndex).getTime());
     }
 
     public Time getTime(String columnLabel) throws SQLException {
@@ -445,31 +273,20 @@
     }
 
     public Time getTime(int columnIndex, Calendar cal) throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
+        return getTime(columnIndex);
     }
 
     public Time getTime(String columnLabel, Calendar cal) throws SQLException {
         return getTime(findColumn(columnLabel), cal);
     }
 
-    public Timestamp getTimestamp(int columnIndex) throws SQLException {
-        Value value = getValue(columnIndex);
-        try {
-            return new Timestamp(value.getDate().getTimeInMillis());
-        } catch (RepositoryException e) {
-            throw newSQLException("Invalid value: " + value, e);
-        }
-    }
-
     public Timestamp getTimestamp(String columnLabel) throws SQLException {
         return getTimestamp(findColumn(columnLabel));
     }
 
     public Timestamp getTimestamp(int columnIndex, Calendar cal)
             throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
+        return getTimestamp(columnIndex);
     }
 
     public Timestamp getTimestamp(String columnLabel, Calendar cal)
@@ -477,18 +294,11 @@
         return getTimestamp(findColumn(columnLabel), cal);
     }
 
-    public int getType() throws SQLException {
-        return TYPE_FORWARD_ONLY;
-    }
-
     public URL getURL(int columnIndex) throws SQLException {
-        Value value = getValue(columnIndex);
         try {
-            return new URL(value.getString());
+            return new URL(getString(columnIndex));
         } catch (MalformedURLException e) {
-            throw newSQLException("Invalid URL: " + value, e);
-        } catch (RepositoryException e) {
-            throw newSQLException("Invalid value: " + value, e);
+            return null;
         }
     }
 
@@ -496,106 +306,185 @@
         return getURL(findColumn(columnLabel));
     }
 
-    public InputStream getUnicodeStream(int columnIndex) throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
+    public Ref getRef(String columnLabel) throws SQLException {
+        return getRef(findColumn(columnLabel));
     }
 
     public InputStream getUnicodeStream(String columnLabel) throws SQLException {
         return getUnicodeStream(findColumn(columnLabel));
     }
 
-    public SQLWarning getWarnings() throws SQLException {
-        return null;
-    }
+    //--------------------------------------------------------< Fixed values >
 
-    public void insertRow() throws SQLException {
-        // TODO Auto-generated method stub
+    public boolean isClosed() {
+        return false;
+    }
 
+    public int getConcurrency() {
+        return CONCUR_READ_ONLY;
     }
 
-    public boolean isAfterLast() throws SQLException {
-        // TODO Auto-generated method stub
+    public boolean wasNull() {
         return false;
     }
 
-    public boolean isBeforeFirst() throws SQLException {
-        // TODO Auto-generated method stub
+    public boolean rowDeleted() {
         return false;
     }
 
-    public boolean isClosed() throws SQLException {
-        return !session.isLive();
+    public boolean rowInserted() {
+        return false;
     }
 
-    public boolean isFirst() throws SQLException {
-        // TODO Auto-generated method stub
+    public boolean rowUpdated() {
         return false;
     }
 
-    public boolean isLast() throws SQLException {
-        // TODO Auto-generated method stub
-        return false;
+    public SQLWarning getWarnings() {
+        return null;
     }
 
-    public boolean last() throws SQLException {
-        // TODO Auto-generated method stub
-        return false;
+    public int getType() throws SQLException {
+        return TYPE_FORWARD_ONLY;
     }
 
-    public void moveToCurrentRow() throws SQLException {
-        // TODO Auto-generated method stub
+    //--------------------------------------------------< Ignored operations >
 
+    public void close() {
     }
 
-    public void moveToInsertRow() throws SQLException {
-        // TODO Auto-generated method stub
+    public void cancelRowUpdates() {
+    }
 
+    public void clearWarnings() {
     }
 
-    public boolean previous() throws SQLException {
-        // TODO Auto-generated method stub
-        return false;
+    public void moveToCurrentRow() {
     }
 
-    public void refreshRow() throws SQLException {
-        // TODO Auto-generated method stub
+    public void refreshRow() {
+    }
 
+    //----------------------------------------------< Unsupported operations >
+
+    public boolean first() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.first");
     }
 
-    public boolean relative(int rows) throws SQLException {
-        // TODO Auto-generated method stub
-        return false;
+    public boolean absolute(int row) throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.absolute");
     }
 
-    public boolean rowDeleted() throws SQLException {
-        // TODO Auto-generated method stub
-        return false;
+    public void afterLast() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.afterLast");
     }
 
-    public boolean rowInserted() throws SQLException {
-        // TODO Auto-generated method stub
-        return false;
+    public void beforeFirst() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.beforeFirst");
     }
 
-    public boolean rowUpdated() throws SQLException {
-        // TODO Auto-generated method stub
-        return false;
+    public void deleteRow() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.deleteRow");
     }
 
-    public void setFetchDirection(int direction) throws SQLException {
-        // TODO Auto-generated method stub
+    public Array getArray(int columnIndex) throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getArray");
+    }
 
+    public InputStream getAsciiStream(int columnIndex) throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getAsciiStream");
     }
 
-    public void setFetchSize(int rows) throws SQLException {
-        // TODO Auto-generated method stub
+    public Reader getCharacterStream(int columnIndex) throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getCharacterStream");
+    }
 
+    public Clob getClob(int columnIndex) throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getCharacterStream");
     }
 
-    public void updateArray(int columnIndex, Array x) throws SQLException {
-        // TODO Auto-generated method stub
+    public String getCursorName() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getCursorName");
+    }
+
+    public int getFetchDirection() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getFetchDirection");
+    }
+
+    public int getFetchSize() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getFetchSize");
+    }
+
+    public int getHoldability() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getHoldability");
+    }
+
+    public Reader getNCharacterStream(int columnIndex) throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getNCharacterStream");
+    }
+
+    public String getNString(int columnIndex) throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getNString");
+    }
+
+    public Ref getRef(int columnIndex) throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getRef");
+    }
+
+    public int getRow() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getRow");
+    }
+
+    public Statement getStatement() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getStatement");
+    }
+
+    public InputStream getUnicodeStream(int columnIndex) throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.getUnicodeStream");
+    }
+
+    public void insertRow() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.insertRow");
+    }
+
+    public boolean isAfterLast() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.isAfterLast");
+    }
+
+    public boolean isBeforeFirst() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.isBeforeFirst");
+    }
+
+    public boolean isFirst() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.isFirst");
+    }
+
+    public boolean isLast() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.isLast");
+    }
+
+    public boolean last() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.last");
+    }
 
+    public void moveToInsertRow() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.moveToInsertRow");
+    }
+
+    public boolean previous() throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.previous");
+    }
+
+    public void setFetchDirection(int direction) throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.setFetchDirection");
+    }
+
+    public void setFetchSize(int rows) throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.setFetchSize");
+    }
+
+    public void updateArray(int columnIndex, Array x) throws SQLException {
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateArray(String columnLabel, Array x) throws SQLException {
@@ -605,8 +494,7 @@
 
     public void updateAsciiStream(int columnIndex, InputStream x)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateAsciiStream(String columnLabel, InputStream x)
@@ -617,8 +505,7 @@
 
     public void updateAsciiStream(int columnIndex, InputStream x, int length)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateAsciiStream(String columnLabel, InputStream x, int length)
@@ -629,8 +516,7 @@
 
     public void updateAsciiStream(int columnIndex, InputStream x, long length)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateAsciiStream(String columnLabel, InputStream x, long length)
@@ -641,8 +527,7 @@
 
     public void updateBigDecimal(int columnIndex, BigDecimal x)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateBigDecimal(String columnLabel, BigDecimal x)
@@ -653,8 +538,7 @@
 
     public void updateBinaryStream(int columnIndex, InputStream x)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateBinaryStream(String columnLabel, InputStream x)
@@ -665,8 +549,7 @@
 
     public void updateBinaryStream(int columnIndex, InputStream x, int length)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateBinaryStream(String columnLabel, InputStream x, int length)
@@ -677,8 +560,7 @@
 
     public void updateBinaryStream(int columnIndex, InputStream x, long length)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateBinaryStream(String columnLabel, InputStream x,
@@ -688,8 +570,7 @@
     }
 
     public void updateBlob(int columnIndex, Blob x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateBlob(String columnLabel, Blob x) throws SQLException {
@@ -699,8 +580,7 @@
 
     public void updateBlob(int columnIndex, InputStream inputStream)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateBlob(String columnLabel, InputStream inputStream)
@@ -711,8 +591,7 @@
 
     public void updateBlob(int columnIndex, InputStream inputStream, long length)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateBlob(String columnLabel, InputStream inputStream,
@@ -722,8 +601,7 @@
     }
 
     public void updateBoolean(int columnIndex, boolean x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateBoolean(String columnLabel, boolean x)
@@ -733,8 +611,7 @@
     }
 
     public void updateByte(int columnIndex, byte x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateByte(String columnLabel, byte x) throws SQLException {
@@ -743,8 +620,7 @@
     }
 
     public void updateBytes(int columnIndex, byte[] x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateBytes(String columnLabel, byte[] x) throws SQLException {
@@ -754,8 +630,7 @@
 
     public void updateCharacterStream(int columnIndex, Reader x)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateCharacterStream(String columnLabel, Reader reader)
@@ -766,8 +641,7 @@
 
     public void updateCharacterStream(int columnIndex, Reader x, int length)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateCharacterStream(String columnLabel, Reader reader,
@@ -778,8 +652,7 @@
 
     public void updateCharacterStream(int columnIndex, Reader x, long length)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateCharacterStream(String columnLabel, Reader reader,
@@ -789,8 +662,7 @@
     }
 
     public void updateClob(int columnIndex, Clob x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateClob(String columnLabel, Clob x) throws SQLException {
@@ -799,8 +671,7 @@
     }
 
     public void updateClob(int columnIndex, Reader reader) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateClob(String columnLabel, Reader reader)
@@ -811,8 +682,7 @@
 
     public void updateClob(int columnIndex, Reader reader, long length)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateClob(String columnLabel, Reader reader, long length)
@@ -822,8 +692,7 @@
     }
 
     public void updateDate(int columnIndex, Date x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateDate(String columnLabel, Date x) throws SQLException {
@@ -832,8 +701,7 @@
     }
 
     public void updateDouble(int columnIndex, double x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateDouble(String columnLabel, double x) throws SQLException {
@@ -842,8 +710,7 @@
     }
 
     public void updateFloat(int columnIndex, float x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateFloat(String columnLabel, float x) throws SQLException {
@@ -852,8 +719,7 @@
     }
 
     public void updateInt(int columnIndex, int x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateInt(String columnLabel, int x) throws SQLException {
@@ -862,8 +728,7 @@
     }
 
     public void updateLong(int columnIndex, long x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateLong(String columnLabel, long x) throws SQLException {
@@ -873,8 +738,7 @@
 
     public void updateNCharacterStream(int columnIndex, Reader x)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateNCharacterStream(String columnLabel, Reader reader)
@@ -885,8 +749,7 @@
 
     public void updateNCharacterStream(int columnIndex, Reader x, long length)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateNCharacterStream(String columnLabel, Reader reader,
@@ -895,8 +758,7 @@
     }
 
     public void updateNClob(int columnIndex, Reader reader) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateNClob(String columnLabel, Reader reader)
@@ -907,8 +769,7 @@
 
     public void updateNClob(int columnIndex, Reader reader, long length)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateNClob(String columnLabel, Reader reader, long length)
@@ -919,8 +780,7 @@
 
     public void updateNString(int columnIndex, String string)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateNString(String columnLabel, String string)
@@ -930,8 +790,7 @@
     }
 
     public void updateNull(int columnIndex) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateNull(String columnLabel) throws SQLException {
@@ -940,8 +799,7 @@
     }
 
     public void updateObject(int columnIndex, Object x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateObject(String columnLabel, Object x) throws SQLException {
@@ -951,8 +809,7 @@
 
     public void updateObject(int columnIndex, Object x, int scaleOrLength)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateObject(String columnLabel, Object x, int scaleOrLength)
@@ -962,8 +819,7 @@
     }
 
     public void updateRef(int columnIndex, Ref x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateRef(String columnLabel, Ref x) throws SQLException {
@@ -972,13 +828,11 @@
     }
 
     public void updateRow() throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateShort(int columnIndex, short x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateShort(String columnLabel, short x) throws SQLException {
@@ -987,8 +841,7 @@
     }
 
     public void updateString(int columnIndex, String x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateString(String columnLabel, String x) throws SQLException {
@@ -997,8 +850,7 @@
     }
 
     public void updateTime(int columnIndex, Time x) throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateTime(String columnLabel, Time x) throws SQLException {
@@ -1008,8 +860,7 @@
 
     public void updateTimestamp(int columnIndex, Timestamp x)
             throws SQLException {
-        // TODO Auto-generated method stub
-
+        throw new SQLFeatureNotSupportedException("ResultSet.update...");
     }
 
     public void updateTimestamp(String columnLabel, Timestamp x)
@@ -1018,19 +869,4 @@
 
     }
 
-    public boolean wasNull() throws SQLException {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    public boolean isWrapperFor(Class<?> iface) throws SQLException {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    public <T> T unwrap(Class<T> iface) throws SQLException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
 }

Added: jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRView.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRView.java?rev=725407&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRView.java (added)
+++ jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRView.java Wed Dec 10 12:03:08 2008
@@ -0,0 +1,326 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.jdbc;
+
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.sql.Blob;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+
+class JCRView implements ResultSetMetaData {
+
+    private final Session session;
+
+    private final String name;
+
+    private final String query;
+
+    private final String language;
+
+    private final List<JCRColumn> columns = new ArrayList<JCRColumn>();
+
+    public JCRView(Node node)
+            throws RepositoryException {
+        this.session = node.getSession();
+
+        if (node.hasProperty("name")) {
+            this.name = node.getProperty("name").getString();
+        } else {
+            this.name = node.getName();
+        }
+
+        if (node.hasProperty("query")) {
+            this.query = node.getProperty("query").getString();
+        } else {
+            this.query = "//*";
+        }
+
+        if (node.hasProperty("language")) {
+            this.language = node.getProperty("language").getString();
+        } else {
+            this.language = Query.XPATH;
+        }
+
+        columns.add(new JCRColumn(
+                "jcr_path", "jcr:path()", Types.VARCHAR, false));
+        columns.add(new JCRColumn(
+                "jcr_name", "jcr:name()", Types.VARCHAR, false));
+        columns.add(new JCRColumn(
+                "jcr_primaryType", "jcr:primaryType", Types.VARCHAR, false));
+        columns.add(new JCRColumn(
+                "jcr_mixinTypes", "jcr:mixinTypes", Types.ARRAY, false));
+
+        String jdbc = session.getNamespacePrefix("jdbc");
+        NodeIterator nodes = node.getNodes();
+        while (nodes.hasNext()) {
+            Node column = nodes.nextNode();
+            if (column.isNodeType(jdbc + ":column")) {
+                String name = column.getName();
+ 
+                boolean multiple = false;
+                if (node.hasProperty("multiple")) {
+                    multiple = node.getProperty("multiple").getBoolean();
+                }
+
+                int type = Types.VARCHAR;
+                if (multiple) {
+                    type = Types.ARRAY;
+                } else if (node.hasProperty("type")) {
+                    String typeName = node.getProperty("type").getString();
+                    if (typeName.equalsIgnoreCase(
+                            PropertyType.TYPENAME_BINARY)) {
+                        type = Types.BLOB;
+                    } else if (typeName.equalsIgnoreCase(
+                            PropertyType.TYPENAME_BOOLEAN)) {
+                        type = Types.BOOLEAN;
+                    } else if (typeName.equalsIgnoreCase(
+                            PropertyType.TYPENAME_DATE)) {
+                        type = Types.TIMESTAMP;
+                    } else if (typeName.equalsIgnoreCase(
+                            PropertyType.TYPENAME_DOUBLE)) {
+                        type = Types.DOUBLE;
+                    } else if (typeName.equalsIgnoreCase(
+                            PropertyType.TYPENAME_LONG)) {
+                        type = Types.BIGINT;
+                    }
+                }
+
+                String path = name;
+                if (node.hasProperty("path")) {
+                    path = node.getProperty("path").getString();
+                }
+
+                columns.add(new JCRColumn(name, path, type, true));
+            }
+        }
+    }
+
+    private JCRColumn getColumn(int index) throws SQLException {
+        if (index < 1 || index > columns.size()) {
+            throw new SQLException("Invalid column index: " + index);
+        } else {
+            return columns.get(index - 1);
+        }
+    }
+
+    public int findColumn(String columnLabel) throws SQLException {
+        int index = 1;
+        for (JCRColumn column : columns) {
+            if (column.getColumnName().equalsIgnoreCase(columnLabel)) {
+                return index;
+            } else {
+                index++;
+            }
+        }
+        throw new SQLException("Column not found: " + columnLabel);
+    }
+
+    public NodeIterator executeQuery() throws RepositoryException {
+        QueryManager manager = session.getWorkspace().getQueryManager();
+        return manager.createQuery(query, language).execute().getNodes();
+    }
+
+    public BigDecimal getBigDecimal(Node node, int index) throws SQLException {
+        JCRColumn column = getColumn(index);
+        if (column.getColumnType() == Types.BIGINT) {
+            return new BigDecimal(column.getLong(node));
+        } else {
+            return new BigDecimal(column.getDouble(node));
+        }
+    }
+
+    public Blob getBlob(Node node, int index) throws SQLException {
+        return new JCRBlob(getColumn(index), node);
+    }
+
+    public boolean getBoolean(Node node, int index) throws SQLException {
+        return getColumn(index).getBoolean(node);
+    }
+
+    public double getDouble(Node node, int index) throws SQLException {
+        return getColumn(index).getDouble(node);
+    }
+
+    public long getLong(Node node, int index) throws SQLException {
+        return getColumn(index).getLong(node);
+    }
+
+    public String getString(Node node, int index) throws SQLException {
+        return getColumn(index).getString(node);
+    }
+
+    public Calendar getDate(Node node, int index) throws SQLException {
+        return getColumn(index).getDate(node);
+    }
+
+    //-------------------------------------------------------< View metadata >
+
+    public String getCatalogName(int column) {
+        return ""; // not applicable
+    }
+
+    public String getSchemaName(int column) {
+        return ""; // not applicable
+    }
+
+    public String getTableName(int column) {
+        return name;
+    }
+
+    public int getColumnCount() {
+        return columns.size();
+    }
+
+    public String getColumnName(int column) throws SQLException {
+        return getColumn(column).getColumnName();
+    }
+
+    public int getColumnType(int column) throws SQLException {
+        return getColumn(column).getColumnType();
+    }
+
+    public int isNullable(int column) throws SQLException {
+        if (getColumn(column).isNullable()) {
+            return columnNullable;
+        } else {
+            return columnNoNulls;
+        }
+    }
+
+    //------------------------------------------------------< Derived values >
+
+    public String getColumnLabel(int column) throws SQLException {
+        return getColumnName(column);
+    }
+
+    public String getColumnTypeName(int column) throws SQLException {
+        // Use just the fixed set of types form JCRColumn
+        switch (getColumnType(column)) {
+        case Types.ARRAY:
+            return "ARRAY";
+        case Types.BIGINT:
+            return "BIGINT";
+        case Types.BLOB:
+            return "BLOB";
+        case Types.BOOLEAN:
+            return "BOOLEAN";
+        case Types.DOUBLE:
+            return "DOUBLE";
+        case Types.TIMESTAMP:
+            return "TIMESTAMP";
+        default:
+            return "VARCHAR";
+        }
+    }
+
+    public String getColumnClassName(int column) throws SQLException {
+        // Use just the fixed set of types form JCRColumn
+        switch (getColumnType(column)) {
+        case Types.ARRAY:
+            return new String[0].getClass().getName();
+        case Types.BIGINT:
+            return Long.class.getName();
+        case Types.BLOB:
+            return InputStream.class.getName();
+        case Types.BOOLEAN:
+            return Boolean.class.getName();
+        case Types.DOUBLE:
+            return Double.class.getName();
+        case Types.TIMESTAMP:
+            return Timestamp.class.getName();
+        default:
+            return String.class.getName();
+        }
+    }
+
+    public int getPrecision(int column) throws SQLException {
+        if (getColumnType(column) == Types.DOUBLE) {
+            return 3;
+        } else {
+            return 0;
+        }
+    }
+
+    public int getColumnDisplaySize(int column) throws SQLException {
+        switch (getColumnType(column)) {
+        case Types.BOOLEAN:
+            return 6;
+        case Types.BIGINT:
+            return 12;
+        case Types.DOUBLE:
+            return 18;
+        case Types.DATE:
+            return 24;
+        default:
+            return 32;
+        }
+    }
+
+    public boolean isSigned(int column) throws SQLException {
+        int type = getColumnType(column);
+        return type == Types.BIGINT || type == Types.DOUBLE;
+    }
+
+    //--------------------------------------------------------< Fixed values >
+
+    public int getScale(int column) throws SQLException {
+        return 12;
+    }
+
+    public boolean isCurrency(int column) {
+        return false;
+    }
+
+    public boolean isCaseSensitive(int column) {
+        return false;
+    }
+
+    public boolean isReadOnly(int column) {
+        return true;
+    }
+
+    public boolean isWritable(int column) {
+        return false;
+    }
+
+    public boolean isDefinitelyWritable(int column) {
+        return false;
+    }
+
+    public boolean isAutoIncrement(int column) {
+        return false;
+    }
+
+    public boolean isSearchable(int column) throws SQLException {
+        return false;
+    }
+
+}

Propchange: jackrabbit/sandbox/jackrabbit-jdbc2jcr/src/main/java/org/apache/jackrabbit/jdbc/JCRView.java
------------------------------------------------------------------------------
    svn:eol-style = native