All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.adejanovski.cassandra.jdbc.CassandraStatement Maven / Gradle / Ivy
/*
*
* 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.
*/
package com.github.adejanovski.cassandra.jdbc;
import static com.github.adejanovski.cassandra.jdbc.Utils.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLNonTransientException;
import java.sql.SQLRecoverableException;
import java.sql.SQLSyntaxErrorException;
import java.sql.SQLTransientException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.ResultSetFuture;
import com.datastax.driver.core.SimpleStatement;
import com.google.common.collect.Lists;
/**
* Cassandra statement: implementation class for {@link PreparedStatement}.
*/
public class CassandraStatement extends AbstractStatement implements CassandraStatementExtras, Comparable, Statement
{
public static final int MAX_ASYNC_QUERIES=1000;
public static final String semiColonRegex = ";";
private static final Logger logger = LoggerFactory.getLogger(CassandraStatement.class);
/**
* The connection.
*/
protected CassandraConnection connection;
/**
* The cql.
*/
protected String cql;
protected ArrayList batchQueries;
protected int fetchDirection = ResultSet.FETCH_FORWARD;
protected int fetchSize = 100;
protected int maxFieldSize = 0;
protected int maxRows = 0;
protected int resultSetType = CassandraResultSet.DEFAULT_TYPE;
protected int resultSetConcurrency = CassandraResultSet.DEFAULT_CONCURRENCY;
protected int resultSetHoldability = CassandraResultSet.DEFAULT_HOLDABILITY;
protected ResultSet currentResultSet = null;
protected int updateCount = -1;
protected boolean escapeProcessing = true;
protected com.datastax.driver.core.Statement statement;
protected com.datastax.driver.core.ConsistencyLevel consistencyLevel;
CassandraStatement(CassandraConnection con) throws SQLException
{
this(con, null, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
CassandraStatement(CassandraConnection con, String cql) throws SQLException
{
this(con, cql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
CassandraStatement(CassandraConnection con, String cql, int resultSetType, int resultSetConcurrency) throws SQLException
{
this(con, cql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
CassandraStatement(CassandraConnection con, String cql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException
{
this.connection = con;
this.cql = cql;
this.batchQueries = Lists.newArrayList();
this.consistencyLevel = con.defaultConsistencyLevel;
if (!(resultSetType == ResultSet.TYPE_FORWARD_ONLY
|| resultSetType == ResultSet.TYPE_SCROLL_INSENSITIVE
|| resultSetType == ResultSet.TYPE_SCROLL_SENSITIVE)) throw new SQLSyntaxErrorException(BAD_TYPE_RSET);
this.resultSetType = resultSetType;
if (!(resultSetConcurrency == ResultSet.CONCUR_READ_ONLY
|| resultSetConcurrency == ResultSet.CONCUR_UPDATABLE)) throw new SQLSyntaxErrorException(BAD_TYPE_RSET);
this.resultSetConcurrency = resultSetConcurrency;
if (!(resultSetHoldability == ResultSet.HOLD_CURSORS_OVER_COMMIT
|| resultSetHoldability == ResultSet.CLOSE_CURSORS_AT_COMMIT))
throw new SQLSyntaxErrorException(BAD_HOLD_RSET);
this.resultSetHoldability = resultSetHoldability;
}
public void addBatch(String query) throws SQLException
{
checkNotClosed();
batchQueries.add(query);
}
protected final void checkNotClosed() throws SQLException
{
if (isClosed()) throw new SQLRecoverableException(WAS_CLOSED_STMT);
}
public void clearBatch() throws SQLException
{
checkNotClosed();
batchQueries = new ArrayList();
}
public void clearWarnings() throws SQLException
{
// This implementation does not support the collection of warnings so clearing is a no-op
// but it is still an exception to call this on a closed connection.
checkNotClosed();
}
public void close() throws SQLException
{
//connection.removeStatement(this);
connection = null;
cql = null;
}
private void doExecute(String cql) throws SQLException
{
List futures = new ArrayList();
try
{
String[] cqlQueries = cql.split(semiColonRegex);
if(cqlQueries.length>1 && !(cql.trim().toLowerCase().startsWith("begin") && cql.toLowerCase().contains("batch") && cql.toLowerCase().contains("apply"))){
// several statements in the query to execute asynchronously
ArrayList results = Lists.newArrayList();
if(cqlQueries.length>MAX_ASYNC_QUERIES*1.1){
// Protect the cluster from receiving too many queries at once and force the dev to split the load
throw new SQLNonTransientException("Too many queries at once (" + cqlQueries.length + "). You must split your queries into more batches !");
}
StringBuilder prevCqlQuery=new StringBuilder();
for(String cqlQuery:cqlQueries){
if((cqlQuery.contains("'") && ((StringUtils.countMatches(cqlQuery,"'")%2==1 && prevCqlQuery.length()==0)
|| (StringUtils.countMatches(cqlQuery,"'")%2==0 && prevCqlQuery.length()>0)))
|| (prevCqlQuery.toString().length()>0 && !cqlQuery.contains("'"))){
prevCqlQuery.append(cqlQuery+";");
}else{
prevCqlQuery.append(cqlQuery);
if (logger.isTraceEnabled() || this.connection.debugMode) logger.debug("CQL:: "+ prevCqlQuery.toString());
SimpleStatement stmt = new SimpleStatement(prevCqlQuery.toString());
stmt.setConsistencyLevel(this.connection.defaultConsistencyLevel);
stmt.setFetchSize(this.fetchSize);
ResultSetFuture resultSetFuture = this.connection.getSession().executeAsync(stmt);
futures.add(resultSetFuture);
prevCqlQuery = new StringBuilder();
}
}
//ListenableFuture> res = Futures.allAsList(futures);
for (ResultSetFuture future : futures){
com.datastax.driver.core.ResultSet rows = future.getUninterruptibly();
results.add(rows);
}
currentResultSet = new CassandraResultSet(this, results);
}else{
// Only one statement to execute so we go synchronous
if (logger.isTraceEnabled() || this.connection.debugMode) logger.debug("CQL:: "+ cql);
SimpleStatement stmt = new SimpleStatement(cql);
stmt.setConsistencyLevel(this.connection.defaultConsistencyLevel);
stmt.setFetchSize(this.fetchSize);
currentResultSet = new CassandraResultSet(this, this.connection.getSession().execute(stmt));
}
}
catch (Exception e)
{
for(ResultSetFuture future:futures){
try{
future.cancel(true);
}catch(Exception e1){
}
}
throw new SQLTransientException(e);
}
}
public boolean execute(String query) throws SQLException
{
checkNotClosed();
doExecute(query);
return !(currentResultSet == null);
}
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException
{
checkNotClosed();
if (!(autoGeneratedKeys == RETURN_GENERATED_KEYS || autoGeneratedKeys == NO_GENERATED_KEYS))
throw new SQLSyntaxErrorException(BAD_AUTO_GEN);
if (autoGeneratedKeys == RETURN_GENERATED_KEYS) throw new SQLFeatureNotSupportedException(NO_GEN_KEYS);
return execute(sql);
}
public int[] executeBatch() throws SQLException
{
int[] returnCounts= new int[batchQueries.size()];
List futures = new ArrayList();
if (logger.isTraceEnabled() || this.connection.debugMode) logger.debug("CQL statements: "+ batchQueries.size());
for(String q:batchQueries){
if (logger.isTraceEnabled() || this.connection.debugMode) logger.debug("CQL: "+ q);
SimpleStatement stmt = new SimpleStatement(q);
stmt.setConsistencyLevel(this.connection.defaultConsistencyLevel);
ResultSetFuture resultSetFuture = this.connection.getSession().executeAsync(stmt);
futures.add(resultSetFuture);
}
int i=0;
for (ResultSetFuture future : futures){
future.getUninterruptibly();
returnCounts[i]=1;
i++;
}
return returnCounts;
}
public ResultSet executeQuery(String query) throws SQLException
{
checkNotClosed();
doExecute(query);
if (currentResultSet == null)
throw new SQLNonTransientException(NO_RESULTSET);
return currentResultSet;
}
public int executeUpdate(String query) throws SQLException
{
checkNotClosed();
doExecute(query);
// no updateCount available in Datastax Java Driver
return 0;
}
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException
{
checkNotClosed();
if (!(autoGeneratedKeys == RETURN_GENERATED_KEYS || autoGeneratedKeys == NO_GENERATED_KEYS))
throw new SQLFeatureNotSupportedException(BAD_AUTO_GEN);
return executeUpdate(sql);
}
@SuppressWarnings("cast")
public Connection getConnection() throws SQLException
{
checkNotClosed();
return (Connection) connection;
}
public int getFetchDirection() throws SQLException
{
checkNotClosed();
return fetchDirection;
}
public int getFetchSize() throws SQLException
{
checkNotClosed();
return fetchSize;
}
public int getMaxFieldSize() throws SQLException
{
checkNotClosed();
return maxFieldSize;
}
public int getMaxRows() throws SQLException
{
checkNotClosed();
return maxRows;
}
public boolean getMoreResults() throws SQLException
{
checkNotClosed();
resetResults();
// in the current Cassandra implementation there are never MORE results
return false;
}
@SuppressWarnings("boxing")
public boolean getMoreResults(int current) throws SQLException
{
checkNotClosed();
switch (current)
{
case CLOSE_CURRENT_RESULT:
resetResults();
break;
case CLOSE_ALL_RESULTS:
case KEEP_CURRENT_RESULT:
throw new SQLFeatureNotSupportedException(NO_MULTIPLE);
default:
throw new SQLSyntaxErrorException(String.format(BAD_KEEP_RSET, current));
}
// in the current Cassandra implementation there are never MORE results
return false;
}
public int getQueryTimeout() throws SQLException
{
// the Cassandra implementation does not support timeouts on queries
return 0;
}
public ResultSet getResultSet() throws SQLException
{
checkNotClosed();
return currentResultSet;
}
public int getResultSetConcurrency() throws SQLException
{
checkNotClosed();
return ResultSet.CONCUR_READ_ONLY;
}
public int getResultSetHoldability() throws SQLException
{
checkNotClosed();
// the Cassandra implementations does not support commits so this is the closest match
return ResultSet.HOLD_CURSORS_OVER_COMMIT;
}
public int getResultSetType() throws SQLException
{
checkNotClosed();
return ResultSet.TYPE_FORWARD_ONLY;
}
public int getUpdateCount() throws SQLException
{
checkNotClosed();
return updateCount;
}
public SQLWarning getWarnings() throws SQLException
{
checkNotClosed();
return null;
}
public boolean isClosed()
{
return connection == null ;
}
public boolean isPoolable() throws SQLException
{
checkNotClosed();
return false;
}
public boolean isWrapperFor(Class> iface) throws SQLException
{
return false;
}
protected final void resetResults()
{
currentResultSet = null;
updateCount = -1;
}
public void setEscapeProcessing(boolean enable) throws SQLException
{
checkNotClosed();
// the Cassandra implementation does not currently look at this
escapeProcessing = enable;
}
@SuppressWarnings("boxing")
public void setFetchDirection(int direction) throws SQLException
{
checkNotClosed();
if (direction == ResultSet.FETCH_FORWARD || direction == ResultSet.FETCH_REVERSE || direction == ResultSet.FETCH_UNKNOWN)
{
if ((getResultSetType() == ResultSet.TYPE_FORWARD_ONLY) && (direction != ResultSet.FETCH_FORWARD))
throw new SQLSyntaxErrorException(String.format(BAD_FETCH_DIR, direction));
fetchDirection = direction;
}
else throw new SQLSyntaxErrorException(String.format(BAD_FETCH_DIR, direction));
}
@SuppressWarnings("boxing")
public void setFetchSize(int size) throws SQLException
{
checkNotClosed();
if (size < 0) throw new SQLSyntaxErrorException(String.format(BAD_FETCH_SIZE, size));
fetchSize = size;
}
public void setMaxFieldSize(int arg0) throws SQLException
{
checkNotClosed();
// silently ignore this setting. always use default 0 (unlimited)
}
public void setMaxRows(int arg0) throws SQLException
{
checkNotClosed();
// silently ignore this setting. always use default 0 (unlimited)
}
public void setPoolable(boolean poolable) throws SQLException
{
checkNotClosed();
// silently ignore any attempt to set this away from the current default (false)
}
public void setQueryTimeout(int arg0) throws SQLException
{
checkNotClosed();
// silently ignore any attempt to set this away from the current default (0)
}
public T unwrap(Class iface) throws SQLException
{
if(iface.isInstance(this)) return iface.cast(this);
throw new SQLFeatureNotSupportedException(String.format(NO_INTERFACE, iface.getSimpleName()));
}
public ConsistencyLevel getConsistencyLevel()
{
return consistencyLevel;
}
public void setConsistencyLevel(ConsistencyLevel consistencyLevel)
{
this.consistencyLevel = consistencyLevel;
this.statement.setConsistencyLevel(consistencyLevel);
}
public int compareTo(Object target)
{
if (this.equals(target)) return 0;
if (this.hashCode()< target.hashCode()) return -1;
return 1;
}
}