Repository: lens Updated Branches: refs/heads/master 34f15c6e2 -> 70855ea8c
LENS-897: support for prepared query on lens client jdbc Project: http://git-wip-us.apache.org/repos/asf/lens/repo Commit: http://git-wip-us.apache.org/repos/asf/lens/commit/70855ea8 Tree: http://git-wip-us.apache.org/repos/asf/lens/tree/70855ea8 Diff: http://git-wip-us.apache.org/repos/asf/lens/diff/70855ea8 Branch: refs/heads/master Commit: 70855ea8c31fb9aa18deefabf9b2691368fd583d Parents: 34f15c6 Author: piyush <piyush.muk...@gmail.com> Authored: Tue Oct 18 20:29:36 2016 +0530 Committer: Rajat Khandelwal <rajatgupt...@gmail.com> Committed: Tue Oct 18 20:29:36 2016 +0530 ---------------------------------------------------------------------- .../lens/client/jdbc/LensJdbcConnection.java | 2 +- .../apache/lens/client/jdbc/LensJdbcDriver.java | 2 +- .../client/jdbc/LensJdbcPreparedStatement.java | 421 +++++++++++++++++++ .../jdbc/LensJdbcPreparedStatementTest.java | 51 +++ 4 files changed, 474 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lens/blob/70855ea8/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcConnection.java ---------------------------------------------------------------------- diff --git a/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcConnection.java b/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcConnection.java index 9ad31ee..a3e7bfb 100644 --- a/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcConnection.java +++ b/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcConnection.java @@ -65,7 +65,7 @@ public class LensJdbcConnection implements Connection { */ @Override public PreparedStatement prepareStatement(String s) throws SQLException { - throw new SQLException("Operation not supported!!!"); + return new LensJdbcPreparedStatement(this, s); } /* http://git-wip-us.apache.org/repos/asf/lens/blob/70855ea8/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcDriver.java ---------------------------------------------------------------------- diff --git a/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcDriver.java b/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcDriver.java index 056a0b2..53c7b49 100644 --- a/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcDriver.java +++ b/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcDriver.java @@ -50,7 +50,7 @@ public class LensJdbcDriver implements Driver { */ @Override public Connection connect(String s, Properties properties) throws SQLException { - return null; + return new LensJdbcConnection(s, properties); } /* http://git-wip-us.apache.org/repos/asf/lens/blob/70855ea8/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcPreparedStatement.java ---------------------------------------------------------------------- diff --git a/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcPreparedStatement.java b/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcPreparedStatement.java new file mode 100644 index 0000000..943c59c --- /dev/null +++ b/lens-client/src/main/java/org/apache/lens/client/jdbc/LensJdbcPreparedStatement.java @@ -0,0 +1,421 @@ +/** + * 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.lens.client.jdbc; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; +import java.sql.*; +import java.sql.Date; +import java.text.SimpleDateFormat; +import java.util.*; + + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; + +public class LensJdbcPreparedStatement extends LensJdbcStatement implements PreparedStatement { + private final List<String> sqlTokens; + private List<String> parameters; + private static final char ESCAPE_CHAR = '\\'; + + private static final String NULL = "\"NULL\""; + + private static final ImmutableMap<Character, Character> OPEN_TO_CLOSE_QUOTES = + new ImmutableMap.Builder<Character, Character>() + .put('\'', '\'') + .put('"', '"') + .put('`', '`') + .build(); + + /** + * Instantiates a new lens jdbc statement. + * + * @param connection the connection + */ + public LensJdbcPreparedStatement(LensJdbcConnection connection, String parametrisedSql) { + super(connection); + this.sqlTokens = tokenize(parametrisedSql); + this.parameters = Arrays.asList(new String[sqlTokens.size() - 1]); + } + + @Override + public ResultSet executeQuery() throws SQLException { + final String finalSql = compile(); + return super.executeQuery(finalSql); + } + + @Override + public int executeUpdate() throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void setNull(int parameterIndex, int sqlType) throws SQLException { + parameters.set(parameterIndex - 1, NULL); + } + + @Override + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + parameters.set(parameterIndex - 1, String.valueOf(x)); + } + + @Override + public void setByte(int parameterIndex, byte x) throws SQLException { + parameters.set(parameterIndex - 1, String.valueOf(x)); + } + + @Override + public void setShort(int parameterIndex, short x) throws SQLException { + parameters.set(parameterIndex - 1, String.valueOf(x)); + + } + + @Override + public void setInt(int parameterIndex, int x) throws SQLException { + parameters.set(parameterIndex - 1, String.valueOf(x)); + + } + + @Override + public void setLong(int parameterIndex, long x) throws SQLException { + parameters.set(parameterIndex - 1, String.valueOf(x)); + + } + + @Override + public void setFloat(int parameterIndex, float x) throws SQLException { + parameters.set(parameterIndex - 1, String.valueOf(x)); + } + + @Override + public void setDouble(int parameterIndex, double x) throws SQLException { + parameters.set(parameterIndex - 1, String.valueOf(x)); + + } + + @Override + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + parameters.set(parameterIndex - 1, String.valueOf(x)); + + } + + @Override + public void setString(int parameterIndex, String x) throws SQLException { + parameters.set(parameterIndex - 1, wrapString(x)); + + } + + @Override + public void setBytes(int parameterIndex, byte[] x) throws SQLException { + throw new UnsupportedOperationException(); + } + + + @Override + public void setDate(int parameterIndex, Date x) throws SQLException { + SimpleDateFormat formatter = new SimpleDateFormat("YYYY-MM-dd"); + parameters.set(parameterIndex - 1, formatter.format(x)); + } + + @Override + public void setTime(int parameterIndex, Time x) throws SQLException { + SimpleDateFormat formatter = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss.SSS"); + parameters.set(parameterIndex - 1, formatter.format(x)); + } + + @Override + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + SimpleDateFormat formatter = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss.SSS"); + parameters.set(parameterIndex - 1, formatter.format(x)); + } + + @Override + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void clearParameters() throws SQLException { + parameters = Arrays.asList(new String[sqlTokens.size() - 1]); + } + + @Override + public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void setObject(int parameterIndex, Object x) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public boolean execute() throws SQLException { + final String finalSql = compile(); + return super.execute(finalSql); + } + + @Override + public void addBatch() throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void setRef(int parameterIndex, Ref x) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void setBlob(int parameterIndex, Blob x) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void setClob(int parameterIndex, Clob x) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void setArray(int parameterIndex, Array x) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public ResultSetMetaData getMetaData() throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + parameters.set(parameterIndex - 1, NULL); + } + + @Override + public void setURL(int parameterIndex, URL x) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public ParameterMetaData getParameterMetaData() throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void setRowId(int parameterIndex, RowId x) throws SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void setNString(int parameterIndex, String value) throws SQLException { + parameters.set(parameterIndex - 1, wrapString(value)); + } + + @Override + public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setNClob(int parameterIndex, NClob value) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setClob(int parameterIndex, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + throw new UnsupportedOperationException(); + + } + + @Override + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + throw new UnsupportedOperationException(); + + } + + + // split the sql string by parameter place holder ('?') + public static List<String> tokenize(String sql) { + Preconditions.checkNotNull(sql); + + + // if closeQuote is not null we are inside string and have to ignore all ? + // and it will have value of closing quotes. + Character closeQuote = null; + + //last index till we have processed the string + int lastIndex = 0; + + ArrayList tokens = new ArrayList<String>(); + for (int index = 0; index < sql.length(); index++) { + + char sqlChar = sql.charAt(index); + if (ESCAPE_CHAR == sqlChar) { + index++; + continue; + } + + + if (closeQuote == null && OPEN_TO_CLOSE_QUOTES.containsKey(sqlChar)) { + closeQuote = OPEN_TO_CLOSE_QUOTES.get(sqlChar); + + } else if (closeQuote != null) { + if (closeQuote.equals(sqlChar)) { + closeQuote = null; + } + + } else if (sqlChar == '?') { + tokens.add(sql.substring(lastIndex, index)); + lastIndex = index + 1; + } + } + tokens.add(sql.substring(lastIndex, sql.length())); + + return tokens; + } + + public String compile() { + StringBuffer buf = new StringBuffer(); + buf.append(sqlTokens.get(0)); + for (int i = 0; i < parameters.size(); i++) { + buf.append(parameters.get(i)); + buf.append(sqlTokens.get(i + 1)); + } + return buf.toString(); + } + + private static String wrapString(String x) { + return "'" + x + "'"; + } + +} http://git-wip-us.apache.org/repos/asf/lens/blob/70855ea8/lens-client/src/test/java/org/apache/lens/jdbc/LensJdbcPreparedStatementTest.java ---------------------------------------------------------------------- diff --git a/lens-client/src/test/java/org/apache/lens/jdbc/LensJdbcPreparedStatementTest.java b/lens-client/src/test/java/org/apache/lens/jdbc/LensJdbcPreparedStatementTest.java new file mode 100644 index 0000000..310bb7e --- /dev/null +++ b/lens-client/src/test/java/org/apache/lens/jdbc/LensJdbcPreparedStatementTest.java @@ -0,0 +1,51 @@ +/** + * 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.lens.jdbc; + +import static org.apache.lens.client.jdbc.LensJdbcPreparedStatement.tokenize; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + + +public class LensJdbcPreparedStatementTest { + + @Test + public void testTokenize() { + List<String> out = tokenize("select * from tab limit ?"); + Assert.assertArrayEquals(new String[]{"select * from tab limit ", ""}, out.toArray()); + + out = tokenize("select * from tab where a = ? and b=c"); + Assert.assertArrayEquals(new String[]{"select * from tab where a = ", " and b=c"}, out.toArray()); + + out = tokenize("select \"? something \" from tab"); + Assert.assertArrayEquals(new String[]{"select \"? something \" from tab"}, out.toArray()); + + out = tokenize("select \'?\' from tab where a=?"); + Assert.assertArrayEquals(new String[]{"select \'?\' from tab where a=", ""}, out.toArray()); + + out = tokenize("select \'indian\\\'s\' from tab where a=b"); + Assert.assertArrayEquals(new String[]{"select 'indian\\'s' from tab where a=b"}, out.toArray()); + + + } + +}