/**
* Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
*
* Licensed 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.
*
* For more information: http://www.orientechnologies.com
*/
package com.orientechnologies.orient.jdbc;
import com.orientechnologies.common.exception.OException;
import com.orientechnologies.orient.core.command.OCommandRequest;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.exception.OQueryParsingException;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.OCommandSQL;
import java.sql.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import static java.lang.Boolean.parseBoolean;
import static java.util.Collections.emptyList;
/**
* @author Roberto Franchini (CELI Srl - franchini@celi.it)
* @author Salvatore Piccione (TXT e-solutions SpA - salvo.picci@gmail.com)
*/
public class OrientJdbcStatement implements Statement {
protected final OrientJdbcConnection connection;
protected final ODatabaseDocument database;
// protected OCommandSQL query;
protected OCommandRequest query;
protected String sql;
protected List<ODocument> documents;
protected boolean closed;
protected Object rawResult;
protected OrientJdbcResultSet resultSet;
protected List<String> batches;
protected int resultSetType;
protected int resultSetConcurrency;
protected int resultSetHoldability;
protected Properties info;
public OrientJdbcStatement(final OrientJdbcConnection iConnection) {
this(iConnection, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
/**
* @param iConnection
* @param resultSetType
* @param resultSetConcurrency
* @throws SQLException
*/
public OrientJdbcStatement(OrientJdbcConnection iConnection, int resultSetType, int resultSetConcurrency) throws SQLException {
this(iConnection, resultSetType, resultSetConcurrency, resultSetType);
}
/**
* @param iConnection
* @param resultSetType
* @param resultSetConcurrency
* @param resultSetHoldability
*/
public OrientJdbcStatement(OrientJdbcConnection iConnection, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) {
this.connection = iConnection;
this.database = iConnection.getDatabase();
database.activateOnCurrentThread();
documents = emptyList();
batches = new ArrayList<String>();
this.resultSetType = resultSetType;
this.resultSetConcurrency = resultSetConcurrency;
this.resultSetHoldability = resultSetHoldability;
info = connection.getInfo();
}
@Override
public boolean execute(final String sqlCommand) throws SQLException {
if ("".equals(sqlCommand))
return false;
sql = mayCleanForSpark(sqlCommand);
if (sql.equalsIgnoreCase("select 1")) {
documents = new ArrayList<ODocument>(1);
documents.add(new ODocument().field("1", 1));
} else {
query = new OCommandSQL(sql);
try {
rawResult = executeCommand(query);
if (rawResult instanceof List<?>) {
documents = (List<ODocument>) rawResult;
} else if (rawResult instanceof OIdentifiable) {
documents = new ArrayList<ODocument>(1);
documents.add((ODocument) ((OIdentifiable) rawResult).getRecord());
} else {
return false;
}
} catch (OQueryParsingException e) {
throw new SQLSyntaxErrorException("Error while parsing query", e);
} catch (OException e) {
throw new SQLException("Error while executing query", e);
}
}
resultSet = new OrientJdbcResultSet(this, documents, resultSetType, resultSetConcurrency, resultSetHoldability);
return true;
}
public ResultSet executeQuery(final String sql) throws SQLException {
if (execute(sql))
return resultSet;
else
return null;
}
public int executeUpdate(final String sql) throws SQLException {
query = new OCommandSQL(sql);
rawResult = executeCommand(query);
if (rawResult instanceof ODocument)
return 1;
else if (rawResult instanceof Integer)
return (Integer) rawResult;
else if (rawResult instanceof Collection)
return ((Collection) rawResult).size();
return 0;
}
protected <RET> RET executeCommand(OCommandRequest query) throws SQLException {
try {
database.activateOnCurrentThread();
return database.command(query).execute();
} catch (OQueryParsingException e) {
throw new SQLSyntaxErrorException("Error while parsing command", e);
} catch (OException e) {
throw new SQLException("Error while executing command", e);
}
}
public int executeUpdate(final String sql, int autoGeneratedKeys) throws SQLException {
return 0;
}
public int executeUpdate(final String sql, int[] columnIndexes) throws SQLException {
return 0;
}
public int executeUpdate(final String sql, String[] columnNames) throws SQLException {
return 0;
}
public Connection getConnection() throws SQLException {
return connection;
}
public void close() throws SQLException {
query = null;
closed = true;
}
public boolean execute(final String sql, int autoGeneratedKeys) throws SQLException {
return false;
}
public boolean execute(final String sql, int[] columnIndexes) throws SQLException {
return false;
}
public boolean execute(final String sql, String[] columnNames) throws SQLException {
return false;
}
public void addBatch(final String sql) throws SQLException {
batches.add(sql);
}
public void cancel() throws SQLException {
}
public void clearBatch() throws SQLException {
batches.clear();
}
public void clearWarnings() throws SQLException {
}
public int[] executeBatch() throws SQLException {
int[] results = new int[batches.size()];
int i = 0;
for (String sql : batches) {
results[i++] = executeUpdate(sql);
}
return results;
}
public int getFetchDirection() throws SQLException {
return 0;
}
public void setFetchDirection(final int direction) throws SQLException {
}
public int getFetchSize() throws SQLException {
return 0;
}
public void setFetchSize(final int rows) throws SQLException {
}
public ResultSet getGeneratedKeys() throws SQLException {
return null;
}
public int getMaxFieldSize() throws SQLException {
return 0;
}
public void setMaxFieldSize(final int max) throws SQLException {
}
public int getMaxRows() throws SQLException {
return 0;
}
public void setMaxRows(final int max) throws SQLException {
}
public boolean getMoreResults() throws SQLException {
return false;
}
public boolean getMoreResults(final int current) throws SQLException {
return false;
}
public int getQueryTimeout() throws SQLException {
return 0;
}
public void setQueryTimeout(final int seconds) throws SQLException {
}
public ResultSet getResultSet() throws SQLException {
return resultSet;
}
public int getResultSetConcurrency() throws SQLException {
return resultSet.getConcurrency();
}
public int getResultSetHoldability() throws SQLException {
return resultSet.getHoldability();
}
public int getResultSetType() throws SQLException {
return resultSet.getType();
}
public int getUpdateCount() throws SQLException {
if (isClosed())
throw new SQLException("Statement already closed");
return -1;
}
public SQLWarning getWarnings() throws SQLException {
return null;
}
public boolean isClosed() throws SQLException {
return query == null;
}
public boolean isPoolable() throws SQLException {
return false;
}
public void setPoolable(final boolean poolable) throws SQLException {
}
public void setCursorName(final String name) throws SQLException {
}
public void setEscapeProcessing(final boolean enable) throws SQLException {
}
public boolean isWrapperFor(Class<?> iface) throws SQLException {
try {
// the following if-then structure makes sense if the query can be a
// subclass of OCommandSQL.
if (this.query == null) {
return OCommandSQL.class.isAssignableFrom(iface);
} else {
return this.query.getClass().isAssignableFrom(iface);
}
} catch (NullPointerException e) {
throw new SQLException(e);
}
}
public <T> T unwrap(Class<T> iface) throws SQLException {
try {
return iface.cast(query);
} catch (ClassCastException e) {
throw new SQLException(e);
}
}
public void closeOnCompletion() throws SQLException {
}
public boolean isCloseOnCompletion() throws SQLException {
return false;
}
protected String mayCleanForSpark(String sql) {
//SPARK support
if (parseBoolean(info.getProperty("spark", "false"))) {
String sqlToClean = sql.toLowerCase();
if (sqlToClean.endsWith("where 1=0")) {
sqlToClean = sqlToClean.replace("where 1=0", " limit 1");
}
return sqlToClean.replace('"', ' ');
}
return sql;
}
}