/* * 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.xenei.jdbc4sparql; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.SQLWarning; import java.sql.Statement; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xenei.jdbc4sparql.iface.Catalog; import org.xenei.jdbc4sparql.iface.Schema; import org.xenei.jdbc4sparql.impl.rdf.RdfCatalog; import org.xenei.jdbc4sparql.sparql.SparqlQueryBuilder; import org.xenei.jdbc4sparql.sparql.SparqlView; import org.xenei.jdbc4sparql.sparql.parser.SparqlParser; public class J4SStatement implements Statement { private final J4SConnection connection; private RdfCatalog catalog; private Schema schema; private SQLWarning warnings = null; private boolean closed = false; private final SparqlParser parser; private ResultSet resultSet; private int fetchDirection; private final int resultSetConcurrency; private int queryTimeout; private final int resultSetType; private final int resultSetHoldability; private boolean poolable; private static Logger LOG = LoggerFactory.getLogger(J4SStatement.class); public J4SStatement(final J4SConnection connection, final RdfCatalog catalog, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { if (LOG.isDebugEnabled()) { J4SStatement.LOG.debug("Creating statement"); } this.connection = connection; this.catalog = catalog; if (connection.getSchema() != null) { this.schema = catalog.getSchema(connection.getSchema()); } else { final Set<Schema> schemas = catalog.getSchemas(); if (schemas.size() == 1) { this.schema = schemas.iterator().next(); } } this.queryTimeout = connection.getNetworkTimeout(); this.parser = connection.getSparqlParser(); this.resultSet = null; this.poolable = true; this.resultSetHoldability = resultSetHoldability; this.fetchDirection = ResultSet.FETCH_FORWARD; this.resultSetConcurrency = resultSetConcurrency; this.resultSetType = resultSetType; } @Override public void addBatch(final String arg0) throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public void cancel() throws SQLException { // TODO Auto-generated method stub } @Override public void clearBatch() throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public void clearWarnings() throws SQLException { warnings = null; } @Override public void close() throws SQLException { if ((resultSet != null) && !resultSet.isClosed()) { resultSet.close(); } closed = true; } @Override public void closeOnCompletion() throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public boolean execute(final String sql) throws SQLException { resultSet = null; if (LOG.isDebugEnabled()) { J4SStatement.LOG.debug("execute {}", sql); } final String[] parts = sql.trim().split("\\s"); if (parts[0].equalsIgnoreCase("use")) { executeUse(parts); } else if (parts[0].equalsIgnoreCase("show")) { resultSet = executeShow(parts); } else { final SparqlView view = new SparqlView(parse(sql)); resultSet = view.getResultSet(); resultSet.setFetchDirection(getFetchDirection()); } return resultSet != null; } @Override public boolean execute(final String sql, final int autoGeneratedKeys) throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public boolean execute(final String arg0, final int[] columnIndexes) throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public boolean execute(final String arg0, final String[] columnNames) throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public int[] executeBatch() throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public ResultSet executeQuery(final String sql) throws SQLException { execute(sql); return getResultSet(); } private ResultSet executeShow(final String[] parts) throws SQLException { if (parts.length == 1) { throw new SQLException( "show must be followed by CATalog, SCHema, TABle or COLums [tablename]"); } final String name = (parts.length == 2) ? null : parts[2]; if (parts[1].toLowerCase().startsWith("cat")) { return connection.getMetaData().getCatalogs(); } if (parts[1].toLowerCase().startsWith("sch")) { return connection.getMetaData().getSchemas(connection.getCatalog(), name); } if (parts[1].toLowerCase().startsWith("tab")) { return connection.getMetaData().getTables(connection.getCatalog(), connection.getSchema(), name, null); } if (parts[1].toLowerCase().startsWith("col")) { return connection.getMetaData().getColumns(connection.getCatalog(), connection.getSchema(), name, null); } throw new SQLException( "show must be followed by CATalog, SCHema, TABle or COLums [tablename]"); } @Override public int executeUpdate(final String arg0) throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public int executeUpdate(final String arg0, final int arg1) throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public int executeUpdate(final String arg0, final int[] arg1) throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public int executeUpdate(final String arg0, final String[] arg1) throws SQLException { throw new SQLFeatureNotSupportedException(); } private void executeUse(final String[] parts) throws SQLException { if (parts.length == 1) { throw new SQLException( "use must be followed by CATalog or SCHema and a name."); } final String name = (parts.length == 2) ? "" : parts[2]; if (parts[1].toLowerCase().startsWith("cat")) { final Catalog catalog = connection.getCatalogs().get(name); if (catalog == null) { throw new SQLException(String.format("Catalog '%s' not found", name)); } if (catalog instanceof RdfCatalog) { this.catalog = (RdfCatalog) catalog; connection.setCatalog(name); } else { throw new SQLException(String.format( "Catalog '%s' does not support statements", name)); } return; } if (parts[1].toLowerCase().startsWith("sch")) { connection.setSchema(name); this.schema = catalog.getSchema(name); return; } } @Override public Connection getConnection() throws SQLException { return connection; } @Override public int getFetchDirection() throws SQLException { return fetchDirection; } @Override public int getFetchSize() throws SQLException { return Integer.MAX_VALUE; } @Override public ResultSet getGeneratedKeys() throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public int getMaxFieldSize() throws SQLException { return Integer.MAX_VALUE; } @Override public int getMaxRows() throws SQLException { return Integer.MAX_VALUE; } @Override public boolean getMoreResults() throws SQLException { return false; } @Override public boolean getMoreResults(final int arg0) throws SQLException { return false; } @Override public int getQueryTimeout() throws SQLException { return queryTimeout; } @Override public ResultSet getResultSet() throws SQLException { return resultSet; } @Override public int getResultSetConcurrency() throws SQLException { return resultSetConcurrency; } @Override public int getResultSetHoldability() throws SQLException { return resultSetHoldability; } @Override public int getResultSetType() throws SQLException { return resultSetType; } @Override public int getUpdateCount() throws SQLException { return -1; // don't do updates } @Override public SQLWarning getWarnings() throws SQLException { return warnings; } @Override public boolean isClosed() throws SQLException { return closed; } @Override public boolean isCloseOnCompletion() throws SQLException { return false; } @Override public boolean isPoolable() throws SQLException { return poolable; } @Override public boolean isWrapperFor(final Class<?> arg0) throws SQLException { return false; } public SparqlQueryBuilder parse(final String sql) throws SQLException { return parser.parse(connection.getCatalogs(), catalog, schema, sql); } @Override public void setCursorName(final String arg0) throws SQLException { throw new SQLFeatureNotSupportedException(); } @Override public void setEscapeProcessing(final boolean arg0) throws SQLException { // no op -- we don't set this } @Override public void setFetchDirection(final int direction) throws SQLException { switch (direction) { case ResultSet.FETCH_REVERSE: fetchDirection = direction; break; case ResultSet.FETCH_UNKNOWN: case ResultSet.FETCH_FORWARD: fetchDirection = ResultSet.FETCH_FORWARD; break; default: throw new SQLException("invalid fetch direciton value"); } } @Override public void setFetchSize(final int arg0) throws SQLException { // ignore this } @Override public void setMaxFieldSize(final int arg0) throws SQLException { // TODO Auto-generated method stub } @Override public void setMaxRows(final int arg0) throws SQLException { // TODO Auto-generated method stub } @Override public void setPoolable(final boolean poolable) throws SQLException { this.poolable = poolable; } @Override public void setQueryTimeout(final int queryTimeout) throws SQLException { this.queryTimeout = queryTimeout; } @Override public <T> T unwrap(final Class<T> arg0) throws SQLException { throw new SQLFeatureNotSupportedException(); } }