http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/531d9ba3/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcDriver.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcDriver.java b/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcDriver.java new file mode 100644 index 0000000..5233a58 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcDriver.java @@ -0,0 +1,482 @@ +/* + * 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.ignite.jdbc; + + +import java.sql.*; +import java.util.*; +import java.util.logging.*; + +/** + * JDBC driver implementation for In-Memory Data Grid. + * <p> + * Driver allows to get distributed data from GridGain cache using standard + * SQL queries and standard JDBC API. It will automatically get only fields that + * you actually need from objects stored in cache. + * <h1 class="header">Limitations</h1> + * Data in GridGain cache is usually distributed across several nodes, + * so some queries may not work as expected since the query will be sent to each + * individual node and results will then be collected and returned as JDBC result set. + * Keep in mind following limitations (not applied if data is queried from one node only, + * or data is fully co-located or fully replicated on multiple nodes): + * <ul> + * <li> + * {@code Group by} and {@code sort by} statements are applied separately + * on each node, so result set will likely be incorrectly grouped or sorted + * after results from multiple remote nodes are grouped together. + * </li> + * <li> + * Aggregation functions like {@code sum}, {@code max}, {@code avg}, etc. + * are also applied on each node. Therefore you will get several results + * containing aggregated values, one for each node. + * </li> + * <li> + * Joins will work correctly only if joined objects are stored in + * collocated mode. Refer to + * {@link org.apache.ignite.cache.affinity.GridCacheAffinityKey} + * javadoc for more details. + * </li> + * <li> + * Note that if you are connected to local or replicated cache, all data will + * be queried only on one node, not depending on what caches participate in + * the query (some data from partitioned cache can be lost). And visa versa, + * if you are connected to partitioned cache, data from replicated caches + * will be duplicated. + * </li> + * </ul> + * <h1 class="header">SQL Notice</h1> + * Driver allows to query data from several caches. Cache that driver is connected to is + * treated as default schema in this case. Other caches can be referenced by their names. + * <p> + * Note that cache name is case sensitive and you have to always specify it in quotes. + * <h1 class="header">Dependencies</h1> + * JDBC driver is located in main GridGain JAR and depends on all libraries located in + * {@code GRIDGAIN_HOME/libs} folder. So if you are using JDBC driver in any external tool, + * you have to add main GridGain JAR will all dependencies to its classpath. + * <h1 class="header">Configuration</h1> + * Internally JDBC driver <b>is based on GridGain Java client</b>. Therefore, all client + * configuration properties can be applied to JDBC connection. + * <p> + * JDBC connection URL has the following pattern: + * {@code jdbc:gridgain://<hostname>:<port>/<cache_name>?nodeId=<UUID>}<br> + * Note the following: + * <ul> + * <li>Hostname is required.</li> + * <li>If port is not defined, {@code 11211} is used (default for GridGain client).</li> + * <li>Leave {@code <cache_name>} empty if you are connecting to default cache.</li> + * <li> + * Provide {@code nodeId} parameter if you want to specify node where to execute + * your queries. Note that local and replicated caches will be queried locally on + * this node while partitioned cache is queried distributively. If node ID is not + * provided, random node is used. If node with provided ID doesn't exist, + * exception is thrown. + * </li> + * </ul> + * Other properties can be defined in {@link Properties} object passed to + * {@link DriverManager#getConnection(String, Properties)} method: + * <table class="doctable"> + * <tr> + * <th>Name</th> + * <th>Description</th> + * <th>Default</th> + * <th>Optional</th> + * </tr> + * <tr> + * <td><b>gg.client.protocol</b></td> + * <td>Communication protocol ({@code TCP} or {@code HTTP}).</td> + * <td>{@code TCP}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.connectTimeout</b></td> + * <td>Socket connection timeout.</td> + * <td>{@code 0} (infinite timeout)</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.tcp.noDelay</b></td> + * <td>Flag indicating whether TCP_NODELAY flag should be enabled for outgoing connections.</td> + * <td>{@code true}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.enabled</b></td> + * <td>Flag indicating that {@code SSL} is needed for connection.</td> + * <td>{@code false}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.protocol</b></td> + * <td>SSL protocol ({@code SSL} or {@code TLS}).</td> + * <td>{@code TLS}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.key.algorithm</b></td> + * <td>Key manager algorithm.</td> + * <td>{@code SunX509}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.keystore.location</b></td> + * <td>Key store to be used by client to connect with GridGain topology.</td> + * <td> </td> + * <td>No (if {@code SSL} is enabled)</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.keystore.password</b></td> + * <td>Key store password.</td> + * <td> </td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.keystore.type</b></td> + * <td>Key store type.</td> + * <td>{@code jks}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.truststore.location</b></td> + * <td>Trust store to be used by client to connect with GridGain topology.</td> + * <td> </td> + * <td>No (if {@code SSL} is enabled)</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.truststore.password</b></td> + * <td>Trust store password.</td> + * <td> </td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.truststore.type</b></td> + * <td>Trust store type.</td> + * <td>{@code jks}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.credentials</b></td> + * <td>Client credentials used in authentication process.</td> + * <td> </td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.cache.top</b></td> + * <td> + * Flag indicating that topology is cached internally. Cache will be refreshed in + * the background with interval defined by {@code gg.client.topology.refresh} + * property (see below). + * </td> + * <td>{@code false}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.topology.refresh</b></td> + * <td>Topology cache refresh frequency (ms).</td> + * <td>{@code 2000}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.idleTimeout</b></td> + * <td>Maximum amount of time that connection can be idle before it is closed (ms).</td> + * <td>{@code 30000}</td> + * <td>Yes</td> + * </tr> + * </table> + * <h1 class="header">Example</h1> + * <pre name="code" class="java"> + * // Register JDBC driver. + * Class.forName("org.gridgain.jdbc.IgniteJdbcDriver"); + * + * // Open JDBC connection. + * Connection conn = DriverManager.getConnection("jdbc:gridgain://localhost/cache"); + * + * // Query persons' names + * ResultSet rs = conn.createStatement().executeQuery("select name from Person"); + * + * while (rs.next()) { + * String name = rs.getString(1); + * + * ... + * } + * + * // Query persons with specific age + * PreparedStatement stmt = conn.prepareStatement("select name, age from Person where age = ?"); + * + * stmt.setInt(1, 30); + * + * ResultSet rs = stmt.executeQuery(); + * + * while (rs.next()) { + * String name = rs.getString("name"); + * int age = rs.getInt("age"); + * + * ... + * } + * </pre> + */ +@SuppressWarnings("JavadocReference") +public class IgniteJdbcDriver implements Driver { + /** Prefix for property names. */ + private static final String PROP_PREFIX = "gg.jdbc."; + + /** Hostname property name. */ + static final String PROP_HOST = PROP_PREFIX + "host"; + + /** Port number property name. */ + static final String PROP_PORT = PROP_PREFIX + "port"; + + /** Cache name property name. */ + static final String PROP_CACHE = PROP_PREFIX + "cache"; + + /** Node ID URL parameter name. */ + static final String PARAM_NODE_ID = "nodeId"; + + /** Node ID property name. */ + static final String PROP_NODE_ID = PROP_PREFIX + PARAM_NODE_ID; + + /** URL prefix. */ + private static final String URL_PREFIX = "jdbc:gridgain://"; + + /** Default port. */ + private static final int DFLT_PORT = 11211; + + /** Major version. */ + private static final int MAJOR_VER = 1; + + /** Minor version. */ + private static final int MINOR_VER = 0; + + /** + * Register driver. + */ + static { + try { + DriverManager.registerDriver(new IgniteJdbcDriver()); + } + catch (SQLException e) { + throw new RuntimeException("Failed to register GridGain JDBC driver.", e); + } + } + + /** {@inheritDoc} */ + @Override public Connection connect(String url, Properties props) throws SQLException { + if (!parseUrl(url, props)) + throw new SQLException("URL is invalid: " + url); + + return new IgniteJdbcConnection(url, props); + } + + /** {@inheritDoc} */ + @Override public boolean acceptsURL(String url) throws SQLException { + return url.startsWith(URL_PREFIX); + } + + /** {@inheritDoc} */ + @Override public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + if (!parseUrl(url, info)) + throw new SQLException("URL is invalid: " + url); + + DriverPropertyInfo[] props = new DriverPropertyInfo[20]; + + props[0] = new PropertyInfo("Hostname", info.getProperty(PROP_HOST), true); + props[1] = new PropertyInfo("Port number", info.getProperty(PROP_PORT), ""); + props[2] = new PropertyInfo("Cache name", info.getProperty(PROP_CACHE), ""); + props[3] = new PropertyInfo("Node ID", info.getProperty(PROP_NODE_ID, "")); + props[4] = new PropertyInfo("gg.client.protocol", info.getProperty("gg.client.protocol", "TCP"), + "Communication protocol (TCP or HTTP)."); + props[5] = new PropertyInfo("gg.client.connectTimeout", info.getProperty("gg.client.connectTimeout", "0"), + "Socket connection timeout."); + props[6] = new PropertyInfo("gg.client.tcp.noDelay", info.getProperty("gg.client.tcp.noDelay", "true"), + "Flag indicating whether TCP_NODELAY flag should be enabled for outgoing connections."); + props[7] = new PropertyInfo("gg.client.ssl.enabled", info.getProperty("gg.client.ssl.enabled", "false"), + "Flag indicating that SSL is needed for connection."); + props[8] = new PropertyInfo("gg.client.ssl.protocol", info.getProperty("gg.client.ssl.protocol", "TLS"), + "SSL protocol."); + props[9] = new PropertyInfo("gg.client.ssl.key.algorithm", info.getProperty("gg.client.ssl.key.algorithm", + "SunX509"), "Key manager algorithm."); + props[10] = new PropertyInfo("gg.client.ssl.keystore.location", + info.getProperty("gg.client.ssl.keystore.location", ""), + "Key store to be used by client to connect with GridGain topology."); + props[11] = new PropertyInfo("gg.client.ssl.keystore.password", + info.getProperty("gg.client.ssl.keystore.password", ""), "Key store password."); + props[12] = new PropertyInfo("gg.client.ssl.keystore.type", info.getProperty("gg.client.ssl.keystore.type", + "jks"), "Key store type."); + props[13] = new PropertyInfo("gg.client.ssl.truststore.location", + info.getProperty("gg.client.ssl.truststore.location", ""), + "Trust store to be used by client to connect with GridGain topology."); + props[14] = new PropertyInfo("gg.client.ssl.keystore.password", + info.getProperty("gg.client.ssl.truststore.password", ""), "Trust store password."); + props[15] = new PropertyInfo("gg.client.ssl.truststore.type", info.getProperty("gg.client.ssl.truststore.type", + "jks"), "Trust store type."); + props[16] = new PropertyInfo("gg.client.credentials", info.getProperty("gg.client.credentials", ""), + "Client credentials used in authentication process."); + props[17] = new PropertyInfo("gg.client.cache.top", info.getProperty("gg.client.cache.top", "false"), + "Flag indicating that topology is cached internally. Cache will be refreshed in the background with " + + "interval defined by topologyRefreshFrequency property (see below)."); + props[18] = new PropertyInfo("gg.client.topology.refresh", info.getProperty("gg.client.topology.refresh", + "2000"), "Topology cache refresh frequency (ms)."); + props[19] = new PropertyInfo("gg.client.idleTimeout", info.getProperty("gg.client.idleTimeout", "30000"), + "Maximum amount of time that connection can be idle before it is closed (ms)."); + + return props; + } + + /** {@inheritDoc} */ + @Override public int getMajorVersion() { + return MAJOR_VER; + } + + /** {@inheritDoc} */ + @Override public int getMinorVersion() { + return MINOR_VER; + } + + /** {@inheritDoc} */ + @Override public boolean jdbcCompliant() { + return false; + } + + /** {@inheritDoc} */ + @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { + throw new SQLFeatureNotSupportedException("java.util.logging is not used."); + } + + /** + * Validates and parses connection URL. + * + * @param props Properties. + * @param url URL. + * @return Whether URL is valid. + */ + private boolean parseUrl(String url, Properties props) { + if (url == null || !url.startsWith(URL_PREFIX) || url.length() == URL_PREFIX.length()) + return false; + + url = url.substring(URL_PREFIX.length()); + + String[] parts = url.split("\\?"); + + if (parts.length > 2) + return false; + + if (parts.length == 2) + if (!parseUrlParameters(parts[1], props)) + return false; + + parts = parts[0].split("/"); + + assert parts.length > 0; + + if (parts.length > 2) + return false; + + if (parts.length == 2 && !parts[1].isEmpty()) + props.setProperty(PROP_CACHE, parts[1]); + + url = parts[0]; + + parts = url.split(":"); + + assert parts.length > 0; + + if (parts.length > 2) + return false; + + props.setProperty(PROP_HOST, parts[0]); + + try { + props.setProperty(PROP_PORT, String.valueOf(parts.length == 2 ? Integer.valueOf(parts[1]) : DFLT_PORT)); + } + catch (NumberFormatException ignored) { + return false; + } + + return true; + } + + /** + * Validates and parses URL parameters. + * + * @param urlParams URL parameters string. + * @param props Properties. + * @return Whether URL parameters string is valid. + */ + private boolean parseUrlParameters(String urlParams, Properties props) { + String[] params = urlParams.split("&"); + + for (String param : params) { + String[] pair = param.split("="); + + if (pair.length != 2 || pair[0].isEmpty() || pair[1].isEmpty()) + return false; + + props.setProperty(PROP_PREFIX + pair[0], pair[1]); + } + + return true; + } + + /** + * Extension of {@link DriverPropertyInfo} that adds + * convenient constructors. + */ + private static class PropertyInfo extends DriverPropertyInfo { + /** + * @param name Name. + * @param val Value. + */ + private PropertyInfo(String name, String val) { + super(name, val); + } + + /** + * @param name Name. + * @param val Value. + * @param desc Description. + */ + private PropertyInfo(String name, String val, String desc) { + super(name, val); + + description = desc; + } + + /** + * @param name Name. + * @param val Value. + * @param required Required flag. + */ + private PropertyInfo(String name, String val, boolean required) { + super(name, val); + + this.required = required; + } + + /** + * @param name Name. + * @param val Value. + * @param desc Description. + * @param required Required flag. + */ + private PropertyInfo(String name, String val, String desc, boolean required) { + super(name, val); + + description = desc; + this.required = required; + } + } +}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/531d9ba3/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcPreparedStatement.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcPreparedStatement.java b/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcPreparedStatement.java new file mode 100644 index 0000000..36cdb3e --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcPreparedStatement.java @@ -0,0 +1,411 @@ +/* + * 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.ignite.jdbc; + +import java.io.*; +import java.math.*; +import java.net.*; +import java.sql.*; +import java.sql.Date; +import java.util.*; + +/** + * JDBC prepared statement implementation. + */ +class IgniteJdbcPreparedStatement extends IgniteJdbcStatement implements PreparedStatement { + /** SQL query. */ + private final String sql; + + /** Arguments count. */ + private final int argsCnt; + + /** + * Creates new prepared statement. + * + * @param conn Connection. + * @param sql SQL query. + */ + IgniteJdbcPreparedStatement(IgniteJdbcConnection conn, String sql) { + super(conn); + + this.sql = sql; + + argsCnt = sql.replaceAll("[^?]", "").length(); + } + + /** {@inheritDoc} */ + @Override public ResultSet executeQuery() throws SQLException { + ResultSet rs = executeQuery(sql); + + args = null; + + return rs; + } + + /** {@inheritDoc} */ + @Override public int executeUpdate() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNull(int paramIdx, int sqlType) throws SQLException { + setArgument(paramIdx, null); + } + + /** {@inheritDoc} */ + @Override public void setBoolean(int paramIdx, boolean x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setByte(int paramIdx, byte x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setShort(int paramIdx, short x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setInt(int paramIdx, int x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setLong(int paramIdx, long x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setFloat(int paramIdx, float x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setDouble(int paramIdx, double x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setBigDecimal(int paramIdx, BigDecimal x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setString(int paramIdx, String x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setBytes(int paramIdx, byte[] x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setDate(int paramIdx, Date x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setTime(int paramIdx, Time x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setTimestamp(int paramIdx, Timestamp x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setAsciiStream(int paramIdx, InputStream x, int length) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setUnicodeStream(int paramIdx, InputStream x, int length) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setBinaryStream(int paramIdx, InputStream x, int length) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void clearParameters() throws SQLException { + ensureNotClosed(); + + args = null; + } + + /** {@inheritDoc} */ + @Override public void setObject(int paramIdx, Object x, int targetSqlType) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setObject(int paramIdx, Object x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public boolean execute() throws SQLException { + return execute(sql); + } + + /** {@inheritDoc} */ + @Override public void addBatch() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setCharacterStream(int paramIdx, Reader x, int length) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setRef(int paramIdx, Ref x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setBlob(int paramIdx, Blob x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setClob(int paramIdx, Clob x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setArray(int paramIdx, Array x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public ResultSetMetaData getMetaData() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Meta data for prepared statement is not supported."); + } + + /** {@inheritDoc} */ + @Override public void setDate(int paramIdx, Date x, Calendar cal) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setTime(int paramIdx, Time x, Calendar cal) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setTimestamp(int paramIdx, Timestamp x, Calendar cal) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setNull(int paramIdx, int sqlType, String typeName) throws SQLException { + setNull(paramIdx, sqlType); + } + + /** {@inheritDoc} */ + @Override public void setURL(int paramIdx, URL x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public ParameterMetaData getParameterMetaData() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Meta data for prepared statement is not supported."); + } + + /** {@inheritDoc} */ + @Override public void setRowId(int paramIdx, RowId x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNString(int paramIdx, String val) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNCharacterStream(int paramIdx, Reader val, long length) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNClob(int paramIdx, NClob val) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setClob(int paramIdx, Reader reader, long length) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setBlob(int paramIdx, InputStream inputStream, long length) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNClob(int paramIdx, Reader reader, long length) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setSQLXML(int paramIdx, SQLXML xmlObj) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setObject(int paramIdx, Object x, int targetSqlType, + int scaleOrLength) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setAsciiStream(int paramIdx, InputStream x, long length) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setBinaryStream(int paramIdx, InputStream x, long length) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setCharacterStream(int paramIdx, Reader x, long length) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setAsciiStream(int paramIdx, InputStream x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setBinaryStream(int paramIdx, InputStream x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setCharacterStream(int paramIdx, Reader x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNCharacterStream(int paramIdx, Reader val) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setClob(int paramIdx, Reader reader) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setBlob(int paramIdx, InputStream inputStream) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNClob(int paramIdx, Reader reader) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** + * Sets query argument value. + * + * @param paramIdx Index. + * @param val Value. + * @throws SQLException If index is invalid. + */ + private void setArgument(int paramIdx, Object val) throws SQLException { + ensureNotClosed(); + + if (paramIdx < 1 || paramIdx > argsCnt) + throw new SQLException("Parameter index is invalid: " + paramIdx); + + if (args == null) + args = new Object[argsCnt]; + + args[paramIdx - 1] = val; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/531d9ba3/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcResultSet.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcResultSet.java b/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcResultSet.java new file mode 100644 index 0000000..6d839b8 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcResultSet.java @@ -0,0 +1,1520 @@ +/* + * 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.ignite.jdbc; + +import org.apache.ignite.client.*; +import org.apache.ignite.internal.util.typedef.internal.*; +import org.apache.ignite.jdbc.typedef.*; + +import java.io.*; +import java.math.*; +import java.net.*; +import java.sql.*; +import java.sql.Date; +import java.util.*; + +/** + * JDBC result set implementation. + */ +class IgniteJdbcResultSet implements ResultSet { + /** Task name. */ + private static final String TASK_NAME = + "org.apache.ignite.internal.processors.cache.query.jdbc.GridCacheQueryJdbcTask"; + + /** Statement. */ + private final IgniteJdbcStatement stmt; + + /** Node ID. */ + private final UUID nodeId; + + /** Future ID. */ + private final UUID futId; + + /** Table names. */ + private final List<String> tbls; + + /** Column names. */ + private final List<String> cols; + + /** Class names. */ + private final List<String> types; + + /** Fields iterator. */ + private Iterator<List<Object>> fields; + + /** Finished flag. */ + private boolean finished; + + /** Current position. */ + private int pos; + + /** Current. */ + private List<Object> curr; + + /** Closed flag. */ + private boolean closed; + + /** Was {@code NULL} flag. */ + private boolean wasNull; + + /** Fetch size. */ + private int fetchSize; + + /** + * Creates new result set. + * + * @param stmt Statement. + * @param nodeId Node ID. + * @param futId Future ID. + * @param tbls Table names. + * @param cols Column names. + * @param types Types. + * @param fields Fields. + * @param finished Finished flag. + * @param fetchSize Fetch size. + */ + IgniteJdbcResultSet(IgniteJdbcStatement stmt, UUID nodeId, UUID futId, + List<String> tbls, List<String> cols, List<String> types, + Collection<List<Object>> fields, boolean finished, int fetchSize) { + assert stmt != null; + assert nodeId != null; + assert futId != null; + assert tbls != null; + assert cols != null; + assert types != null; + assert fields != null; + assert fetchSize > 0; + + this.stmt = stmt; + this.nodeId = nodeId; + this.futId = futId; + this.tbls = tbls; + this.cols = cols; + this.types = types; + this.fetchSize = fetchSize; + this.fields = fields.iterator(); + this.finished = finished; + } + + /** + * Creates new result set with predefined fields. + * Result set created with this constructor will + * never execute remote tasks. + * + * @param stmt Statement. + * @param tbls Table names. + * @param cols Column names. + * @param types Types. + * @param fields Fields. + */ + IgniteJdbcResultSet(IgniteJdbcStatement stmt, List<String> tbls, List<String> cols, + List<String> types, Collection<List<Object>> fields) { + assert stmt != null; + assert tbls != null; + assert cols != null; + assert types != null; + assert fields != null; + + this.stmt = stmt; + this.tbls = tbls; + this.cols = cols; + this.types = types; + this.fields = fields.iterator(); + + nodeId = null; + futId = null; + + // Prevent task execution. + finished = true; + } + + /** {@inheritDoc} */ + @Override public boolean next() throws SQLException { + ensureNotClosed(); + + if (fields == null && !finished) { + assert nodeId != null; + assert futId != null; + + try { + GridClientCompute compute = stmt.connection().client().compute(); + + GridClientCompute prj = compute.projection(compute.node(nodeId)); + + byte[] packet = prj.execute(TASK_NAME, JU.marshalArgument( + JU.taskArgument(nodeId, futId, fetchSize, stmt.getMaxRows()))); + + byte status = packet[0]; + byte[] data = new byte[packet.length - 1]; + + U.arrayCopy(packet, 1, data, 0, data.length); + + if (status == 1) + throw JU.unmarshalError(data); + else { + List<?> msg = JU.unmarshal(data); + + assert msg.size() == 2; + + fields = ((Collection<List<Object>>)msg.get(0)).iterator(); + finished = (Boolean)msg.get(1); + } + } + catch (GridClientException e) { + throw new SQLException("Failed to query GridGain.", e); + } + } + + if (fields != null && fields.hasNext()) { + curr = fields.next(); + + if (!fields.hasNext()) + fields = null; + + pos++; + + return true; + } + else { + curr = null; + + return false; + } + } + + /** {@inheritDoc} */ + @Override public void close() throws SQLException { + closed = true; + } + + /** {@inheritDoc} */ + @Override public boolean wasNull() throws SQLException { + return wasNull; + } + + /** {@inheritDoc} */ + @Override public String getString(int colIdx) throws SQLException { + return getTypedValue(colIdx, String.class); + } + + /** {@inheritDoc} */ + @Override public boolean getBoolean(int colIdx) throws SQLException { + Boolean val = getTypedValue(colIdx, Boolean.class); + + return val != null ? val : false; + } + + /** {@inheritDoc} */ + @Override public byte getByte(int colIdx) throws SQLException { + Byte val = getTypedValue(colIdx, Byte.class); + + return val != null ? val : 0; + } + + /** {@inheritDoc} */ + @Override public short getShort(int colIdx) throws SQLException { + Short val = getTypedValue(colIdx, Short.class); + + return val != null ? val : 0; + } + + /** {@inheritDoc} */ + @Override public int getInt(int colIdx) throws SQLException { + Integer val = getTypedValue(colIdx, Integer.class); + + return val != null ? val : 0; + } + + /** {@inheritDoc} */ + @Override public long getLong(int colIdx) throws SQLException { + Long val = getTypedValue(colIdx, Long.class); + + return val != null ? val : 0; + } + + /** {@inheritDoc} */ + @Override public float getFloat(int colIdx) throws SQLException { + Float val = getTypedValue(colIdx, Float.class); + + return val != null ? val : 0; + } + + /** {@inheritDoc} */ + @Override public double getDouble(int colIdx) throws SQLException { + Double val = getTypedValue(colIdx, Double.class); + + return val != null ? val : 0; + } + + /** {@inheritDoc} */ + @Override public BigDecimal getBigDecimal(int colIdx, int scale) throws SQLException { + return getTypedValue(colIdx, BigDecimal.class); + } + + /** {@inheritDoc} */ + @Override public byte[] getBytes(int colIdx) throws SQLException { + return getTypedValue(colIdx, byte[].class); + } + + /** {@inheritDoc} */ + @Override public Date getDate(int colIdx) throws SQLException { + return getTypedValue(colIdx, Date.class); + } + + /** {@inheritDoc} */ + @Override public Time getTime(int colIdx) throws SQLException { + return getTypedValue(colIdx, Time.class); + } + + /** {@inheritDoc} */ + @Override public Timestamp getTimestamp(int colIdx) throws SQLException { + return getTypedValue(colIdx, Timestamp.class); + } + + /** {@inheritDoc} */ + @Override public InputStream getAsciiStream(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public InputStream getUnicodeStream(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public InputStream getBinaryStream(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Stream are not supported."); + } + + /** {@inheritDoc} */ + @Override public String getString(String colLb) throws SQLException { + return getTypedValue(colLb, String.class); + } + + /** {@inheritDoc} */ + @Override public boolean getBoolean(String colLb) throws SQLException { + Boolean val = getTypedValue(colLb, Boolean.class); + + return val != null ? val : false; + } + + /** {@inheritDoc} */ + @Override public byte getByte(String colLb) throws SQLException { + Byte val = getTypedValue(colLb, Byte.class); + + return val != null ? val : 0; + } + + /** {@inheritDoc} */ + @Override public short getShort(String colLb) throws SQLException { + Short val = getTypedValue(colLb, Short.class); + + return val != null ? val : 0; + } + + /** {@inheritDoc} */ + @Override public int getInt(String colLb) throws SQLException { + Integer val = getTypedValue(colLb, Integer.class); + + return val != null ? val : 0; + } + + /** {@inheritDoc} */ + @Override public long getLong(String colLb) throws SQLException { + Long val = getTypedValue(colLb, Long.class); + + return val != null ? val : 0; + } + + /** {@inheritDoc} */ + @Override public float getFloat(String colLb) throws SQLException { + Float val = getTypedValue(colLb, Float.class); + + return val != null ? val : 0; + } + + /** {@inheritDoc} */ + @Override public double getDouble(String colLb) throws SQLException { + Double val = getTypedValue(colLb, Double.class); + + return val != null ? val : 0; + } + + /** {@inheritDoc} */ + @Override public BigDecimal getBigDecimal(String colLb, int scale) throws SQLException { + return getTypedValue(colLb, BigDecimal.class); + } + + /** {@inheritDoc} */ + @Override public byte[] getBytes(String colLb) throws SQLException { + return getTypedValue(colLb, byte[].class); + } + + /** {@inheritDoc} */ + @Override public Date getDate(String colLb) throws SQLException { + return getTypedValue(colLb, Date.class); + } + + /** {@inheritDoc} */ + @Override public Time getTime(String colLb) throws SQLException { + return getTypedValue(colLb, Time.class); + } + + /** {@inheritDoc} */ + @Override public Timestamp getTimestamp(String colLb) throws SQLException { + return getTypedValue(colLb, Timestamp.class); + } + + /** {@inheritDoc} */ + @Override public InputStream getAsciiStream(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public InputStream getUnicodeStream(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public InputStream getBinaryStream(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public SQLWarning getWarnings() throws SQLException { + ensureNotClosed(); + + return null; + } + + /** {@inheritDoc} */ + @Override public void clearWarnings() throws SQLException { + ensureNotClosed(); + } + + /** {@inheritDoc} */ + @Override public String getCursorName() throws SQLException { + ensureNotClosed(); + + return null; + } + + /** {@inheritDoc} */ + @Override public ResultSetMetaData getMetaData() throws SQLException { + ensureNotClosed(); + + return new IgniteJdbcResultSetMetadata(tbls, cols, types); + } + + /** {@inheritDoc} */ + @Override public Object getObject(int colIdx) throws SQLException { + return getTypedValue(colIdx, Object.class); + } + + /** {@inheritDoc} */ + @Override public Object getObject(String colLb) throws SQLException { + return getTypedValue(colLb, Object.class); + } + + /** {@inheritDoc} */ + @Override public int findColumn(String colLb) throws SQLException { + ensureNotClosed(); + + int idx = cols.indexOf(colLb.toUpperCase()); + + if (idx == -1) + throw new SQLException("Column not found: " + colLb); + + return idx + 1; + } + + /** {@inheritDoc} */ + @Override public Reader getCharacterStream(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public Reader getCharacterStream(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public BigDecimal getBigDecimal(int colIdx) throws SQLException { + return getTypedValue(colIdx, BigDecimal.class); + } + + /** {@inheritDoc} */ + @Override public BigDecimal getBigDecimal(String colLb) throws SQLException { + return getTypedValue(colLb, BigDecimal.class); + } + + /** {@inheritDoc} */ + @Override public boolean isBeforeFirst() throws SQLException { + ensureNotClosed(); + + return pos < 1; + } + + /** {@inheritDoc} */ + @Override public boolean isAfterLast() throws SQLException { + ensureNotClosed(); + + return finished && fields == null && curr == null; + } + + /** {@inheritDoc} */ + @Override public boolean isFirst() throws SQLException { + ensureNotClosed(); + + return pos == 1; + } + + /** {@inheritDoc} */ + @Override public boolean isLast() throws SQLException { + ensureNotClosed(); + + return finished && fields == null && curr != null; + } + + /** {@inheritDoc} */ + @Override public void beforeFirst() throws SQLException { + ensureNotClosed(); + + throw new SQLException("Result set is forward-only."); + } + + /** {@inheritDoc} */ + @Override public void afterLast() throws SQLException { + ensureNotClosed(); + + throw new SQLException("Result set is forward-only."); + } + + /** {@inheritDoc} */ + @Override public boolean first() throws SQLException { + ensureNotClosed(); + + throw new SQLException("Result set is forward-only."); + } + + /** {@inheritDoc} */ + @Override public boolean last() throws SQLException { + ensureNotClosed(); + + throw new SQLException("Result set is forward-only."); + } + + /** {@inheritDoc} */ + @Override public int getRow() throws SQLException { + ensureNotClosed(); + + return isAfterLast() ? 0 : pos; + } + + /** {@inheritDoc} */ + @Override public boolean absolute(int row) throws SQLException { + ensureNotClosed(); + + throw new SQLException("Result set is forward-only."); + } + + /** {@inheritDoc} */ + @Override public boolean relative(int rows) throws SQLException { + ensureNotClosed(); + + throw new SQLException("Result set is forward-only."); + } + + /** {@inheritDoc} */ + @Override public boolean previous() throws SQLException { + ensureNotClosed(); + + throw new SQLException("Result set is forward-only."); + } + + /** {@inheritDoc} */ + @Override public void setFetchDirection(int direction) throws SQLException { + ensureNotClosed(); + + if (direction != FETCH_FORWARD) + throw new SQLFeatureNotSupportedException("Only forward direction is supported"); + } + + /** {@inheritDoc} */ + @Override public int getFetchDirection() throws SQLException { + ensureNotClosed(); + + return FETCH_FORWARD; + } + + /** {@inheritDoc} */ + @Override public void setFetchSize(int fetchSize) throws SQLException { + ensureNotClosed(); + + if (fetchSize <= 0) + throw new SQLException("Fetch size must be greater than zero."); + + this.fetchSize = fetchSize; + } + + /** {@inheritDoc} */ + @Override public int getFetchSize() throws SQLException { + ensureNotClosed(); + + return fetchSize; + } + + /** {@inheritDoc} */ + @Override public int getType() throws SQLException { + ensureNotClosed(); + + return stmt.getResultSetType(); + } + + /** {@inheritDoc} */ + @Override public int getConcurrency() throws SQLException { + ensureNotClosed(); + + return CONCUR_READ_ONLY; + } + + /** {@inheritDoc} */ + @Override public boolean rowUpdated() throws SQLException { + ensureNotClosed(); + + return false; + } + + /** {@inheritDoc} */ + @Override public boolean rowInserted() throws SQLException { + ensureNotClosed(); + + return false; + } + + /** {@inheritDoc} */ + @Override public boolean rowDeleted() throws SQLException { + ensureNotClosed(); + + return false; + } + + /** {@inheritDoc} */ + @Override public void updateNull(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBoolean(int colIdx, boolean x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateByte(int colIdx, byte x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateShort(int colIdx, short x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateInt(int colIdx, int x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateLong(int colIdx, long x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateFloat(int colIdx, float x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateDouble(int colIdx, double x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBigDecimal(int colIdx, BigDecimal x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateString(int colIdx, String x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBytes(int colIdx, byte[] x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateDate(int colIdx, Date x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateTime(int colIdx, Time x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateTimestamp(int colIdx, Timestamp x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateAsciiStream(int colIdx, InputStream x, int len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBinaryStream(int colIdx, InputStream x, int len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateCharacterStream(int colIdx, Reader x, int len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateObject(int colIdx, Object x, int scaleOrLen) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateObject(int colIdx, Object x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateNull(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBoolean(String colLb, boolean x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateByte(String colLb, byte x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateShort(String colLb, short x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateInt(String colLb, int x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateLong(String colLb, long x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateFloat(String colLb, float x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateDouble(String colLb, double x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBigDecimal(String colLb, BigDecimal x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateString(String colLb, String x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBytes(String colLb, byte[] x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateDate(String colLb, Date x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateTime(String colLb, Time x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateTimestamp(String colLb, Timestamp x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateAsciiStream(String colLb, InputStream x, int len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBinaryStream(String colLb, InputStream x, int len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateCharacterStream(String colLb, Reader reader, int len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateObject(String colLb, Object x, int scaleOrLen) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateObject(String colLb, Object x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void insertRow() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateRow() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void deleteRow() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void refreshRow() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Row refreshing is not supported."); + } + + /** {@inheritDoc} */ + @Override public void cancelRowUpdates() throws SQLException { + ensureNotClosed(); + } + + /** {@inheritDoc} */ + @Override public void moveToInsertRow() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void moveToCurrentRow() throws SQLException { + ensureNotClosed(); + } + + /** {@inheritDoc} */ + @Override public Statement getStatement() throws SQLException { + ensureNotClosed(); + + return stmt; + } + + /** {@inheritDoc} */ + @Override public Object getObject(int colIdx, Map<String, Class<?>> map) throws SQLException { + return getTypedValue(colIdx, Object.class); + } + + /** {@inheritDoc} */ + @Override public Ref getRef(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public Blob getBlob(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public Clob getClob(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public Array getArray(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public Object getObject(String colLb, Map<String, Class<?>> map) throws SQLException { + return getTypedValue(colLb, Object.class); + } + + /** {@inheritDoc} */ + @Override public Ref getRef(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public Blob getBlob(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public Clob getClob(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public Array getArray(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public Date getDate(int colIdx, Calendar cal) throws SQLException { + return getTypedValue(colIdx, Date.class); + } + + /** {@inheritDoc} */ + @Override public Date getDate(String colLb, Calendar cal) throws SQLException { + return getTypedValue(colLb, Date.class); + } + + /** {@inheritDoc} */ + @Override public Time getTime(int colIdx, Calendar cal) throws SQLException { + return getTypedValue(colIdx, Time.class); + } + + /** {@inheritDoc} */ + @Override public Time getTime(String colLb, Calendar cal) throws SQLException { + return getTypedValue(colLb, Time.class); + } + + /** {@inheritDoc} */ + @Override public Timestamp getTimestamp(int colIdx, Calendar cal) throws SQLException { + return getTypedValue(colIdx, Timestamp.class); + } + + /** {@inheritDoc} */ + @Override public Timestamp getTimestamp(String colLb, Calendar cal) throws SQLException { + return getTypedValue(colLb, Timestamp.class); + } + + /** {@inheritDoc} */ + @Override public URL getURL(int colIdx) throws SQLException { + return getTypedValue(colIdx, URL.class); + } + + /** {@inheritDoc} */ + @Override public URL getURL(String colLb) throws SQLException { + return getTypedValue(colLb, URL.class); + } + + /** {@inheritDoc} */ + @Override public void updateRef(int colIdx, Ref x) throws SQLException { + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateRef(String colLb, Ref x) throws SQLException { + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBlob(int colIdx, Blob x) throws SQLException { + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBlob(String colLb, Blob x) throws SQLException { + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateClob(int colIdx, Clob x) throws SQLException { + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateClob(String colLb, Clob x) throws SQLException { + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateArray(int colIdx, Array x) throws SQLException { + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateArray(String colLb, Array x) throws SQLException { + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public RowId getRowId(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public RowId getRowId(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateRowId(int colIdx, RowId x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateRowId(String colLb, RowId x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public int getHoldability() throws SQLException { + ensureNotClosed(); + + return HOLD_CURSORS_OVER_COMMIT; + } + + /** {@inheritDoc} */ + @Override public boolean isClosed() throws SQLException { + return closed; + } + + /** {@inheritDoc} */ + @Override public void updateNString(int colIdx, String nStr) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateNString(String colLb, String nStr) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateNClob(int colIdx, NClob nClob) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateNClob(String colLb, NClob nClob) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public NClob getNClob(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public NClob getNClob(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public SQLXML getSQLXML(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public SQLXML getSQLXML(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateSQLXML(int colIdx, SQLXML xmlObj) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateSQLXML(String colLb, SQLXML xmlObj) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public String getNString(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public String getNString(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public Reader getNCharacterStream(int colIdx) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public Reader getNCharacterStream(String colLb) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateNCharacterStream(int colIdx, Reader x, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateNCharacterStream(String colLb, Reader reader, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateAsciiStream(int colIdx, InputStream x, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBinaryStream(int colIdx, InputStream x, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateCharacterStream(int colIdx, Reader x, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateAsciiStream(String colLb, InputStream x, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBinaryStream(String colLb, InputStream x, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateCharacterStream(String colLb, Reader reader, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBlob(int colIdx, InputStream inputStream, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBlob(String colLb, InputStream inputStream, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateClob(int colIdx, Reader reader, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateClob(String colLb, Reader reader, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateNClob(int colIdx, Reader reader, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateNClob(String colLb, Reader reader, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateNCharacterStream(int colIdx, Reader x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateNCharacterStream(String colLb, Reader reader) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateAsciiStream(int colIdx, InputStream x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBinaryStream(int colIdx, InputStream x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateCharacterStream(int colIdx, Reader x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateAsciiStream(String colLb, InputStream x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBinaryStream(String colLb, InputStream x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateCharacterStream(String colLb, Reader reader) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBlob(int colIdx, InputStream inputStream) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateBlob(String colLb, InputStream inputStream) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateClob(int colIdx, Reader reader) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateClob(String colLb, Reader reader) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateNClob(int colIdx, Reader reader) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void updateNClob(String colLb, Reader reader) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public <T> T unwrap(Class<T> iface) throws SQLException { + if (!isWrapperFor(iface)) + throw new SQLException("Result set is not a wrapper for " + iface.getName()); + + return (T)this; + } + + /** {@inheritDoc} */ + @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { + return iface != null && iface == ResultSet.class; + } + + /** {@inheritDoc} */ + @Override public <T> T getObject(int colIdx, Class<T> type) throws SQLException { + return getTypedValue(colIdx, type); + } + + /** {@inheritDoc} */ + @Override public <T> T getObject(String colLb, Class<T> type) throws SQLException { + return getTypedValue(colLb, type); + } + + /** + * Gets casted field value by label. + * + * @param colLb Column label. + * @param cls Value class. + * @return Casted field value. + * @throws SQLException In case of error. + */ + private <T> T getTypedValue(String colLb, Class<T> cls) throws SQLException { + ensureNotClosed(); + ensureHasCurrentRow(); + + int colIdx = cols.indexOf(colLb.toUpperCase()) + 1; + + if (colIdx <= 0) + throw new SQLException("Invalid column label: " + colLb); + + return getTypedValue(colIdx, cls); + } + + /** + * Gets casted field value by index. + * + * @param colIdx Column index. + * @param cls Value class. + * @return Casted field value. + * @throws SQLException In case of error. + */ + private <T> T getTypedValue(int colIdx, Class<T> cls) throws SQLException { + ensureNotClosed(); + ensureHasCurrentRow(); + + try { + T val = cls == String.class ? (T)String.valueOf(curr.get(colIdx - 1)) : (T)curr.get(colIdx - 1); + + wasNull = val == null; + + return val; + } + catch (IndexOutOfBoundsException ignored) { + throw new SQLException("Invalid column index: " + colIdx); + } + catch (ClassCastException ignored) { + throw new SQLException("Value is an not instance of " + cls.getName()); + } + } + + /** + * Ensures that result set is not closed. + * + * @throws SQLException If result set is closed. + */ + private void ensureNotClosed() throws SQLException { + if (closed) + throw new SQLException("Result set is closed."); + } + + /** + * Ensures that result set is positioned on a row. + * + * @throws SQLException If result set is not positioned on a row. + */ + private void ensureHasCurrentRow() throws SQLException { + if (curr == null) + throw new SQLException("Result set is not positioned on a row."); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/531d9ba3/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcResultSetMetadata.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcResultSetMetadata.java b/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcResultSetMetadata.java new file mode 100644 index 0000000..e95e9aa --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/jdbc/IgniteJdbcResultSetMetadata.java @@ -0,0 +1,172 @@ +/* + * 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.ignite.jdbc; + +import org.apache.ignite.jdbc.typedef.*; + +import java.sql.*; +import java.util.*; + +/** + * JDBC result set metadata implementation. + */ +class IgniteJdbcResultSetMetadata implements ResultSetMetaData { + /** Column width. */ + private static final int COL_WIDTH = 30; + + /** Table names. */ + private final List<String> tbls; + + /** Column names. */ + private final List<String> cols; + + /** Class names. */ + private final List<String> types; + + /** + * @param tbls Table names. + * @param cols Column names. + * @param types Types. + */ + IgniteJdbcResultSetMetadata(List<String> tbls, List<String> cols, List<String> types) { + assert cols != null; + assert types != null; + + this.tbls = tbls; + this.cols = cols; + this.types = types; + } + + /** {@inheritDoc} */ + @Override public int getColumnCount() throws SQLException { + return cols.size(); + } + + /** {@inheritDoc} */ + @Override public boolean isAutoIncrement(int col) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean isCaseSensitive(int col) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean isSearchable(int col) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean isCurrency(int col) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public int isNullable(int col) throws SQLException { + return columnNullable; + } + + /** {@inheritDoc} */ + @Override public boolean isSigned(int col) throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public int getColumnDisplaySize(int col) throws SQLException { + return COL_WIDTH; + } + + /** {@inheritDoc} */ + @Override public String getColumnLabel(int col) throws SQLException { + return cols.get(col - 1); + } + + /** {@inheritDoc} */ + @Override public String getColumnName(int col) throws SQLException { + return cols.get(col - 1); + } + + /** {@inheritDoc} */ + @Override public String getSchemaName(int col) throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public int getPrecision(int col) throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getScale(int col) throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public String getTableName(int col) throws SQLException { + return tbls != null ? tbls.get(col - 1) : ""; + } + + /** {@inheritDoc} */ + @Override public String getCatalogName(int col) throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public int getColumnType(int col) throws SQLException { + return JU.type(types.get(col - 1)); + } + + /** {@inheritDoc} */ + @Override public String getColumnTypeName(int col) throws SQLException { + return JU.typeName(types.get(col - 1)); + } + + /** {@inheritDoc} */ + @Override public boolean isReadOnly(int col) throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean isWritable(int col) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean isDefinitelyWritable(int col) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public String getColumnClassName(int col) throws SQLException { + return types.get(col - 1); + } + + /** {@inheritDoc} */ + @Override public <T> T unwrap(Class<T> iface) throws SQLException { + if (!isWrapperFor(iface)) + throw new SQLException("Result set meta data is not a wrapper for " + iface.getName()); + + return (T)this; + } + + /** {@inheritDoc} */ + @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { + return iface == ResultSetMetaData.class; + } +}