feature: add driver module & upgrade redis version from 3.6.3 to 4.3.1 (#267)

This commit is contained in:
qianmoQ 2023-03-06 09:55:01 +08:00 committed by GitHub
commit 05126611cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 4894 additions and 7 deletions

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>datacap</artifactId>
<groupId>io.edurt.datacap</groupId>
<version>1.6.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-driver-redis</artifactId>
<description>DataCap - Driver</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${redis.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${plugin.maven.checkstyle.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,974 @@
package io.edurt.datacap.core;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.*;
import java.util.Calendar;
import java.util.Map;
public class EmptyResultSet implements ResultSet {
private final static Logger LOGGER = new Logger(EmptyResultSet.class);
@Override
public boolean next() throws SQLException {
return false;
}
@Override
public void close() throws SQLException {
LOGGER.log("close()");
}
@Override
public boolean wasNull() throws SQLException {
return false;
}
@Override
public String getString(int columnIndex) throws SQLException {
return null;
}
@Override
public boolean getBoolean(int columnIndex) throws SQLException {
return false;
}
@Override
public byte getByte(int columnIndex) throws SQLException {
return 0;
}
@Override
public short getShort(int columnIndex) throws SQLException {
return 0;
}
@Override
public int getInt(int columnIndex) throws SQLException {
return 0;
}
@Override
public long getLong(int columnIndex) throws SQLException {
return 0;
}
@Override
public float getFloat(int columnIndex) throws SQLException {
return 0;
}
@Override
public double getDouble(int columnIndex) throws SQLException {
return 0;
}
@Override
public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
return null;
}
@Override
public byte[] getBytes(int columnIndex) throws SQLException {
return new byte[0];
}
@Override
public Date getDate(int columnIndex) throws SQLException {
return null;
}
@Override
public Time getTime(int columnIndex) throws SQLException {
return null;
}
@Override
public Timestamp getTimestamp(int columnIndex) throws SQLException {
return null;
}
@Override
public InputStream getAsciiStream(int columnIndex) throws SQLException {
return null;
}
@Override
public InputStream getUnicodeStream(int columnIndex) throws SQLException {
return null;
}
@Override
public InputStream getBinaryStream(int columnIndex) throws SQLException {
return null;
}
@Override
public String getString(String columnLabel) throws SQLException {
return null;
}
@Override
public boolean getBoolean(String columnLabel) throws SQLException {
return false;
}
@Override
public byte getByte(String columnLabel) throws SQLException {
return 0;
}
@Override
public short getShort(String columnLabel) throws SQLException {
return 0;
}
@Override
public int getInt(String columnLabel) throws SQLException {
return 0;
}
@Override
public long getLong(String columnLabel) throws SQLException {
return 0;
}
@Override
public float getFloat(String columnLabel) throws SQLException {
return 0;
}
@Override
public double getDouble(String columnLabel) throws SQLException {
return 0;
}
@Override
public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException {
return null;
}
@Override
public byte[] getBytes(String columnLabel) throws SQLException {
return new byte[0];
}
@Override
public Date getDate(String columnLabel) throws SQLException {
return null;
}
@Override
public Time getTime(String columnLabel) throws SQLException {
return null;
}
@Override
public Timestamp getTimestamp(String columnLabel) throws SQLException {
return null;
}
@Override
public InputStream getAsciiStream(String columnLabel) throws SQLException {
return null;
}
@Override
public InputStream getUnicodeStream(String columnLabel) throws SQLException {
return null;
}
@Override
public InputStream getBinaryStream(String columnLabel) throws SQLException {
return null;
}
@Override
public SQLWarning getWarnings() throws SQLException {
return null;
}
@Override
public void clearWarnings() throws SQLException {
}
@Override
public String getCursorName() throws SQLException {
return null;
}
@Override
public ResultSetMetaData getMetaData() throws SQLException {
return null;
}
@Override
public Object getObject(int columnIndex) throws SQLException {
return null;
}
@Override
public Object getObject(String columnLabel) throws SQLException {
return null;
}
@Override
public int findColumn(String columnLabel) throws SQLException {
return 0;
}
@Override
public Reader getCharacterStream(int columnIndex) throws SQLException {
return null;
}
@Override
public Reader getCharacterStream(String columnLabel) throws SQLException {
return null;
}
@Override
public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
return null;
}
@Override
public BigDecimal getBigDecimal(String columnLabel) throws SQLException {
return null;
}
@Override
public boolean isBeforeFirst() throws SQLException {
return false;
}
@Override
public boolean isAfterLast() throws SQLException {
return false;
}
@Override
public boolean isFirst() throws SQLException {
return false;
}
@Override
public boolean isLast() throws SQLException {
return false;
}
@Override
public void beforeFirst() throws SQLException {
}
@Override
public void afterLast() throws SQLException {
}
@Override
public boolean first() throws SQLException {
return false;
}
@Override
public boolean last() throws SQLException {
return false;
}
@Override
public int getRow() throws SQLException {
return 0;
}
@Override
public boolean absolute(int row) throws SQLException {
return false;
}
@Override
public boolean relative(int rows) throws SQLException {
return false;
}
@Override
public boolean previous() throws SQLException {
return false;
}
@Override
public void setFetchDirection(int direction) throws SQLException {
}
@Override
public int getFetchDirection() throws SQLException {
return 0;
}
@Override
public void setFetchSize(int rows) throws SQLException {
}
@Override
public int getFetchSize() throws SQLException {
return 0;
}
@Override
public int getType() throws SQLException {
return 0;
}
@Override
public int getConcurrency() throws SQLException {
return 0;
}
@Override
public boolean rowUpdated() throws SQLException {
return false;
}
@Override
public boolean rowInserted() throws SQLException {
return false;
}
@Override
public boolean rowDeleted() throws SQLException {
return false;
}
@Override
public void updateNull(int columnIndex) throws SQLException {
}
@Override
public void updateBoolean(int columnIndex, boolean x) throws SQLException {
}
@Override
public void updateByte(int columnIndex, byte x) throws SQLException {
}
@Override
public void updateShort(int columnIndex, short x) throws SQLException {
}
@Override
public void updateInt(int columnIndex, int x) throws SQLException {
}
@Override
public void updateLong(int columnIndex, long x) throws SQLException {
}
@Override
public void updateFloat(int columnIndex, float x) throws SQLException {
}
@Override
public void updateDouble(int columnIndex, double x) throws SQLException {
}
@Override
public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException {
}
@Override
public void updateString(int columnIndex, String x) throws SQLException {
}
@Override
public void updateBytes(int columnIndex, byte[] x) throws SQLException {
}
@Override
public void updateDate(int columnIndex, Date x) throws SQLException {
}
@Override
public void updateTime(int columnIndex, Time x) throws SQLException {
}
@Override
public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {
}
@Override
public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException {
}
@Override
public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException {
}
@Override
public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException {
}
@Override
public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException {
}
@Override
public void updateObject(int columnIndex, Object x) throws SQLException {
}
@Override
public void updateNull(String columnLabel) throws SQLException {
}
@Override
public void updateBoolean(String columnLabel, boolean x) throws SQLException {
}
@Override
public void updateByte(String columnLabel, byte x) throws SQLException {
}
@Override
public void updateShort(String columnLabel, short x) throws SQLException {
}
@Override
public void updateInt(String columnLabel, int x) throws SQLException {
}
@Override
public void updateLong(String columnLabel, long x) throws SQLException {
}
@Override
public void updateFloat(String columnLabel, float x) throws SQLException {
}
@Override
public void updateDouble(String columnLabel, double x) throws SQLException {
}
@Override
public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException {
}
@Override
public void updateString(String columnLabel, String x) throws SQLException {
}
@Override
public void updateBytes(String columnLabel, byte[] x) throws SQLException {
}
@Override
public void updateDate(String columnLabel, Date x) throws SQLException {
}
@Override
public void updateTime(String columnLabel, Time x) throws SQLException {
}
@Override
public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException {
}
@Override
public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException {
}
@Override
public void updateBinaryStream(String columnLabel, InputStream x, int length) throws SQLException {
}
@Override
public void updateCharacterStream(String columnLabel, Reader reader, int length) throws SQLException {
}
@Override
public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException {
}
@Override
public void updateObject(String columnLabel, Object x) throws SQLException {
}
@Override
public void insertRow() throws SQLException {
}
@Override
public void updateRow() throws SQLException {
}
@Override
public void deleteRow() throws SQLException {
}
@Override
public void refreshRow() throws SQLException {
}
@Override
public void cancelRowUpdates() throws SQLException {
}
@Override
public void moveToInsertRow() throws SQLException {
}
@Override
public void moveToCurrentRow() throws SQLException {
}
@Override
public Statement getStatement() throws SQLException {
return null;
}
@Override
public Object getObject(int columnIndex, Map<String, Class<?>> map) throws SQLException {
return null;
}
@Override
public Ref getRef(int columnIndex) throws SQLException {
return null;
}
@Override
public Blob getBlob(int columnIndex) throws SQLException {
return null;
}
@Override
public Clob getClob(int columnIndex) throws SQLException {
return null;
}
@Override
public Array getArray(int columnIndex) throws SQLException {
return null;
}
@Override
public Object getObject(String columnLabel, Map<String, Class<?>> map) throws SQLException {
return null;
}
@Override
public Ref getRef(String columnLabel) throws SQLException {
return null;
}
@Override
public Blob getBlob(String columnLabel) throws SQLException {
return null;
}
@Override
public Clob getClob(String columnLabel) throws SQLException {
return null;
}
@Override
public Array getArray(String columnLabel) throws SQLException {
return null;
}
@Override
public Date getDate(int columnIndex, Calendar cal) throws SQLException {
return null;
}
@Override
public Date getDate(String columnLabel, Calendar cal) throws SQLException {
return null;
}
@Override
public Time getTime(int columnIndex, Calendar cal) throws SQLException {
return null;
}
@Override
public Time getTime(String columnLabel, Calendar cal) throws SQLException {
return null;
}
@Override
public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
return null;
}
@Override
public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException {
return null;
}
@Override
public URL getURL(int columnIndex) throws SQLException {
return null;
}
@Override
public URL getURL(String columnLabel) throws SQLException {
return null;
}
@Override
public void updateRef(int columnIndex, Ref x) throws SQLException {
}
@Override
public void updateRef(String columnLabel, Ref x) throws SQLException {
}
@Override
public void updateBlob(int columnIndex, Blob x) throws SQLException {
}
@Override
public void updateBlob(String columnLabel, Blob x) throws SQLException {
}
@Override
public void updateClob(int columnIndex, Clob x) throws SQLException {
}
@Override
public void updateClob(String columnLabel, Clob x) throws SQLException {
}
@Override
public void updateArray(int columnIndex, Array x) throws SQLException {
}
@Override
public void updateArray(String columnLabel, Array x) throws SQLException {
}
@Override
public RowId getRowId(int columnIndex) throws SQLException {
return null;
}
@Override
public RowId getRowId(String columnLabel) throws SQLException {
return null;
}
@Override
public void updateRowId(int columnIndex, RowId x) throws SQLException {
}
@Override
public void updateRowId(String columnLabel, RowId x) throws SQLException {
}
@Override
public int getHoldability() throws SQLException {
return 0;
}
@Override
public boolean isClosed() throws SQLException {
LOGGER.log("isClosed = %s", false);
return false;
}
@Override
public void updateNString(int columnIndex, String nString) throws SQLException {
}
@Override
public void updateNString(String columnLabel, String nString) throws SQLException {
}
@Override
public void updateNClob(int columnIndex, NClob nClob) throws SQLException {
}
@Override
public void updateNClob(String columnLabel, NClob nClob) throws SQLException {
}
@Override
public NClob getNClob(int columnIndex) throws SQLException {
return null;
}
@Override
public NClob getNClob(String columnLabel) throws SQLException {
return null;
}
@Override
public SQLXML getSQLXML(int columnIndex) throws SQLException {
return null;
}
@Override
public SQLXML getSQLXML(String columnLabel) throws SQLException {
return null;
}
@Override
public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException {
}
@Override
public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException {
}
@Override
public String getNString(int columnIndex) throws SQLException {
return null;
}
@Override
public String getNString(String columnLabel) throws SQLException {
return null;
}
@Override
public Reader getNCharacterStream(int columnIndex) throws SQLException {
return null;
}
@Override
public Reader getNCharacterStream(String columnLabel) throws SQLException {
return null;
}
@Override
public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
}
@Override
public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException {
}
@Override
public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException {
}
@Override
public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException {
}
@Override
public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException {
}
@Override
public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException {
}
@Override
public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException {
}
@Override
public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException {
}
@Override
public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException {
}
@Override
public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException {
}
@Override
public void updateClob(int columnIndex, Reader reader, long length) throws SQLException {
}
@Override
public void updateClob(String columnLabel, Reader reader, long length) throws SQLException {
}
@Override
public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException {
}
@Override
public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException {
}
@Override
public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException {
}
@Override
public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException {
}
@Override
public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException {
}
@Override
public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException {
}
@Override
public void updateCharacterStream(int columnIndex, Reader x) throws SQLException {
}
@Override
public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException {
}
@Override
public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException {
}
@Override
public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException {
}
@Override
public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException {
}
@Override
public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException {
}
@Override
public void updateClob(int columnIndex, Reader reader) throws SQLException {
}
@Override
public void updateClob(String columnLabel, Reader reader) throws SQLException {
}
@Override
public void updateNClob(int columnIndex, Reader reader) throws SQLException {
}
@Override
public void updateNClob(String columnLabel, Reader reader) throws SQLException {
}
@Override
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
return null;
}
@Override
public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
try {
return iface.cast(this);
} catch (ClassCastException cce) {
LOGGER.log("Unable to unwrap to %s", iface);
throw new SQLException("Unable to unwrap to " + iface);
}
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return iface.isInstance(this);
}
}

View File

@ -0,0 +1,21 @@
package io.edurt.datacap.core;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Hint {
/**
* hint key
*/
private HintKey key;
/**
* hint value
*/
private String value;
}

View File

@ -0,0 +1,17 @@
package io.edurt.datacap.core;
import java.util.Arrays;
import java.util.Objects;
public enum HintKey {
decoder,
sample_key,
noop;
public static HintKey fromString(String string) {
return Arrays.stream(values())
.filter(t -> Objects.equals(t.toString(), string))
.findFirst()
.orElse(noop);
}
}

View File

@ -0,0 +1,23 @@
package io.edurt.datacap.core;
import java.util.Arrays;
public class Logger {
private final Class<?> mark;
public Logger(Class<?> mark) {
this.mark = mark;
}
public synchronized void log(String format, Object... arguments) {
Object[] objs = Arrays.stream(arguments)
.map(t -> {
if (t instanceof Throwable) {
Throwable th = (Throwable) t;
return th.getMessage();
}
return t;
}).toArray(Object[]::new);
System.out.printf(mark + ":::" + format + "\n", objs);
}
}

View File

@ -0,0 +1,32 @@
package io.edurt.datacap.core;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Op {
/**
* 执行的原始SQL
*/
private String originSql;
/**
* SQL中解析出来的hint
*/
private List<Hint> hints;
/**
* SQL中解析出来的command
*/
private String command;
/**
* SQL解析出来的参数
*/
private String[] params;
}

View File

@ -0,0 +1,11 @@
package io.edurt.datacap.core;
import java.sql.SQLException;
public interface RedisClient {
String[] sendCommand(String sql) throws SQLException;
void select(int dbIndex) throws SQLException;
void close();
}

View File

@ -0,0 +1,357 @@
package io.edurt.datacap.core;
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
public class RedisConnection implements Connection {
private final static Logger LOGGER = new Logger(RedisConnection.class);
private final RedisClient redisClient;
private final Properties properties;
private String dbIndex;
public RedisConnection(RedisClient redisClient, String dbIndex, Properties properties) {
this.redisClient = redisClient;
this.dbIndex = dbIndex;
this.properties = properties;
}
private boolean isClosed = false;
@Override
public Statement createStatement() throws SQLException {
this.checkClosed();
return new RedisStatement(this, this.redisClient);
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
// TODO 暂不实现感觉意义不大未来看是否需要实现
LOGGER.log("prepareStatement not implemented");
throw new SQLFeatureNotSupportedException("prepareStatement not implemented");
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
// TODO 暂不实现感觉无意义因为主要是执行存储过程的redis没这玩意
LOGGER.log("prepareCall not implemented");
throw new SQLFeatureNotSupportedException("prepareCall not implemented");
}
@Override
public String nativeSQL(String sql) throws SQLException {
LOGGER.log("nativeSQL not implemented");
throw new SQLFeatureNotSupportedException("nativeSQL not implemented");
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
}
@Override
public boolean getAutoCommit() throws SQLException {
return true;
}
@Override
public void commit() throws SQLException {
// TODO 待支持事务
}
@Override
public void rollback() throws SQLException {
// TODO
}
@Override
public void close() throws SQLException {
this.redisClient.close();
LOGGER.log("Connection close");
this.isClosed = true;
}
@Override
public boolean isClosed() throws SQLException {
LOGGER.log("Connection isClosed = %s", isClosed);
return this.isClosed;
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
return new RedisDatabaseMetadata(this, this.dbIndex);
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
// do nothing
}
@Override
public boolean isReadOnly() throws SQLException {
return false;
}
@Override
public void setCatalog(String catalog) throws SQLException {
LOGGER.log("setCatalog(%s)", catalog);
// do nothing
}
@Override
public String getCatalog() throws SQLException {
return null;
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
}
@Override
public int getTransactionIsolation() throws SQLException {
return Connection.TRANSACTION_NONE;
}
@Override
public SQLWarning getWarnings() throws SQLException {
LOGGER.log("getWarnings returns null");
return null;
}
@Override
public void clearWarnings() throws SQLException {
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return this.createStatement();
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return this.prepareStatement(sql);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return this.prepareCall(sql);
}
@Override
public Map<String, Class<?>> getTypeMap() throws SQLException {
LOGGER.log("getTypeMap not implemented");
throw new SQLFeatureNotSupportedException("getTypeMap not implemented");
}
@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
LOGGER.log("setTypeMap not implemented");
throw new SQLFeatureNotSupportedException("setTypeMap not implemented");
}
@Override
public void setHoldability(int holdability) throws SQLException {
// do nothing
}
@Override
public int getHoldability() throws SQLException {
return ResultSet.HOLD_CURSORS_OVER_COMMIT;
}
@Override
public Savepoint setSavepoint() throws SQLException {
LOGGER.log("setSavepoint not implemented");
throw new SQLFeatureNotSupportedException("setSavepoint not implemented");
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
LOGGER.log("setSavepoint not implemented");
throw new SQLFeatureNotSupportedException("setSavepoint not implemented");
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
LOGGER.log("rollback not implemented");
throw new SQLFeatureNotSupportedException("rollback not implemented");
}
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
LOGGER.log("releaseSavepoint not implemented");
throw new SQLFeatureNotSupportedException("releaseSavepoint not implemented");
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return this.createStatement();
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return this.prepareStatement(sql);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
return this.prepareCall(sql);
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
return this.prepareStatement(sql);
}
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
return this.prepareStatement(sql);
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
return this.prepareStatement(sql);
}
@Override
public Clob createClob() throws SQLException {
LOGGER.log("createClob not implemented");
throw new SQLFeatureNotSupportedException("createClob not implemented");
}
@Override
public Blob createBlob() throws SQLException {
LOGGER.log("createBlob not implemented");
throw new SQLFeatureNotSupportedException("createBlob not implemented");
}
@Override
public NClob createNClob() throws SQLException {
LOGGER.log("createNClob not implemented");
throw new SQLFeatureNotSupportedException("createNClob not implemented");
}
@Override
public SQLXML createSQLXML() throws SQLException {
LOGGER.log("createSQLXML not implemented");
throw new SQLFeatureNotSupportedException("createSQLXML not implemented");
}
@Override
public boolean isValid(int timeout) throws SQLException {
LOGGER.log("isValid = %s", isClosed);
if (this.isClosed) {
return false;
}
// TODO 超时时间
try {
this.redisClient.sendCommand("PING");
return true;
} catch (Exception e) {
return false;
}
}
@Override
public void setClientInfo(String name, String value) throws SQLClientInfoException {
this.properties.put(name, value);
}
@Override
public void setClientInfo(Properties properties) throws SQLClientInfoException {
this.properties.putAll(properties);
}
@Override
public String getClientInfo(String name) throws SQLException {
this.checkClosed();
String property = this.properties.getProperty(name);
property = property == null ? "" : property;
LOGGER.log("getClientInfo(%s) = %s, properties = %s", name, property, properties);
return property;
}
@Override
public Properties getClientInfo() throws SQLException {
LOGGER.log("getClientInfo() = %s", properties);
return this.properties;
}
@Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
LOGGER.log("createArrayOf not implemented");
throw new SQLFeatureNotSupportedException("createArrayOf not implemented");
}
@Override
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
LOGGER.log("createStruct not implemented");
throw new SQLFeatureNotSupportedException("createStruct not implemented");
}
@Override
public void setSchema(String schema) throws SQLException {
synchronized (RedisConnection.class) {
LOGGER.log("setSchema(%s)", schema);
this.checkClosed();
this.redisClient.select(Integer.parseInt(schema));
this.dbIndex = schema;
}
}
@Override
public String getSchema() throws SQLException {
synchronized (RedisConnection.class) {
this.checkClosed();
LOGGER.log("getSchema() = %s", this.dbIndex);
return this.dbIndex;
}
}
@Override
public void abort(Executor executor) throws SQLException {
LOGGER.log("abort not implemented");
throw new SQLFeatureNotSupportedException("abort not implemented");
}
@Override
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
LOGGER.log("setNetworkTimeout not implemented");
throw new SQLFeatureNotSupportedException("setNetworkTimeout not implemented");
}
@Override
public int getNetworkTimeout() throws SQLException {
LOGGER.log("getNetworkTimeout not implemented");
throw new SQLFeatureNotSupportedException("getNetworkTimeout not implemented");
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
try {
return iface.cast(this);
} catch (ClassCastException cce) {
LOGGER.log("Unable to unwrap to %s", iface);
throw new SQLException("Unable to unwrap to " + iface);
}
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
this.checkClosed();
return iface.isInstance(this);
}
private void checkClosed() throws SQLException {
if (isClosed()) {
LOGGER.log("Connection is closed.");
throw new SQLException("Connection is closed.");
}
}
}

View File

@ -0,0 +1,133 @@
package io.edurt.datacap.core;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
public class RedisResultSetMetaData implements ResultSetMetaData {
private final static Logger LOGGER = new Logger(RedisResultSetMetaData.class);
public static final int MAX_SIZE = 1024;
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
try {
return iface.cast(this);
} catch (ClassCastException cce) {
LOGGER.log("Unable to unwrap to %s", iface);
throw new SQLException("Unable to unwrap to " + iface);
}
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return iface.isInstance(this);
}
@Override
public int getColumnCount() throws SQLException {
return 1;
}
@Override
public boolean isAutoIncrement(int column) throws SQLException {
return false;
}
@Override
public boolean isCaseSensitive(int column) throws SQLException {
return true;
}
@Override
public boolean isSearchable(int column) throws SQLException {
return false;
}
@Override
public boolean isCurrency(int column) throws SQLException {
return false;
}
@Override
public int isNullable(int column) throws SQLException {
return ResultSetMetaData.columnNoNulls;
}
@Override
public boolean isSigned(int column) throws SQLException {
return false;
}
@Override
public int getColumnDisplaySize(int column) throws SQLException {
return MAX_SIZE;
}
@Override
public String getColumnLabel(int column) throws SQLException {
return "RESULTS";
}
@Override
public String getColumnName(int column) throws SQLException {
return "RESULTS";
}
@Override
public String getSchemaName(int column) throws SQLException {
LOGGER.log("getSchemaName(%s)", column);
return "9";
}
@Override
public int getPrecision(int column) throws SQLException {
return MAX_SIZE;
}
@Override
public int getScale(int column) throws SQLException {
return 0;
}
@Override
public String getTableName(int column) throws SQLException {
return "";
}
@Override
public String getCatalogName(int column) throws SQLException {
return "";
}
@Override
public int getColumnType(int column) throws SQLException {
return Types.NVARCHAR;
}
@Override
public String getColumnTypeName(int column) throws SQLException {
return "String";
}
@Override
public boolean isReadOnly(int column) throws SQLException {
return true;
}
@Override
public boolean isWritable(int column) throws SQLException {
return false;
}
@Override
public boolean isDefinitelyWritable(int column) throws SQLException {
return false;
}
@Override
public String getColumnClassName(int column) throws SQLException {
return "java.lang.String";
}
}

View File

@ -0,0 +1,314 @@
package io.edurt.datacap.core;
import java.sql.*;
public class RedisStatement implements Statement {
private final static Logger LOGGER = new Logger(RedisStatement.class);
private final RedisConnection connection;
private final RedisClient redisClient;
private ResultSet resultSet;
private boolean isClosed = false;
private int fetchSize = 1;
public RedisStatement(RedisConnection connection, RedisClient redisClient) {
this.connection = connection;
this.redisClient = redisClient;
}
@Override
public ResultSet executeQuery(String sql) throws SQLException {
LOGGER.log("executeQuery(%s)", sql);
this.checkClosed();
String[] result = this.redisClient.sendCommand(sql);
return new RedisResultSet(result, this);
}
@Override
public int executeUpdate(String sql) throws SQLException {
this.checkClosed();
String[] result = this.redisClient.sendCommand(sql);
return result.length;
}
@Override
public void close() throws SQLException {
LOGGER.log("close()");
if (isClosed) {
LOGGER.log("Statement has been closed.");
return;
}
if (this.resultSet != null && !this.resultSet.isClosed()) {
this.resultSet.close();
}
isClosed = true;
}
@Override
public int getMaxFieldSize() throws SQLException {
this.checkClosed();
return Integer.MAX_VALUE;
}
@Override
public void setMaxFieldSize(int max) throws SQLException {
this.checkClosed();
// do nothing
}
@Override
public int getMaxRows() throws SQLException {
this.checkClosed();
return 0;
}
@Override
public void setMaxRows(int max) throws SQLException {
this.checkClosed();
// do nothing
}
@Override
public void setEscapeProcessing(boolean enable) throws SQLException {
this.checkClosed();
// do nothing
}
@Override
public int getQueryTimeout() throws SQLException {
this.checkClosed();
return 0;
}
@Override
public void setQueryTimeout(int seconds) throws SQLException {
LOGGER.log("setQueryTimeout..");
}
@Override
public void cancel() throws SQLException {
throw new SQLFeatureNotSupportedException("cancel not implemented");
}
@Override
public SQLWarning getWarnings() throws SQLException {
LOGGER.log("getWarnings returns null");
return null;
}
@Override
public void clearWarnings() throws SQLException {
this.checkClosed();
}
@Override
public void setCursorName(String name) throws SQLException {
LOGGER.log("setCursorName not implemented");
throw new SQLFeatureNotSupportedException("setCursorName not implemented");
}
@Override
public boolean execute(String sql) throws SQLException {
this.checkClosed();
String[] result = this.redisClient.sendCommand(sql);
this.resultSet = new RedisResultSet(result, this);
return true;
}
@Override
public ResultSet getResultSet() throws SQLException {
this.checkClosed();
return this.resultSet;
}
@Override
public int getUpdateCount() throws SQLException {
this.checkClosed();
LOGGER.log("getUpdateCount()");
// 原因在父类
return -1;
}
@Override
public boolean getMoreResults() throws SQLException {
this.checkClosed();
LOGGER.log("getMoreResults()");
return this.getMoreResults(CLOSE_CURRENT_RESULT);
}
@Override
public void setFetchDirection(int direction) throws SQLException {
this.checkClosed();
LOGGER.log("setFetchDirection not implemented");
throw new SQLFeatureNotSupportedException("setFetchDirection not implemented");
}
@Override
public int getFetchDirection() throws SQLException {
this.checkClosed();
return java.sql.ResultSet.FETCH_FORWARD;
}
@Override
public void setFetchSize(int rows) throws SQLException {
this.checkClosed();
this.fetchSize = rows;
}
@Override
public int getFetchSize() throws SQLException {
this.checkClosed();
return this.fetchSize;
}
@Override
public int getResultSetConcurrency() throws SQLException {
this.checkClosed();
return ResultSet.CONCUR_READ_ONLY;
}
@Override
public int getResultSetType() throws SQLException {
this.checkClosed();
return ResultSet.TYPE_FORWARD_ONLY;
}
@Override
public void addBatch(String sql) throws SQLException {
this.checkClosed();
LOGGER.log("addBatch not implemented");
throw new SQLFeatureNotSupportedException("addBatch not implemented");
}
@Override
public void clearBatch() throws SQLException {
this.checkClosed();
LOGGER.log("clearBatch not implemented");
throw new SQLFeatureNotSupportedException("addBatch not implemented");
}
@Override
public int[] executeBatch() throws SQLException {
this.checkClosed();
LOGGER.log("executeBatch not implemented");
throw new SQLFeatureNotSupportedException("executeBatch not implemented");
}
@Override
public Connection getConnection() throws SQLException {
this.checkClosed();
return this.connection;
}
@Override
public boolean getMoreResults(int current) throws SQLException {
this.checkClosed();
LOGGER.log("getMoreResults(%s)", current);
return false;
}
@Override
public ResultSet getGeneratedKeys() throws SQLException {
LOGGER.log("getGeneratedKeys not implemented");
throw new SQLFeatureNotSupportedException("getGeneratedKeys not implemented");
}
@Override
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
this.executeUpdate(sql);
return 0;
}
@Override
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
return this.executeUpdate(sql, 0);
}
@Override
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
return this.executeUpdate(sql, 0);
}
@Override
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
this.executeUpdate(sql);
return true;
}
@Override
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
return this.execute(sql, 0);
}
@Override
public boolean execute(String sql, String[] columnNames) throws SQLException {
return this.execute(sql, 0);
}
@Override
public int getResultSetHoldability() throws SQLException {
this.checkClosed();
return ResultSet.HOLD_CURSORS_OVER_COMMIT;
}
@Override
public boolean isClosed() throws SQLException {
LOGGER.log("Statement isClosed = %s", isClosed);
return this.isClosed;
}
@Override
public void setPoolable(boolean poolable) throws SQLException {
LOGGER.log("setPoolable not implemented");
throw new SQLFeatureNotSupportedException("setPoolable not implemented");
}
@Override
public boolean isPoolable() throws SQLException {
this.checkClosed();
return false;
}
@Override
public void closeOnCompletion() throws SQLException {
this.checkClosed();
LOGGER.log("closeOnCompletion not implemented");
throw new SQLFeatureNotSupportedException("closeOnCompletion not implemented");
}
@Override
public boolean isCloseOnCompletion() throws SQLException {
this.checkClosed();
LOGGER.log("isCloseOnCompletion not implemented");
return false;
}
private void checkClosed() throws SQLException {
if (isClosed()) {
LOGGER.log("Statement is closed.");
throw new SQLException("Statement is closed.");
}
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
try {
return iface.cast(this);
} catch (ClassCastException cce) {
LOGGER.log("Unable to unwrap to %s", iface);
throw new SQLException("Unable to unwrap to " + iface);
}
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return iface.isInstance(this);
}
}

View File

@ -0,0 +1,29 @@
package io.edurt.datacap.core;
import lombok.Data;
@Data
public class ServerVersion {
private String origin;
private Integer major;
private Integer minor;
private Integer patch;
public ServerVersion(String origin) {
this.origin = origin;
String[] arr = origin.split("\\.");
for (int i = 0; i < arr.length; i++) {
String str = arr[i];
int v = Utils.isNumber(str) ? Integer.parseInt(str) : 0;
if (i == 0) {
this.major = v;
} else if (i == 1) {
minor = v;
} else if (i == 2) {
patch = v;
}
}
}
}

View File

@ -0,0 +1,90 @@
package io.edurt.datacap.core;
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.*;
import java.util.stream.Collectors;
public class Utils {
public static boolean isNumber(String str) {
if (str == null || str.length() == 0) {
return false;
}
for (int i = 0; i < str.length(); i++) {
boolean digit = Character.isDigit(str.charAt(i));
if (!digit) {
return false;
}
}
return true;
}
public static <T> List<T> toList(T[] arr) {
if (arr == null) {
return null;
}
return Arrays.stream(arr)
.collect(Collectors.toList());
}
public static Op parseSql(String rawSql) {
// for IDEA database tool only
if (rawSql.contains("SELECT 'keep alive'")) {
return new Op(rawSql, null, "PING", new String[0]);
}
// hints
List<String> lines = new BufferedReader(new StringReader(rawSql))
.lines()
.collect(Collectors.toList());
List<String> hintLines = new ArrayList<>();
List<String> sqlLines = new ArrayList<>();
lines.forEach(line -> {
if (line.startsWith("--")) {
hintLines.add(line);
} else {
sqlLines.add(line);
}
});
List<Hint> hints = hintLines
.stream()
.map(line -> {
String hintStr = line.replace("--", "")
.replaceAll(" ", "");
String[] arr = hintStr.split(":");
return new Hint(HintKey.fromString(arr[0]), arr[1]);
}).collect(Collectors.toList());
// sql to execute
StringBuilder sb = new StringBuilder();
sqlLines.forEach(sb::append);
String sql = sb.toString();
String[] arr = sql.split(" ");
String commandString = arr[0];
if (arr.length == 1) {
return new Op(rawSql, hints, commandString, new String[0]);
} else {
String[] commandParams = Arrays.copyOfRange(arr, 1, arr.length);
return new Op(rawSql, hints, commandString, commandParams);
}
}
public static Map<String, String> parseQueryStringToMap(String queryString) {
String[] params = queryString.split("&");
Map<String, String> map = new HashMap<>();
for (String param : params) {
String[] p = param.split("=");
if (p.length == 2) {
map.put(p[0], p[1]);
}
}
return map;
}
}

View File

@ -0,0 +1,83 @@
package io.edurt.datacap.driver;
import io.edurt.datacap.core.Hint;
import io.edurt.datacap.core.Logger;
import io.edurt.datacap.core.Op;
import io.edurt.datacap.core.RedisClient;
import io.edurt.datacap.core.Utils;
import redis.clients.jedis.Protocol;
import redis.clients.jedis.util.SafeEncoder;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;
public abstract class AbstractRedisClient implements RedisClient
{
public static final Logger LOGGER = new Logger(AbstractRedisClient.class);
@Override
public String[] sendCommand(String sql) throws SQLException {
try {
Op op = Utils.parseSql(sql);
Object result = this.sendCommand(op);
return this.decodeResult(sql, result, op.getHints());
} catch (Throwable e) {
throw new SQLException(e);
}
}
protected abstract Object sendCommand(Op op);
protected Protocol.Command convertCommand(String commandString) {
return Arrays.stream(Protocol.Command.values())
.filter(t -> {
String string = t.toString();
return string.equalsIgnoreCase(commandString);
})
.findFirst()
.orElseThrow(() -> new RuntimeException(
String.format("command invalided. commandString = %s", commandString)
));
}
/**
* hint:
* -- decoder:jdk
* TODO
*
* @param sql
* @param originResult
* @param hints
* @return
*/
protected String[] decodeResult(String sql, Object originResult, List<Hint> hints) {
String[] decodedResult;
if (originResult == null) {
decodedResult = new String[]{null};
} else if (originResult.getClass().isArray()) {
String decoded = SafeEncoder.encode((byte[]) originResult);
decodedResult = Stream.of(decoded)
.toArray(String[]::new);
} else if (originResult instanceof Collection) {
List<?> list = (List<?>) originResult;
decodedResult = list.stream()
.map(t -> SafeEncoder.encode((byte[]) t))
.toArray(String[]::new);
} else {
LOGGER.log("cannot decode result. originResult = %s", originResult);
decodedResult = Stream.of(originResult.toString())
.toArray(String[]::new);
}
LOGGER.log("decode success. sql = %s, originResult = %s, decodedResult = %s",
sql, originResult, Utils.toList(decodedResult));
return decodedResult;
}
}

View File

@ -0,0 +1,56 @@
package io.edurt.datacap.driver.cluster;
import io.edurt.datacap.driver.AbstractRedisClient;
import io.edurt.datacap.core.Hint;
import io.edurt.datacap.core.HintKey;
import io.edurt.datacap.core.Op;
import lombok.RequiredArgsConstructor;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.Protocol;
import java.sql.SQLException;
import java.util.List;
@RequiredArgsConstructor
public class JedisRedisClusterClient extends AbstractRedisClient {
private final JedisCluster jedisCluster;
@Override
protected Object sendCommand(Op op) {
String rawSql = op.getOriginSql();
String commandString = op.getCommand();
String[] params = op.getParams();
List<Hint> hints = op.getHints();
try {
Protocol.Command command = this.convertCommand(commandString);
String sampleKey = hints.stream()
.filter(hint -> hint.getKey().equals(HintKey.sample_key))
.findFirst()
.map(Hint::getValue)
.orElse(null);
Object result;
if (params == null || params.length == 0) {
result = this.jedisCluster.sendCommand(sampleKey, command);
} else {
result = this.jedisCluster.sendCommand(sampleKey, command, params);
}
return result;
} catch (Throwable e) {
LOGGER.log("command `%s` cannot execute.", rawSql);
throw new RuntimeException(String.format("command `%s` cannot execute.", rawSql));
}
}
@Override
public void select(int dbIndex) throws SQLException {
throw new SQLException("Redis Cluster does not support this operation");
}
@Override
public void close() {
this.jedisCluster.close();
}
}

View File

@ -0,0 +1,91 @@
package io.edurt.datacap.driver.cluster;
import io.edurt.datacap.core.Logger;
import io.edurt.datacap.core.RedisConnection;
import io.edurt.datacap.driver.conf.RedisClusterConnectionInfo;
import io.edurt.datacap.driver.redis.RedisDriver;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.JedisCluster;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.*;
import java.util.Properties;
public class RedisClusterDriver implements Driver {
private final static Logger LOGGER = new Logger(RedisDriver.class);
private static final String REDIS_CLUSTER_JDBC_PREFIX = "jdbc:redis-cluster:";
static {
try {
DriverManager.registerDriver(new RedisClusterDriver());
} catch (Exception e) {
LOGGER.log("Can't register driver!");
throw new RuntimeException("Can't register driver!", e);
}
}
@Override
public Connection connect(String url, Properties info) throws SQLException {
if (!this.acceptsURL(url)) {
LOGGER.log("wrong url. url is %s", url);
return null;
}
if (info == null) {
info = new Properties();
}
String rawUrl = url.replaceFirst("jdbc:", "");
RedisClusterConnectionInfo connectionInfo = new RedisClusterConnectionInfo(rawUrl, info);
JedisCluster jedisCluster = new JedisCluster(
connectionInfo.getNodes(),
connectionInfo.getTimeout(),
connectionInfo.getTimeout(),
connectionInfo.getMaxAttempts(),
connectionInfo.getUsername(),
connectionInfo.getPassword(),
null,
new GenericObjectPoolConfig<>()
);
JedisRedisClusterClient jedisRedisClusterClient = new JedisRedisClusterClient(jedisCluster);
return new RedisConnection(jedisRedisClusterClient, "0", info);
}
@Override
public boolean acceptsURL(String url) throws SQLException {
return url.toLowerCase().startsWith(REDIS_CLUSTER_JDBC_PREFIX);
}
@Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
return new DriverPropertyInfo[0];
}
@Override
public int getMajorVersion() {
return 0;
}
@Override
public int getMinorVersion() {
return 0;
}
@Override
public boolean jdbcCompliant() {
return false;
}
@Override
public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
public static void main(String[] args) throws URISyntaxException {
URI uri = new URI("cluster:///?hosts=localhost:3306");
System.out.println(uri.getQuery());
}
}

View File

@ -0,0 +1,29 @@
package io.edurt.datacap.driver.conf;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Properties;
@Data
@NoArgsConstructor
public class BaseConnectionInfo {
protected String username;
protected String password;
protected boolean ssl;
protected int timeout;
public BaseConnectionInfo(Properties info) {
String username = info.getProperty("user");
String password = info.getProperty("password");
String sslString = info.getProperty("ssl");
Object timeoutString = info.getOrDefault("timeout", "1000");
boolean ssl = "on".equalsIgnoreCase(sslString) || "true".equalsIgnoreCase(sslString);
this.username = username;
this.password = password;
this.timeout = Integer.parseInt(timeoutString.toString());
this.ssl = ssl;
}
}

View File

@ -0,0 +1,51 @@
package io.edurt.datacap.driver.conf;
import io.edurt.datacap.core.Logger;
import io.edurt.datacap.core.Utils;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import java.net.URI;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class RedisClusterConnectionInfo extends BaseConnectionInfo {
public static final Logger LOGGER = new Logger(RedisClusterConnectionInfo.class);
private Set<HostAndPort> nodes;
private int maxAttempts;
public RedisClusterConnectionInfo(String rawUrl, Properties info) {
super((info));
try {
URI uri = new URI(rawUrl);
Object maxAttemptsString = info.getOrDefault("maxAttempts", JedisCluster.DEFAULT_MAX_ATTEMPTS);
int maxAttempts = Integer.parseInt(maxAttemptsString.toString());
String query = uri.getQuery();
Map<String, String> paramMap = Utils.parseQueryStringToMap(query);
String host = paramMap.get("host");
String[] hosts = host.split(";");
this.nodes = Arrays.stream(hosts)
.map(h -> {
String[] split = h.split(":");
return new HostAndPort(split[0], Integer.parseInt(split[1]));
}).collect(Collectors.toSet());
this.maxAttempts = maxAttempts;
} catch (Exception e) {
LOGGER.log("Cannot parse JDBC URL %s", rawUrl);
throw new RuntimeException("Cannot parse JDBC URL: " + rawUrl, e);
}
}
}

View File

@ -0,0 +1,41 @@
package io.edurt.datacap.driver.conf;
import io.edurt.datacap.core.Logger;
import lombok.*;
import java.net.URI;
import java.util.Properties;
@Data
@EqualsAndHashCode(callSuper = true)
public class RedisConnectionInfo extends BaseConnectionInfo {
private final static Logger LOGGER = new Logger(RedisConnectionInfo.class);
private String host;
private int port;
private int dbIndex;
public RedisConnectionInfo(String rawUrl, Properties info) {
super(info);
try {
URI uri = new URI(rawUrl);
String host = uri.getHost() != null ? uri.getHost() : "localhost";
int port = uri.getPort() > 0 ? uri.getPort() : 6379;
String path = uri.getPath();
int dbIndex = 0;
if (path != null && path.length() > 1) {
dbIndex = Integer.parseInt(path.replaceAll("/", ""));
}
this.host = host;
this.port = port;
this.dbIndex = dbIndex;
} catch (Exception e) {
LOGGER.log("Cannot parse JDBC URL %s", rawUrl);
throw new RuntimeException("Cannot parse JDBC URL: " + rawUrl, e);
}
}
}

View File

@ -0,0 +1,52 @@
package io.edurt.datacap.driver.redis;
import io.edurt.datacap.driver.AbstractRedisClient;
import io.edurt.datacap.core.Logger;
import io.edurt.datacap.core.Op;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Protocol;
public class JedisRedisClient extends AbstractRedisClient {
public static final Logger LOGGER = new Logger(JedisRedisClient.class);
private final Jedis jedis;
public JedisRedisClient(Jedis jedis) {
this.jedis = jedis;
}
@Override
protected synchronized Object sendCommand(Op op) {
String rawSql = op.getOriginSql();
String commandString = op.getCommand();
String[] params = op.getParams();
int db = -1;
try {
db = jedis.getDB();
Protocol.Command command = this.convertCommand(commandString);
Object result;
if (params == null || params.length == 0) {
result = this.jedis.sendCommand(command);
} else {
result = this.jedis.sendCommand(command, params);
}
return result;
} catch (Throwable e) {
LOGGER.log("command on db %s `%s` cannot execute.", db, rawSql);
throw new RuntimeException(String.format("command on db %s `%s` cannot execute.", db, rawSql));
}
}
@Override
public synchronized void select(int dbIndex) {
this.jedis.select(dbIndex);
}
@Override
public synchronized void close() {
LOGGER.log("close()");
this.jedis.close();
}
}

View File

@ -0,0 +1,100 @@
package io.edurt.datacap.driver.redis;
import io.edurt.datacap.core.Logger;
import io.edurt.datacap.core.RedisConnection;
import io.edurt.datacap.driver.conf.RedisConnectionInfo;
import redis.clients.jedis.Jedis;
import java.sql.*;
import java.util.Properties;
public class RedisDriver implements Driver {
private final static Logger LOGGER = new Logger(RedisDriver.class);
private static final String REDIS_JDBC_PREFIX = "jdbc:redis:";
static {
try {
DriverManager.registerDriver(new RedisDriver());
} catch (Exception e) {
LOGGER.log("Can't register driver!");
throw new RuntimeException("Can't register driver!", e);
}
}
@Override
public Connection connect(String url, Properties info) throws SQLException {
if (!this.acceptsURL(url)) {
LOGGER.log("wrong url. url is %s", url);
return null;
}
if (info == null) {
info = new Properties();
}
String rawUrl = url.replaceFirst("jdbc:", "");
RedisConnectionInfo redisConnectionInfo = new RedisConnectionInfo(rawUrl, info);
String host = redisConnectionInfo.getHost();
int port = redisConnectionInfo.getPort();
int dbIndex = redisConnectionInfo.getDbIndex();
int timeout = redisConnectionInfo.getTimeout();
boolean ssl = redisConnectionInfo.isSsl();
String username = redisConnectionInfo.getUsername();
String password = redisConnectionInfo.getPassword();
try {
final Jedis jedis = new Jedis(host, port, timeout, timeout, ssl);
jedis.connect();
if (username != null) {
jedis.auth(username, password);
} else if (password != null) {
jedis.auth(password);
}
if (dbIndex != 0) {
jedis.select(dbIndex);
}
// if (clientName != null) {
// jedis.clientSetname(clientName);
// }
return new RedisConnection(new JedisRedisClient(jedis), dbIndex + "", info);
} catch (Exception e) {
LOGGER.log("Cannot init RedisConnection %s", e);
throw new SQLException("Cannot init RedisConnection", e);
}
}
@Override
public boolean acceptsURL(String url) throws SQLException {
return url.toLowerCase().startsWith(REDIS_JDBC_PREFIX);
}
@Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
return new DriverPropertyInfo[0];
}
@Override
public int getMajorVersion() {
return 1;
}
@Override
public int getMinorVersion() {
return 0;
}
@Override
public boolean jdbcCompliant() {
return false;
}
@Override
public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
// ref: com.mysql.cj.jdbc.NonRegisteringDriver.getParentLogger
LOGGER.log("getParentLogger not implemented");
throw new SQLFeatureNotSupportedException("getParentLogger not implemented");
}
}

View File

@ -0,0 +1,2 @@
io.edurt.datacap.driver.redis.RedisDriver
io.edurt.datacap.driver.cluster.RedisClusterDriver

View File

@ -0,0 +1,82 @@
package io.edurt.datacap;
import io.edurt.datacap.core.Logger;
import io.edurt.datacap.core.RedisStatement;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.sql.*;
public class RedisTest {
private final static Logger LOGGER = new Logger(RedisStatement.class);
public static void main(String[] args) throws SQLException, ClassNotFoundException {
Class.forName("com.itmuch.redis.jdbc.redis.RedisDriver");
Connection connection = DriverManager.getConnection("jdbc:redis://localhost:6379/0");
Statement statement = connection.createStatement();
connection.setSchema("11");
ResultSet rs = statement.executeQuery("get a");
while (rs.next()) {
String string = rs.getString(0);
System.out.println(string);
}
// statement.execute("set a b");
// ResultSet rs = statement.executeQuery("get a");
// while (rs.next()) {
// LOGGER.log("rs1:" + rs.getString(0));
// }
//
ResultSet resultSet = statement.executeQuery("keys *");
while (resultSet.next()) {
LOGGER.log(resultSet.getString(0));
}
connection.setSchema("11");
ResultSet resultSet2 = statement.executeQuery("set ab99 ab88");
while (resultSet2.next()) {
LOGGER.log(resultSet.getString(0));
}
resultSet.close();
statement.close();
connection.close();
// statement.execute("ZADD runoobkey 2 mongodb");
// statement.execute("ZADD runoobkey 3 elasticsearch");
// statement.execute("ZADD runoobkey 4 mysql");
//
// ResultSet rs2 = statement.executeQuery("ZRANGE runoobkey 0 10 WITHSCORES");
// while (rs2.next()) {
// LOGGER.log("rs2:" + rs2.getString(0));
// }
//
// statement.execute("HMSET myhash field1 field2");
// ResultSet rs3 = statement.executeQuery("HGETALL myhash");
// while (rs3.next()) {
// LOGGER.log("rs3:" + rs3.getString(0));
// }
// ResultSet rs4 = statement.executeQuery("get user");
// while (rs4.next()) {
// LOGGER.log("rs4:" + rs4.getString(0));
// }
}
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
class User {
private String name;
private Short age;
private String email;
private BigDecimal money;
}

View File

@ -14,7 +14,6 @@
<description>DataCap - Redis</description>
<properties>
<redis-jdbc.version>0.0.1</redis-jdbc.version>
<plugin.name>jdbc-redis</plugin.name>
</properties>
@ -25,13 +24,13 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-driver-redis</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.itmuch.redis</groupId>
<artifactId>redis-jdbc-driver</artifactId>
<version>${redis-jdbc.version}</version>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
</dependencies>

View File

@ -50,7 +50,7 @@ public class RedisPlugin
this.response = new Response();
this.jdbcConfigure = new JdbcConfigure();
BeanUtils.copyProperties(this.jdbcConfigure, configure);
this.jdbcConfigure.setJdbcDriver("com.itmuch.redis.jdbc.redis.RedisDriver");
this.jdbcConfigure.setJdbcDriver("io.edurt.datacap.driver.redis.RedisDriver");
this.jdbcConfigure.setJdbcType("redis");
this.jdbcConfigure.setUsername(configure.getUsername().map(u -> "".equals(u) ? null : u));
this.jdbcConfigure.setPassword(configure.getPassword().map(pwd -> "".equals(pwd) ? null : pwd));

View File

@ -49,6 +49,7 @@
<module>plugin/datacap-jdbc-sqlserver</module>
<module>plugin/datacap-jdbc-tdengine</module>
<module>plugin/datacap-jdbc-trino</module>
<module>driver/datacap-driver-redis</module>
</modules>
<name>DataCap</name>
@ -107,6 +108,7 @@
<sql-formatter.version>2.0.3</sql-formatter.version>
<guava.version>31.1-jre</guava.version>
<commons-beanutils.version>1.9.4</commons-beanutils.version>
<redis.version>4.3.1</redis.version>
<assembly-plugin.version>3.1.1</assembly-plugin.version>
<plugin.maven.checkstyle.version>3.0.0</plugin.maven.checkstyle.version>
<plugin.maven.findbugs.version>3.0.5</plugin.maven.findbugs.version>
@ -211,6 +213,11 @@
<artifactId>datacap-parser</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.edurt.datacap</groupId>
<artifactId>datacap-driver-redis</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>