net.sf.mongodb_jdbc_driver.MongoDbStatement Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2012 Rob Manning
* [email protected]
*
* This file is part of MongoDB JDBC Driver.
*
* MongoDB JDBC Driver is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MongoDB JDBC Driver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MongoDB JDBC Driver. If not, see .
*/
package net.sf.mongodb_jdbc_driver;
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.List;
import net.sf.mongodb_jdbc_driver.zql.ParseException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
public class MongoDbStatement implements Statement
{
private final DB db;
private final MongoDbConnection con;
private final ParserHelper parserHelper = new ParserHelper();
private MongoDbResultSet lastResultSet;
private boolean isClosed = false;
private int maxRows = -1;
/**
* @param con
*/
public MongoDbStatement(final MongoDbConnection con)
{
this.db = con.getDb();
this.con = con;
}
@Override
public T unwrap(final Class iface) throws SQLException
{
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(final Class> iface) throws SQLException
{
// TODO Auto-generated method stub
return false;
}
private void checkForSupportedColumn(final String selectColumn, String sql) throws SQLException
{
if (!selectColumn.equals("*") && !selectColumn.equals("\"_id\"") && !selectColumn.equals("document"))
{
throw new SQLException("Unsupported select item (" + selectColumn + ") in select column list ("
+ sql + ")");
}
}
private int getSelectColumnCount(final List columns) {
if (columns.contains("*")) {
return 2;
}
return columns.size();
}
@Override
public ResultSet executeQuery(final String sql) throws SQLException
{
lastResultSet = new MongoDbResultSet();
lastResultSet.setStatement(this);
try
{
if (!parserHelper.isSelectQuery(sql))
{
throw new SQLException("Statement must be a select query");
}
final String collectionName = parserHelper.getSelectTable(sql);
final DBCollection collection = db.getCollection(collectionName);
final List selectColumns = parserHelper.getSelectColumns(sql);
if (selectColumns.size() == 1 && "count(*)".equals(selectColumns.get(0)))
{
lastResultSet.setColumnNames(new String[] { "count(*)" });
lastResultSet.addRow(new String[] { "" + collection.find().count() });
}
else
{
boolean projectId = false;
boolean projectDocument = false;
String[] selectColumnNamesArr = new String[getSelectColumnCount(selectColumns)];
int selectColumnNamesArrIdx = 0;
/*
* Here we have a select list, which only makes sense if it contains: _id and/or document or "*"
*/
for (final String selectColumn : selectColumns)
{
checkForSupportedColumn(selectColumn, sql);
if (selectColumn.equals("*"))
{
projectId = true;
projectDocument = true;
selectColumnNamesArr[0] = "\"_id\"";
selectColumnNamesArr[1] = "document";
break;
}
else
{
if (selectColumn.equals("\"_id\""))
{
selectColumnNamesArr[selectColumnNamesArrIdx++] = "\"_id\"";
projectId = true;
}
if (selectColumn.equals("document"))
{
selectColumnNamesArr[selectColumnNamesArrIdx++] = "document";
projectDocument = true;
}
}
}
lastResultSet.setColumnNames(selectColumnNamesArr);
final DBCursor cursor = collection.find();
final Gson gson = new GsonBuilder().setPrettyPrinting().create();
final JsonParser jp = new JsonParser();
try
{
// TODO: Fix this greedy implementation
//
// This is not a great implementation here. For instance, if there are many items in the
// cursor, then merely executing the statement causes them all to be read into memory at the
// same time. Instead, the cursor should be moved into the MongoDbResultSet, where next()
// can retrieve the next record from the cursor, just-in-time, rather than this greedy
// approach.
while (cursor.hasNext() && (maxRows == -1 || lastResultSet.getRowCount() < maxRows))
{
final DBObject object = cursor.next();
final String id = object.get("_id").toString();
String document = object.toString();
if (projectDocument)
{
final JsonElement je = jp.parse(document);
document = gson.toJson(je);
}
if (projectId && projectDocument)
{
if (selectColumnNamesArr[0].equals("document")) {
lastResultSet.addRow(new String[] { document, id });
} else {
lastResultSet.addRow(new String[] { id, document });
}
}
else if (projectId)
{
lastResultSet.addRow(new String[] { id });
}
else
{
lastResultSet.addRow(new String[] { document });
}
}
}
finally
{
cursor.close();
}
}
}
catch (final ParseException e)
{
throw new SQLException("Unable to parse query (" + sql + "): " + e.getMessage(), e);
}
return lastResultSet;
}
@Override
public int executeUpdate(final String sql) throws SQLException
{
throw new SQLException("Update support has not yet been added to this driver");
}
/**
* @see java.sql.Statement#close()
*/
@Override
public void close() throws SQLException
{
if (lastResultSet != null)
{
lastResultSet.close();
}
this.isClosed = true;
}
@Override
public int getMaxFieldSize() throws SQLException
{
// TODO Auto-generated method stub
return 0;
}
@Override
public void setMaxFieldSize(final int max) throws SQLException
{
// TODO Auto-generated method stub
}
/**
* @see java.sql.Statement#getMaxRows()
*/
@Override
public int getMaxRows() throws SQLException
{
return maxRows;
}
/**
* @see java.sql.Statement#setMaxRows(int)
*/
@Override
public void setMaxRows(final int max) throws SQLException
{
this.maxRows = max;
}
@Override
public void setEscapeProcessing(final boolean enable) throws SQLException
{
// TODO Auto-generated method stub
}
/**
* @see java.sql.Statement#getQueryTimeout()
*/
@Override
public int getQueryTimeout() throws SQLException
{
checkClosed();
throw new SQLFeatureNotSupportedException("MongoDB provides no support for query timeouts.");
}
/**
* @see java.sql.Statement#setQueryTimeout(int)
*/
@Override
public void setQueryTimeout(final int seconds) throws SQLException
{
checkClosed();
throw new SQLFeatureNotSupportedException("MongoDB provides no support for query timeouts.");
}
/**
* @see java.sql.Statement#cancel()
*/
@Override
public void cancel() throws SQLException
{
checkClosed();
throw new SQLFeatureNotSupportedException("MongoDB provides no support for interrupting an operation.");
}
/**
* @see java.sql.Statement#getWarnings()
*/
@Override
public SQLWarning getWarnings() throws SQLException
{
checkClosed();
// Until update support is added, there are no warnings.
return null;
}
/**
* @see java.sql.Statement#clearWarnings()
*/
@Override
public void clearWarnings() throws SQLException
{
checkClosed();
// Until update support is added, there are no warnings.
}
/**
* @see java.sql.Statement#setCursorName(java.lang.String)
*/
@Override
public void setCursorName(final String name) throws SQLException
{
checkClosed();
// Driver doesn't support positioned updates for now, so no-op.
}
/**
* @see java.sql.Statement#execute(java.lang.String)
*/
@Override
public boolean execute(final String sql) throws SQLException
{
checkClosed();
boolean result = false;
try
{
if (parserHelper.isSelectQuery(sql))
{
lastResultSet = (MongoDbResultSet) executeQuery(sql);
result = true;
}
else
{
// TODO: handle as a non-select statement. Not sure what that would be in the content of MongoDB
}
}
catch (final ParseException e)
{
throw new SQLException("Unable to parse query (" + sql + ") : " + e.getMessage(), e);
}
return result;
}
/**
* @see java.sql.Statement#getResultSet()
*/
@Override
public ResultSet getResultSet() throws SQLException
{
checkClosed();
return lastResultSet;
}
/**
* @see java.sql.Statement#getUpdateCount()
*/
@Override
public int getUpdateCount() throws SQLException
{
checkClosed();
return 0;
}
@Override
public boolean getMoreResults() throws SQLException
{
// TODO Auto-generated method stub
return false;
}
@Override
public void setFetchDirection(final int direction) throws SQLException
{
// TODO Auto-generated method stub
}
@Override
public int getFetchDirection() throws SQLException
{
// TODO Auto-generated method stub
return 0;
}
@Override
public void setFetchSize(final int rows) throws SQLException
{
// TODO Auto-generated method stub
}
@Override
public int getFetchSize() throws SQLException
{
// TODO Auto-generated method stub
return 0;
}
@Override
public int getResultSetConcurrency() throws SQLException
{
// TODO Auto-generated method stub
return 0;
}
@Override
public int getResultSetType() throws SQLException
{
// TODO Auto-generated method stub
return 0;
}
@Override
public void addBatch(final String sql) throws SQLException
{
// TODO Auto-generated method stub
}
@Override
public void clearBatch() throws SQLException
{
// TODO Auto-generated method stub
}
@Override
public int[] executeBatch() throws SQLException
{
checkClosed();
// TODO Auto-generated method stub
return null;
}
/**
* @see java.sql.Statement#getConnection()
*/
@Override
public Connection getConnection() throws SQLException
{
checkClosed();
return this.con;
}
@Override
public boolean getMoreResults(final int current) throws SQLException
{
checkClosed();
// TODO Auto-generated method stub
return false;
}
@Override
public ResultSet getGeneratedKeys() throws SQLException
{
checkClosed();
// TODO Auto-generated method stub
return null;
}
@Override
public int executeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException
{
checkClosed();
// TODO Auto-generated method stub
return 0;
}
@Override
public int executeUpdate(final String sql, final int[] columnIndexes) throws SQLException
{
checkClosed();
// TODO Auto-generated method stub
return 0;
}
@Override
public int executeUpdate(final String sql, final String[] columnNames) throws SQLException
{
checkClosed();
// TODO Auto-generated method stub
return 0;
}
@Override
public boolean execute(final String sql, final int autoGeneratedKeys) throws SQLException
{
checkClosed();
// TODO Auto-generated method stub
return false;
}
@Override
public boolean execute(final String sql, final int[] columnIndexes) throws SQLException
{
checkClosed();
// TODO Auto-generated method stub
return false;
}
@Override
public boolean execute(final String sql, final String[] columnNames) throws SQLException
{
checkClosed();
// TODO Auto-generated method stub
return false;
}
@Override
public int getResultSetHoldability() throws SQLException
{
// TODO Auto-generated method stub
return 0;
}
@Override
public boolean isClosed() throws SQLException
{
return isClosed;
}
@Override
public void setPoolable(final boolean poolable) throws SQLException
{
// TODO Auto-generated method stub
}
@Override
public boolean isPoolable() throws SQLException
{
// TODO Auto-generated method stub
return false;
}
private void checkClosed() throws SQLException
{
if (isClosed)
{
throw new SQLException("Statement was previously closed.");
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy