diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/factory/MysqlValueProcessorFactory.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/factory/MysqlValueProcessorFactory.java index fe9601c4..94367e9a 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/factory/MysqlValueProcessorFactory.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/factory/MysqlValueProcessorFactory.java @@ -45,7 +45,6 @@ public class MysqlValueProcessorFactory { Map.entry(MysqlColumnTypeEnum.DATETIME.name(), mysqlTimestampProcessor), //others Map.entry(MysqlColumnTypeEnum.BIT.name(), new MysqlBitProcessor()), - Map.entry(MysqlColumnTypeEnum.YEAR.name(), new MysqlYearProcessor()), Map.entry(MysqlColumnTypeEnum.DECIMAL.name(), new MysqlDecimalProcessor()), Map.entry(MysqlColumnTypeEnum.BINARY.name(), new MysqlBinaryProcessor()) ); diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlBinaryProcessor.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlBinaryProcessor.java index d35edc70..7e41d21d 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlBinaryProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlBinaryProcessor.java @@ -1,5 +1,6 @@ package ai.chat2db.plugin.mysql.value.sub; +import ai.chat2db.plugin.mysql.value.template.MysqlDmlValueTemplate; import ai.chat2db.spi.jdbc.DefaultValueProcessor; import ai.chat2db.spi.model.JDBCDataValue; import ai.chat2db.spi.model.SQLDataValue; @@ -12,18 +13,28 @@ public class MysqlBinaryProcessor extends DefaultValueProcessor { @Override public String convertSQLValueByType(SQLDataValue dataValue) { - return dataValue.getBlobHexString(); + String value = dataValue.getValue(); + if (value.startsWith("0x")) { + return value; + } + return MysqlDmlValueTemplate.wrapHex(dataValue.getBlobHexString()); } @Override public String convertJDBCValueByType(JDBCDataValue dataValue) { - return dataValue.getBlobHexString(); + byte[] bytes = dataValue.getBytes(); + if (bytes.length == 1) { + if (bytes[0] >= 32 && bytes[0] <= 126) { + return new String(bytes); + } + } + return MysqlDmlValueTemplate.wrapHex(dataValue.getBlobHexString()); } @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return dataValue.getBlobHexString(); + return MysqlDmlValueTemplate.wrapHex(dataValue.getBlobHexString()); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlBitProcessor.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlBitProcessor.java index 238796e4..568d93df 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlBitProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlBitProcessor.java @@ -8,6 +8,7 @@ import ai.chat2db.spi.model.SQLDataValue; import org.apache.commons.lang3.StringUtils; import java.util.Objects; +import java.util.function.Function; /** * @author: zgq @@ -23,23 +24,16 @@ public class MysqlBitProcessor extends DefaultValueProcessor { @Override public String convertJDBCValueByType(JDBCDataValue dataValue) { - int precision = dataValue.getPrecision(); - byte[] bytes = dataValue.getBytes(); - if (precision == 1) { - //bit(1) [1 -> true] [0 -> false] - if (bytes.length == 1 && (bytes[0] == 0 || bytes[0] == 1)) { - return String.valueOf(dataValue.getBoolean()); - } - // tinyint(1) - return String.valueOf(dataValue.getInt()); - } - //bit(m) m: 1~64 - return EasyStringUtils.getBitString(bytes, precision); + return getValue(dataValue, s -> s); } @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { + return getValue(dataValue, this::wrap); + } + + private String getValue(JDBCDataValue dataValue, Function function) { int precision = dataValue.getPrecision(); byte[] bytes = dataValue.getBytes(); if (precision == 1) { @@ -51,7 +45,7 @@ public class MysqlBitProcessor extends DefaultValueProcessor { return String.valueOf(dataValue.getInt()); } //bit(m) m: 2~64 - return wrap(EasyStringUtils.getBitString(bytes, precision)); + return function.apply(EasyStringUtils.getBitString(bytes, precision)); } public String getString(String value) { @@ -65,10 +59,10 @@ public class MysqlBitProcessor extends DefaultValueProcessor { if (StringUtils.isBlank(value)) { return "NULL"; } - return wrap(value); + return MysqlDmlValueTemplate.wrapBit(value); } private String wrap(String value) { - return String.format(MysqlDmlValueTemplate.BIT_TEMPLATE, value); + return MysqlDmlValueTemplate.wrapBit(value); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlDecimalProcessor.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlDecimalProcessor.java index 781fc863..2ee2f3d4 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlDecimalProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlDecimalProcessor.java @@ -12,7 +12,7 @@ public class MysqlDecimalProcessor extends DefaultValueProcessor { @Override public String convertSQLValueByType(SQLDataValue dataValue) { - return super.convertSQLValueByType(dataValue); + return dataValue.getValue(); } @@ -24,6 +24,6 @@ public class MysqlDecimalProcessor extends DefaultValueProcessor { @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return convertJDBCValueByType(dataValue); + return dataValue.getBigDecimalString(); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlGeometryProcessor.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlGeometryProcessor.java index 76f05f98..452d0976 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlGeometryProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlGeometryProcessor.java @@ -6,6 +6,8 @@ import ai.chat2db.spi.model.JDBCDataValue; import ai.chat2db.spi.model.SQLDataValue; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.io.WKBReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.ByteArrayOutputStream; import java.io.InputStream; @@ -17,9 +19,11 @@ import java.io.InputStream; public class MysqlGeometryProcessor extends DefaultValueProcessor { + private static final Logger log = LoggerFactory.getLogger(MysqlGeometryProcessor.class); + @Override public String convertSQLValueByType(SQLDataValue dataValue) { - return wrap(dataValue.getValue()); + return MysqlDmlValueTemplate.wrapGeometry(dataValue.getValue()); } @Override @@ -75,18 +79,15 @@ public class MysqlGeometryProcessor extends DefaultValueProcessor { } return dbGeometry != null ? dbGeometry.toString() : null; } catch (Exception e) { - return super.getJdbcValue(dataValue); + log.warn("Error converting database geometry", e); + return dataValue.getStringValue(); } } @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return wrap(convertJDBCValueByType(dataValue)); - } - - private String wrap(String value) { - return String.format(MysqlDmlValueTemplate.GEOMETRY_TEMPLATE, value); + return MysqlDmlValueTemplate.wrapGeometry(convertJDBCValueByType(dataValue)); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlTextProcessor.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlTextProcessor.java index 2aabdf2f..ff1ed2db 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlTextProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlTextProcessor.java @@ -4,11 +4,8 @@ import ai.chat2db.server.tools.common.util.EasyStringUtils; import ai.chat2db.spi.jdbc.DefaultValueProcessor; import ai.chat2db.spi.model.JDBCDataValue; import ai.chat2db.spi.model.SQLDataValue; -import ai.chat2db.spi.sql.Chat2DBContext; import lombok.extern.slf4j.Slf4j; -import java.util.function.Function; - /** * @author: zgq * @date: 2024年06月05日 0:11 @@ -19,31 +16,19 @@ public class MysqlTextProcessor extends DefaultValueProcessor { @Override public String convertSQLValueByType(SQLDataValue dataValue) { - return wrap(dataValue.getValue()); + return EasyStringUtils.escapeAndQuoteString(dataValue.getValue()); } @Override public String convertJDBCValueByType(JDBCDataValue dataValue) { - return getClobString(dataValue, super::convertJDBCValueByType); + return dataValue.getClobString(); } @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return wrap(getClobString(dataValue, super::convertJDBCValueStrByType)); + return EasyStringUtils.escapeAndQuoteString(dataValue.getClobString()); } - private String getClobString(JDBCDataValue dataValue, Function function) { - try { - return dataValue.getClobString(); - } catch (Exception e) { - log.warn("convertJDBCValue error database: {} , error dataType: {} ", - Chat2DBContext.getDBConfig().getDbType(), dataValue.getType(), e); - return function.apply(dataValue); - } - } - private String wrap(String value) { - return EasyStringUtils.escapeAndQuoteString(value); - } } diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlTimestampProcessor.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlTimestampProcessor.java index 93f0897f..560068d9 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlTimestampProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlTimestampProcessor.java @@ -1,6 +1,6 @@ package ai.chat2db.plugin.mysql.value.sub; -import ai.chat2db.plugin.mysql.value.template.MysqlDmlValueTemplate; +import ai.chat2db.server.tools.common.util.EasyStringUtils; import ai.chat2db.spi.jdbc.DefaultValueProcessor; import ai.chat2db.spi.model.JDBCDataValue; import ai.chat2db.spi.model.SQLDataValue; @@ -13,28 +13,18 @@ public class MysqlTimestampProcessor extends DefaultValueProcessor { @Override public String convertSQLValueByType(SQLDataValue dataValue) { - return super.convertSQLValueByType(dataValue); + return dataValue.getValue(); } @Override public String convertJDBCValueByType(JDBCDataValue dataValue) { - return isValidTimestamp(dataValue) ? new String(dataValue.getBytes()) : "0000-00-00 00:00:00"; + return new String(dataValue.getBytes()); } - protected boolean isValidTimestamp(JDBCDataValue data) { - byte[] buffer = data.getBytes(); - String stringValue = new String(buffer); - return stringValue.length() <= 0 - || stringValue.charAt(0) != '0' - || !"0000-00-00".equals(stringValue) - && !"0000-00-00 00:00:00".equals(stringValue) - && !"00000000000000".equals(stringValue) - && !"0".equals(stringValue); - } @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return String.format(MysqlDmlValueTemplate.COMMON_TEMPLATE, convertJDBCValueByType(dataValue)); + return EasyStringUtils.quoteString(new String(dataValue.getBytes())); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlVarBinaryProcessor.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlVarBinaryProcessor.java index bff92115..71b689ac 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlVarBinaryProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlVarBinaryProcessor.java @@ -1,10 +1,9 @@ package ai.chat2db.plugin.mysql.value.sub; +import ai.chat2db.plugin.mysql.value.template.MysqlDmlValueTemplate; import ai.chat2db.spi.jdbc.DefaultValueProcessor; import ai.chat2db.spi.model.JDBCDataValue; import ai.chat2db.spi.model.SQLDataValue; -import ai.chat2db.spi.sql.Chat2DBContext; -import ch.qos.logback.core.model.processor.DefaultProcessor; import lombok.extern.slf4j.Slf4j; /** @@ -16,26 +15,24 @@ public class MysqlVarBinaryProcessor extends DefaultValueProcessor { @Override public String convertSQLValueByType(SQLDataValue dataValue) { - // TODO: insert file - return super.convertSQLValueByType(dataValue); + String value = dataValue.getValue(); + if (value.startsWith("0x")) { + return value; + } + return MysqlDmlValueTemplate.wrapHex(dataValue.getBlobHexString()); } @Override public String convertJDBCValueByType(JDBCDataValue dataValue) { - try { - return dataValue.getBlobString(); - } catch (Exception e) { - log.warn("convertJDBCValue error database: {} , error dataType: {} ", - Chat2DBContext.getDBConfig().getDbType(), dataValue.getType(), e); - return super.convertJDBCValueByType(dataValue); - } + return dataValue.getBlobString(); } @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return dataValue.getBlobHexString(); + return MysqlDmlValueTemplate.wrapHex(dataValue.getBlobHexString()); } + } diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlYearProcessor.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlYearProcessor.java deleted file mode 100644 index db9f7831..00000000 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/sub/MysqlYearProcessor.java +++ /dev/null @@ -1,62 +0,0 @@ -package ai.chat2db.plugin.mysql.value.sub; - -import ai.chat2db.spi.jdbc.DefaultValueProcessor; -import ai.chat2db.spi.model.JDBCDataValue; -import ai.chat2db.spi.model.SQLDataValue; - -import java.sql.Date; -import java.util.Calendar; - -/** - * 功能描述 - * - * @author: zgq - * @date: 2024年06月01日 12:57 - */ -public class MysqlYearProcessor extends DefaultValueProcessor { - - @Override - public String convertSQLValueByType(SQLDataValue dataValue) { - return dataValue.getValue(); - } - - - @Override - public String convertJDBCValueByType(JDBCDataValue dataValue) { - Date date = dataValue.getDate(); - if (!isValidYear(dataValue)) { - return "0000"; - } - Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - int year = calendar.get(Calendar.YEAR); - String yStr; - String yZerosPadding = "0000"; - if (year < 1000) { - yStr = "" + year; - yStr = yZerosPadding.substring(0, (4 - yStr.length())) + yStr; - } else { - yStr = "" + year; - } - return yStr; - } - - private boolean isValidYear(JDBCDataValue data) { - byte[] buffer = data.getBytes(); - String stringValue = new String(buffer); - return stringValue.length() <= 0 - || stringValue.charAt(0) != '0' - || !"0000-00-00".equals(stringValue) - && !"0000-00-00 00:00:00".equals(stringValue) - && !"00000000000000".equals(stringValue) - && !"0".equals(stringValue) - && !"00000000".equals(stringValue) - && !"0000".equals(stringValue); - } - - - @Override - public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return getJdbcValue(dataValue); - } -} diff --git a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/template/MysqlDmlValueTemplate.java b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/template/MysqlDmlValueTemplate.java index f3547f62..c43f82be 100644 --- a/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/template/MysqlDmlValueTemplate.java +++ b/chat2db-server/chat2db-plugins/chat2db-mysql/src/main/java/ai/chat2db/plugin/mysql/value/template/MysqlDmlValueTemplate.java @@ -6,7 +6,20 @@ package ai.chat2db.plugin.mysql.value.template; */ public class MysqlDmlValueTemplate { - public static final String COMMON_TEMPLATE = "'%s'"; public static final String GEOMETRY_TEMPLATE = "ST_GeomFromText('%s')"; public static final String BIT_TEMPLATE = "b'%s'"; + public static final String HEX_TEMPLATE = "0x%s"; + + + public static String wrapGeometry(String value) { + return String.format(GEOMETRY_TEMPLATE, value); + } + + public static String wrapBit(String value) { + return String.format(BIT_TEMPLATE, value); + } + + public static String wrapHex(String value) { + return String.format(HEX_TEMPLATE, value); + } } diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/oracle.json b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/oracle.json index adb455ed..a16db8c1 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/oracle.json +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/oracle.json @@ -8,10 +8,12 @@ "custom": false, "defaultDriver": true, "downloadJdbcDriverUrls": [ - "https://cdn.chat2db-ai.com/lib/ojdbc8-19.3.0.0.jar", - "https://cdn.chat2db-ai.com/lib/orai18n-19.3.0.0.jar" + "https://cdn.chat2db-ai.com/lib/ojdbc11-21.5.0.0.jar", + "https://cdn.chat2db-ai.com/lib/orai18n-21.5.0.0.jar", + "https://cdn.chat2db-ai.com/lib/xmlparserv2-21.5.0.0.jar", + "https://cdn.chat2db-ai.com/lib/xdb-21.5.0.0.jar" ], - "jdbcDriver": "ojdbc8-19.3.0.0.jar,orai18n-19.3.0.0.jar", + "jdbcDriver": "ojdbc11-21.5.0.0.jar,orai18n-21.5.0.0.jar,xmlparserv2-21.5.0.0.jar,xdb-21.5.0.0.jar", "jdbcDriverClass": "oracle.jdbc.driver.OracleDriver" } ], diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/OracleValueProcessor.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/OracleValueProcessor.java index 9f1c2e27..495333b4 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/OracleValueProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/OracleValueProcessor.java @@ -21,7 +21,7 @@ public class OracleValueProcessor extends DefaultValueProcessor { @Override public String convertJDBCValueByType(JDBCDataValue dataValue) { String type = dataValue.getType(); - return OracleValueProcessorFactory.getValueProcessor(dataValue.getType()).convertJDBCValueByType(dataValue); + return OracleValueProcessorFactory.getValueProcessor(type).convertJDBCValueByType(dataValue); } diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/factory/OracleValueProcessorFactory.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/factory/OracleValueProcessorFactory.java index 2a545ce0..2cd16da3 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/factory/OracleValueProcessorFactory.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/factory/OracleValueProcessorFactory.java @@ -9,7 +9,7 @@ import java.util.Map; /** * @author: zgq * @date: 2024年06月03日 23:21 - */ // TODO: 1.空间数据类型 2.XML数据类型 3.动态类型数据 4.ANSI、DB2 和 SQL/DS 数据 + */ // TODO: 1.空间数据类型 2.动态类型数据 public class OracleValueProcessorFactory { private static final Map PROCESSOR_MAP; @@ -17,6 +17,8 @@ public class OracleValueProcessorFactory { static { OracleClobProcessor oracleClobProcessor = new OracleClobProcessor(); OracleTimeStampProcessor oracleTimeStampProcessor = new OracleTimeStampProcessor(); + OracleBlobProcessor oracleBlobProcessor = new OracleBlobProcessor(); + OracleRawValueProcessor oracleRawValueProcessor = new OracleRawValueProcessor(); PROCESSOR_MAP = Map.ofEntries( //clob Map.entry(OracleColumnTypeEnum.CLOB.name(), oracleClobProcessor), @@ -34,14 +36,18 @@ public class OracleValueProcessorFactory { //number Map.entry(OracleColumnTypeEnum.NUMBER.name(), new OracleNumberProcessor()), //blob - Map.entry(OracleColumnTypeEnum.BLOB.name(), new OracleBlobProcessor()) + Map.entry(OracleColumnTypeEnum.BLOB.name(), oracleBlobProcessor), + //raw + Map.entry(OracleColumnTypeEnum.RAW.name(), oracleRawValueProcessor), + Map.entry(OracleColumnTypeEnum.LONG_RAW.getColumnType().getTypeName(), oracleRawValueProcessor), + //xml + Map.entry("SYS.XMLTYPE", new OracleXmlValueProcessor()) ); } public static DefaultValueProcessor getValueProcessor(String type) { - DefaultValueProcessor processor = PROCESSOR_MAP.get(type); - return processor == null ? new DefaultValueProcessor() : processor; + return PROCESSOR_MAP.getOrDefault(type, new DefaultValueProcessor()); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleBlobProcessor.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleBlobProcessor.java index e246fdb8..63b3b54e 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleBlobProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleBlobProcessor.java @@ -1,9 +1,9 @@ package ai.chat2db.plugin.oracle.value.sub; +import ai.chat2db.server.tools.common.util.EasyStringUtils; import ai.chat2db.spi.jdbc.DefaultValueProcessor; import ai.chat2db.spi.model.JDBCDataValue; import ai.chat2db.spi.model.SQLDataValue; -import ai.chat2db.spi.sql.Chat2DBContext; import lombok.extern.slf4j.Slf4j; /** @@ -15,24 +15,17 @@ public class OracleBlobProcessor extends DefaultValueProcessor { @Override public String convertSQLValueByType(SQLDataValue dataValue) { - return dataValue.getBlobHexString(); + return EasyStringUtils.quoteString(dataValue.getBlobHexString()); } @Override public String convertJDBCValueByType(JDBCDataValue dataValue) { - try { - return dataValue.getBlobString(); - } catch (Exception e) { - log.warn("convertJDBCValueByType error database: {} , error dataType: {} ", - Chat2DBContext.getDBConfig().getDbType(), dataValue.getType(), e); - return super.convertJDBCValueByType(dataValue); - } - + return dataValue.getBlobString(); } @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return dataValue.getBlobHexString(); + return EasyStringUtils.quoteString(dataValue.getBlobHexString()); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleClobProcessor.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleClobProcessor.java index 1409efd5..9773e6b6 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleClobProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleClobProcessor.java @@ -13,7 +13,7 @@ public class OracleClobProcessor extends DefaultValueProcessor { @Override public String convertSQLValueByType(SQLDataValue dataValue) { - return wrap(dataValue.getValue()); + return EasyStringUtils.escapeAndQuoteString(dataValue.getValue()); } @@ -25,10 +25,6 @@ public class OracleClobProcessor extends DefaultValueProcessor { @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return wrap(dataValue.getClobString()); - } - - private String wrap(String value) { - return EasyStringUtils.escapeAndQuoteString(value); + return EasyStringUtils.escapeAndQuoteString(dataValue.getClobString()); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleDateProcessor.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleDateProcessor.java index c807fa67..7507e6bd 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleDateProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleDateProcessor.java @@ -21,7 +21,7 @@ public class OracleDateProcessor extends DefaultValueProcessor { */ @Override public String convertSQLValueByType(SQLDataValue dataValue) { - return wrap(dataValue.getValue()); + return OracleDmlValueTemplate.wrapDate(dataValue.getValue()); } /** @@ -41,16 +41,9 @@ public class OracleDateProcessor extends DefaultValueProcessor { } - /** - * @param dataValue - * @return - */ + @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return wrap(convertJDBCValueByType(dataValue)); - } - - private String wrap(String value) { - return String.format(OracleDmlValueTemplate.DATE_TEMPLATE, value); + return OracleDmlValueTemplate.wrapDate(convertJDBCValueByType(dataValue)); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleIntervalDSProcessor.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleIntervalDSProcessor.java index 11b619b0..717cea5d 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleIntervalDSProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleIntervalDSProcessor.java @@ -14,22 +14,19 @@ public class OracleIntervalDSProcessor extends DefaultValueProcessor { @Override public String convertSQLValueByType(SQLDataValue dataValue) { - return wrap(dataValue.getValue(), dataValue.getPrecision(), dataValue.getScale()); + return OracleDmlValueTemplate.wrapIntervalDayToSecond(dataValue.getValue(), dataValue.getPrecision(), dataValue.getScale()); } @Override public String convertJDBCValueByType(JDBCDataValue dataValue) { - return super.convertJDBCValueByType(dataValue); + return dataValue.getStringValue(); } @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return wrap(convertJDBCValueByType(dataValue), dataValue.getPrecision(), dataValue.getScale()); + return OracleDmlValueTemplate.wrapIntervalDayToSecond(convertJDBCValueByType(dataValue), dataValue.getPrecision(), dataValue.getScale()); } - private String wrap(String value, int precision, int scale) { - return String.format(OracleDmlValueTemplate.INTEGER_DAY_TO_SECOND_TEMPLATE, value, precision, scale); - } } diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleIntervalYMProcessor.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleIntervalYMProcessor.java index f11ca212..1ae0d557 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleIntervalYMProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleIntervalYMProcessor.java @@ -15,22 +15,18 @@ public class OracleIntervalYMProcessor extends DefaultValueProcessor { @Override public String convertSQLValueByType(SQLDataValue dataValue) { - return wrap(dataValue.getValue(), dataValue.getPrecision()); + return OracleDmlValueTemplate.wrapIntervalYearToMonth(dataValue.getValue(), dataValue.getPrecision()); } @Override public String convertJDBCValueByType(JDBCDataValue dataValue) { - return super.convertJDBCValueByType(dataValue); + return dataValue.getStringValue(); } @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return wrap(convertJDBCValueByType(dataValue), dataValue.getPrecision()); - } - - public String wrap(String value, int precision) { - return String.format(OracleDmlValueTemplate.INTEGER_YEAR_TO_MONTH_TEMPLATE, value, precision); + return OracleDmlValueTemplate.wrapIntervalYearToMonth(dataValue.getStringValue(), dataValue.getPrecision()); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleNumberProcessor.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleNumberProcessor.java index 987bdf6d..2c9952dd 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleNumberProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleNumberProcessor.java @@ -14,7 +14,7 @@ public class OracleNumberProcessor extends DefaultValueProcessor { @Override public String convertSQLValueByType(SQLDataValue dataValue) { - return super.convertSQLValueByType(dataValue); + return dataValue.getValue(); } @@ -26,6 +26,6 @@ public class OracleNumberProcessor extends DefaultValueProcessor { @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return convertJDBCValueByType(dataValue); + return dataValue.getBigDecimalString(); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleRawValueProcessor.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleRawValueProcessor.java new file mode 100644 index 00000000..db651780 --- /dev/null +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleRawValueProcessor.java @@ -0,0 +1,31 @@ +package ai.chat2db.plugin.oracle.value.sub; + +import ai.chat2db.server.tools.common.util.EasyStringUtils; +import ai.chat2db.spi.jdbc.DefaultValueProcessor; +import ai.chat2db.spi.model.JDBCDataValue; +import ai.chat2db.spi.model.SQLDataValue; + +/** + * @author: zgq + * @date: 2024年06月28日 下午1:59 + */ +public class OracleRawValueProcessor extends DefaultValueProcessor { + + + @Override + public String convertSQLValueByType(SQLDataValue dataValue) { + return EasyStringUtils.quoteString(dataValue.getValue()); + } + + + @Override + public String convertJDBCValueByType(JDBCDataValue dataValue) { + return dataValue.getBinaryDataString(); + } + + + @Override + public String convertJDBCValueStrByType(JDBCDataValue dataValue) { + return EasyStringUtils.quoteString(dataValue.getBlobHexString()); + } +} diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleTimeStampProcessor.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleTimeStampProcessor.java index 44a9d8dd..eb7ec36e 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleTimeStampProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleTimeStampProcessor.java @@ -24,7 +24,6 @@ public class OracleTimeStampProcessor extends DefaultValueProcessor { @Override public String convertJDBCValueByType(JDBCDataValue dataValue) { - // TODO: datagrip对timestampLTZ的处理是不受时区影响的,但其实这个字段就是为了可以协同时区问题的,有待商讨 Timestamp timestamp = dataValue.getTimestamp(); int scale = dataValue.getScale(); LocalDateTime localDateTime = timestamp.toLocalDateTime(); @@ -45,8 +44,8 @@ public class OracleTimeStampProcessor extends DefaultValueProcessor { private String wrap(String value, int scale) { if (scale == 0) { - return String.format(OracleDmlValueTemplate.DATE_TEMPLATE, value); + return OracleDmlValueTemplate.wrapDate(value); } - return String.format(OracleDmlValueTemplate.TIMESTAMP_TEMPLATE, value, scale); + return OracleDmlValueTemplate.wrapTimestamp(value, scale); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleTimeStampTZProcessor.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleTimeStampTZProcessor.java index 7a2d9574..bd0ceee4 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleTimeStampTZProcessor.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleTimeStampTZProcessor.java @@ -21,21 +21,19 @@ public class OracleTimeStampTZProcessor extends DefaultValueProcessor { @Override public String convertJDBCValueByType(JDBCDataValue dataValue) { - // TODO: return:2024-06-05 17:32:52.849 +8:00 but it actually is 2024-06-05 17:32:52.849000 +8:00 - return super.convertJDBCValueByType(dataValue); - + return dataValue.getStringValue(); } @Override public String convertJDBCValueStrByType(JDBCDataValue dataValue) { - return wrap(convertJDBCValueByType(dataValue), dataValue.getScale()); + return wrap(dataValue.getStringValue(), dataValue.getScale()); } private String wrap(String value, int scale) { if (scale == 0) { - return String.format(OracleDmlValueTemplate.TIMESTAMP_TZ_WITHOUT_NANOS_TEMPLATE, value); + return OracleDmlValueTemplate.wrapTimestampTzWithOutNanos(value); } - return String.format(OracleDmlValueTemplate.TIMESTAMP_TZ_TEMPLATE, value, scale); + return OracleDmlValueTemplate.wrapTimestampTz(value, scale); } } diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleXmlValueProcessor.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleXmlValueProcessor.java new file mode 100644 index 00000000..2d8214cb --- /dev/null +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/sub/OracleXmlValueProcessor.java @@ -0,0 +1,30 @@ +package ai.chat2db.plugin.oracle.value.sub; + +import ai.chat2db.plugin.oracle.value.template.OracleDmlValueTemplate; +import ai.chat2db.spi.jdbc.DefaultValueProcessor; +import ai.chat2db.spi.model.JDBCDataValue; +import ai.chat2db.spi.model.SQLDataValue; + +/** + * @author: zgq + * @date: 2024年06月21日 12:55 + */ +public class OracleXmlValueProcessor extends DefaultValueProcessor { + + @Override + public String convertSQLValueByType(SQLDataValue dataValue) { + return OracleDmlValueTemplate.wrapXml(dataValue.getValue()); + } + + + @Override + public String convertJDBCValueByType(JDBCDataValue dataValue) { + return dataValue.getStringValue(); + } + + + @Override + public String convertJDBCValueStrByType(JDBCDataValue dataValue) { + return OracleDmlValueTemplate.wrapXml(dataValue.getString()); + } +} diff --git a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/template/OracleDmlValueTemplate.java b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/template/OracleDmlValueTemplate.java index e9080ae7..a0cb8f1b 100644 --- a/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/template/OracleDmlValueTemplate.java +++ b/chat2db-server/chat2db-plugins/chat2db-oracle/src/main/java/ai/chat2db/plugin/oracle/value/template/OracleDmlValueTemplate.java @@ -13,6 +13,38 @@ public class OracleDmlValueTemplate { public static final String TIMESTAMP_TZ_TEMPLATE = "TO_TIMESTAMP_TZ('%s', 'YYYY-MM-DD HH24:MI:SS.FF%d TZH:TZM')"; public static final String TIMESTAMP_TZ_WITHOUT_NANOS_TEMPLATE = "TO_TIMESTAMP_TZ('%s', 'YYYY-MM-DD HH24:MI:SS TZH:TZM')"; - public static final String INTEGER_YEAR_TO_MONTH_TEMPLATE = "INTERVAL '%s' YEAR(%d) TO MONTH"; - public static final String INTEGER_DAY_TO_SECOND_TEMPLATE = "INTERVAL '%s' DAY(%d) TO SECOND(%d)"; + public static final String INTERVAL_YEAR_TO_MONTH_TEMPLATE = "INTERVAL '%s' YEAR(%d) TO MONTH"; + public static final String INTERVAL_DAY_TO_SECOND_TEMPLATE = "INTERVAL '%s' DAY(%d) TO SECOND(%d)"; + + public static final String XML_TEMPLATE = "XMLType('%s')"; + + + public static String wrapDate(String date) { + return String.format(DATE_TEMPLATE, date); + } + + public static String wrapTimestamp(String timestamp, int scale) { + return String.format(TIMESTAMP_TEMPLATE, timestamp, scale); + } + + public static String wrapTimestampTz(String timestamp, int scale) { + return String.format(TIMESTAMP_TZ_TEMPLATE, timestamp, scale); + } + + public static String wrapTimestampTzWithOutNanos(String timestamp) { + return String.format(TIMESTAMP_TZ_WITHOUT_NANOS_TEMPLATE, timestamp); + } + + public static String wrapIntervalYearToMonth(String year, int precision) { + return String.format(INTERVAL_YEAR_TO_MONTH_TEMPLATE, year, precision); + } + + public static String wrapIntervalDayToSecond(String day, int precision, int scale) { + return String.format(INTERVAL_DAY_TO_SECOND_TEMPLATE, day, precision, scale); + } + + public static String wrapXml(String xml) { + return String.format(XML_TEMPLATE, xml); + } + } diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/jdbc/BaseValueProcessor.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/jdbc/BaseValueProcessor.java index a0ca6750..4c209a3c 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/jdbc/BaseValueProcessor.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/jdbc/BaseValueProcessor.java @@ -4,6 +4,7 @@ import ai.chat2db.server.tools.common.util.EasyStringUtils; import ai.chat2db.spi.ValueProcessor; import ai.chat2db.spi.model.JDBCDataValue; import ai.chat2db.spi.model.SQLDataValue; +import ai.chat2db.spi.sql.Chat2DBContext; import org.apache.commons.lang3.StringUtils; import java.util.Objects; @@ -27,12 +28,19 @@ public abstract class BaseValueProcessor implements ValueProcessor { @Override public String getJdbcValue(JDBCDataValue dataValue) { Object value = dataValue.getObject(); - if (Objects.isNull(dataValue.getObject())) { + if (Objects.isNull(value)) { + // mysql -> [date]->0000:00:00 + if (Chat2DBContext.getDBConfig().getDbType().equalsIgnoreCase("mysql")) { + String stringValue = dataValue.getStringValue(); + if (Objects.nonNull(stringValue)) { + return stringValue; + } + } return null; } - if (value instanceof String emptySry) { - if (StringUtils.isBlank(emptySry)) { - return emptySry; + if (value instanceof String emptyStr) { + if (StringUtils.isBlank(emptyStr)) { + return emptyStr; } } return convertJDBCValueByType(dataValue); @@ -43,6 +51,13 @@ public abstract class BaseValueProcessor implements ValueProcessor { public String getJdbcValueString(JDBCDataValue dataValue) { Object value = dataValue.getObject(); if (Objects.isNull(value)) { + // mysql -> [date]->0000:00:00 + if (Chat2DBContext.getDBConfig().getDbType().equalsIgnoreCase("mysql")) { + String stringValue = dataValue.getStringValue(); + if (Objects.nonNull(stringValue)) { + return EasyStringUtils.escapeAndQuoteString(stringValue); + } + } return "NULL"; } if (value instanceof String stringValue) { diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/model/JDBCDataValue.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/model/JDBCDataValue.java index 420cf1ba..4e3d0a33 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/model/JDBCDataValue.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/model/JDBCDataValue.java @@ -7,14 +7,16 @@ import lombok.Data; import lombok.Getter; import org.apache.tika.Tika; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; +import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; import java.sql.*; import java.util.Objects; @@ -25,6 +27,7 @@ import java.util.Objects; @Data @AllArgsConstructor public class JDBCDataValue { + private static final Logger log = LoggerFactory.getLogger(JDBCDataValue.class); private ResultSet resultSet; private ResultSetMetaData metaData; private int columnIndex; @@ -34,6 +37,7 @@ public class JDBCDataValue { try { return resultSet.getObject(columnIndex); } catch (Exception e) { + log.warn("Failed to retrieve object from database", e); try { return resultSet.getString(columnIndex); } catch (SQLException ex) { @@ -71,7 +75,6 @@ public class JDBCDataValue { } public int getInt() { - return ResultSetUtils.getInt(resultSet, columnIndex); } @@ -91,123 +94,8 @@ public class JDBCDataValue { return ResultSetUtils.getBlob(resultSet, columnIndex); } - public String getBlobString() { - Blob blob = getBlob(); - LOBInfo blobInfo = getBlobInfo(blob); - String unit = blobInfo.getUnit(); - if (blobInfo.getSize() == 0) { - return ""; - } - - try (InputStream binaryStream = blob.getBinaryStream()) { - Tika tika = new Tika(); - String contentType = tika.detect(binaryStream); - FileTypeEnum fileTypeEnum = FileTypeEnum.fromDescription(contentType); - if (Objects.isNull(fileTypeEnum)) { - if (limitSize && isBigSize(unit)) { - return String.format("[%s] %d %s", getType(), blobInfo.getSize(), unit); - } - return getBlobHexString(); - } - switch (fileTypeEnum) { - case IMAGE: - if (limitSize) { - try (InputStream imageStream = blob.getBinaryStream()) { - BufferedImage bufferedImage = ImageIO.read(imageStream); - return String.format("[%s] %dx%d JPEG image %d %s", - getType(), bufferedImage.getWidth(), - bufferedImage.getHeight(), blobInfo.getSize(), unit); - } - } else { - return getBlobHexString(); - } - case STRING: - if (isBigSize(unit) && limitSize) { - return String.format("[%s] %d %s", getType(), blobInfo.getSize(), unit); - } else { - return new String(binaryStream.readAllBytes()); - } - default: - if (isBigSize(unit) && limitSize) { - return String.format("[%s] %d %s", getType(), blobInfo.getSize(), unit); - } - return getBlobHexString(); - } - } catch (SQLException | IOException e) { - throw new RuntimeException(e); - } - } - - - private LOBInfo getBlobInfo(Blob blob) { - try { - long size = blob.length(); - return getLobInfo(size); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - public String getClobString() { - Clob clob = getClob(); - LOBInfo cLobInfo = getCLobInfo(clob); - int size = cLobInfo.getSize(); - if (size == 0) { - return ""; - } - String unit = cLobInfo.getUnit(); - if (limitSize && isBigSize(unit)) { - return String.format("[%s] %d %s", getType(), size, unit); - } - StringBuilder builder = new StringBuilder(size); - String line; - try (BufferedReader reader = new BufferedReader(clob.getCharacterStream())) { - while ((line = reader.readLine()) != null) { - builder.append(line).append("\n"); - } - } catch (IOException | SQLException e) { - throw new RuntimeException(e); - } - return builder.toString(); - } - - private boolean isBigSize(String unit) { - return LobUnit.G.unit.equals(unit) || LobUnit.M.unit.equals(unit); - } - - public LOBInfo getCLobInfo(Clob clob) { - try { - long size = clob.length(); - return getLobInfo(size); - } catch (SQLException e) { - throw new RuntimeException(e); - } - - } - - @NotNull - private LOBInfo getLobInfo(long size) { - if (size == 0) { - return new LOBInfo(LobUnit.B.unit, 0); - } - return calculateSizeAndUnit(size); - } - - @NotNull - private LOBInfo calculateSizeAndUnit(long size) { - if (size > LobUnit.G.size) { - return new LOBInfo(LobUnit.G.unit, (int) (size / LobUnit.G.size)); - } else if (size > LobUnit.M.size) { - return new LOBInfo(LobUnit.M.unit, (int) (size / LobUnit.M.size)); - } else if (size > LobUnit.K.size) { - return new LOBInfo(LobUnit.K.unit, (int) (size / LobUnit.K.size)); - } else { - return new LOBInfo(LobUnit.B.unit, (int) size); - } - } - public String getBlobHexString() { - return "0x" + BaseEncoding.base16().encode(getBytes()); + return BaseEncoding.base16().encode(getBytes()); } public BigDecimal getBigDecimal() { @@ -219,26 +107,189 @@ public class JDBCDataValue { return bigDecimal == null ? new String(getBytes()) : bigDecimal.toPlainString(); } - @Data - @AllArgsConstructor - public static class LOBInfo { - private String unit; - private int size; + + public String getBlobString() { + Blob blob = getBlob(); + try (InputStream binaryStream = blob.getBinaryStream()) { + long length = blob.length(); + return converterBinaryData(length, binaryStream); + } catch (SQLException | IOException e) { + log.warn("Error while reading binary stream", e); + return getString(); + } } + + public String getClobString() { + Clob clob = getClob(); + try (BufferedReader reader = new BufferedReader(clob.getCharacterStream())) { + long length = clob.length(); + LOBInfo cLobInfo = getLobInfo(length); + double size = cLobInfo.getSize(); + if (size == 0) { + return ""; + } + String unit = cLobInfo.getUnit(); + if (limitSize && isBigSize(unit)) { + return String.format("[%s] %s", getType(), cLobInfo); + } + StringBuilder builder = new StringBuilder((int) (Math.ceil(size))); + String line; + + while ((line = reader.readLine()) != null) { + builder.append(line).append("\n"); + } + return builder.toString(); + } catch (IOException | SQLException e) { + log.warn("Error while reading clob stream", e); + return getStringValue(); + } + } + + private String handleImageType(InputStream imageStream, LOBInfo lobInfo) { + if (limitSize) { + try { + BufferedImage bufferedImage = ImageIO.read(imageStream); + return String.format("[%s] %dx%d JPEG image %s", getType(), bufferedImage.getWidth(), bufferedImage.getHeight(), lobInfo); + } catch (IOException e) { + log.warn("Error while reading image stream", e); + return getStringValue(); + } + } else { + return "0x" + getBlobHexString(); + } + } + + private String handleStringType(InputStream binaryStream, LOBInfo lobInfo) throws IOException { + if (isBigSize(lobInfo.getUnit()) && limitSize) { + return String.format("[%s] %s", getType(), lobInfo); + } else { + return new String(binaryStream.readAllBytes()); + } + } + + private boolean isBigSize(String unit) { + return LobUnit.G.unit.equals(unit) || LobUnit.M.unit.equals(unit); + } + + + @NotNull + private LOBInfo getLobInfo(long size) { + if (size == 0) { + return new LOBInfo(LobUnit.B.unit, 0); + } + return new LOBInfo(size); + } + + public String getStringValue() { + return ResultSetUtils.getStringValue(resultSet, columnIndex); + } + + public String getBinaryDataString() { + InputStream binaryStream = null; + try { + binaryStream = getBinaryStream(); + // 检查流是否支持 mark 操作,不支持则用 BufferedInputStream 包装 + if (!binaryStream.markSupported()) { + binaryStream = new BufferedInputStream(binaryStream); + } + + binaryStream.mark(Integer.MAX_VALUE); + + long size = 0; + byte[] buffer = new byte[8192]; // 缓冲区 + int bytesRead; + while ((bytesRead = binaryStream.read(buffer)) != -1) { + size += bytesRead; + } + binaryStream.reset(); // 重置流到标记的位置 + return converterBinaryData(size, binaryStream); + } catch (SQLException | IOException e) { + log.warn("Error while reading binary stream", e); + return getStringValue(); + } finally { + // 关闭流 + if (binaryStream != null) { + try { + binaryStream.close(); + } catch (IOException e) { + log.warn("Error while closing binary stream", e); + } + } + } + } + + private String converterBinaryData(long size, InputStream binaryStream) throws IOException, SQLException { + LOBInfo lobInfo = getLobInfo(size); + String unit = lobInfo.unit; + if (size == 0) { + return ""; + } + Tika tika = new Tika(); + String contentType = tika.detect(binaryStream); + FileTypeEnum fileTypeEnum = FileTypeEnum.fromDescription(contentType); + if (Objects.isNull(fileTypeEnum)) { + if (isBigSize(unit) && limitSize) { + return String.format("[%s] %s", getType(), lobInfo); + } + return "0x" + getBlobHexString(); + } + + return switch (fileTypeEnum) { + case IMAGE -> handleImageType(binaryStream, lobInfo); + case STRING -> handleStringType(binaryStream, lobInfo); + default -> ""; + }; + } + + @Getter public enum LobUnit { - B("B", 1), - K("KB", 1024), - M("MB", 1024 * 1024), - G("GB", 1024 * 1024 * 1024); - private final String unit; - private final int size; + B("B", 1L), + K("KB", 1024L), + M("MB", 1024L * 1024L), + G("GB", 1024L * 1024L * 1024L); - LobUnit(String unit, int size) { + private final String unit; + private final long size; + + LobUnit(String unit, long size) { this.unit = unit; this.size = size; } + + } + + @Getter + public static class LOBInfo { + private final String unit; + private final double size; + + public LOBInfo(String unit, double size) { + this.unit = unit; + this.size = size; + } + + public LOBInfo(long size) { + if (size >= LobUnit.G.size) { + this.unit = LobUnit.G.unit; + this.size = (double) size / LobUnit.G.size; + } else if (size >= LobUnit.M.size) { + this.unit = LobUnit.M.unit; + this.size = (double) size / LobUnit.M.size; + } else if (size >= LobUnit.K.size) { + this.unit = LobUnit.K.unit; + this.size = (double) size / LobUnit.K.size; + } else { + this.unit = LobUnit.B.unit; + this.size = (double) size; + } + } + + @Override + public String toString() { + return String.format("%.2f %s", size, unit); + } } @Getter diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/model/SQLDataValue.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/model/SQLDataValue.java index f285bc75..05e95583 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/model/SQLDataValue.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/model/SQLDataValue.java @@ -25,6 +25,6 @@ public class SQLDataValue { } public String getBlobHexString() { - return "0x" + BaseEncoding.base16().encode(value.getBytes()); + return BaseEncoding.base16().encode(value.getBytes()); } } diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/SQLExecutor.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/SQLExecutor.java index b947eb07..0503cfa7 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/SQLExecutor.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/sql/SQLExecutor.java @@ -1,10 +1,5 @@ package ai.chat2db.spi.sql; -import java.sql.*; -import java.util.*; -import java.util.function.Consumer; -import java.util.stream.Collectors; - import ai.chat2db.server.tools.base.constant.EasyToolsConstant; import ai.chat2db.server.tools.base.enums.DataSourceTypeEnum; import ai.chat2db.server.tools.base.excption.BusinessException; @@ -15,25 +10,26 @@ import ai.chat2db.spi.MetaData; import ai.chat2db.spi.ValueProcessor; import ai.chat2db.spi.enums.DataTypeEnum; import ai.chat2db.spi.enums.SqlTypeEnum; -import ai.chat2db.spi.jdbc.DefaultValueProcessor; import ai.chat2db.spi.model.*; import ai.chat2db.spi.util.JdbcUtils; import ai.chat2db.spi.util.ResultSetUtils; import ai.chat2db.spi.util.SqlUtils; import cn.hutool.core.date.TimeInterval; - import com.alibaba.druid.DbType; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import com.google.common.collect.Lists; - import lombok.extern.slf4j.Slf4j; - import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.util.Assert; +import java.sql.*; +import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Collectors; + /** * Dbhub unified database connection management * @@ -248,7 +244,7 @@ public class SQLExecutor implements CommandExecutor { continue; } ValueProcessor valueProcessor = Chat2DBContext.getMetaData().getValueProcessor(); - row.add(valueProcessor.getJdbcValue(new JDBCDataValue(rs, rs.getMetaData(), i, false))); + row.add(valueProcessor.getJdbcValue(new JDBCDataValue(rs, rs.getMetaData(), i, limitRowSize))); } if (count != null && count > 0 && rowCount++ >= count) { break; @@ -386,7 +382,7 @@ public class SQLExecutor implements CommandExecutor { tableName, String columnName) { try (ResultSet resultSet = connection.getMetaData().getColumns(databaseName, schemaName, tableName, - columnName)) { + columnName)) { return ResultSetUtils.toObjectList(resultSet, TableColumn.class); } catch (Exception e) { throw new RuntimeException(e); @@ -405,8 +401,8 @@ public class SQLExecutor implements CommandExecutor { public List indexes(Connection connection, String databaseName, String schemaName, String tableName) { List tableIndices = Lists.newArrayList(); try (ResultSet resultSet = connection.getMetaData().getIndexInfo(databaseName, schemaName, tableName, - false, - false)) { + false, + false)) { List tableIndexColumns = ResultSetUtils.toObjectList(resultSet, TableIndexColumn.class); tableIndexColumns.stream().filter(c -> c.getIndexName() != null).collect( Collectors.groupingBy(TableIndexColumn::getIndexName)).entrySet() @@ -582,7 +578,7 @@ public class SQLExecutor implements CommandExecutor { Header rowNumberHeader = Header.builder() .name(I18nUtils.getMessage("sqlResult.rowNumber")) .dataType(DataTypeEnum.CHAT2DB_ROW_NUMBER - .getCode()).build(); + .getCode()).build(); executeResult.setHeaderList(EasyCollectionUtils.union(Arrays.asList(rowNumberHeader), headers)); // Add row number diff --git a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/ResultSetUtils.java b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/ResultSetUtils.java index e26d496e..9c872dc0 100644 --- a/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/ResultSetUtils.java +++ b/chat2db-server/chat2db-spi/src/main/java/ai/chat2db/spi/util/ResultSetUtils.java @@ -1,8 +1,6 @@ package ai.chat2db.spi.util; -import ai.chat2db.server.tools.common.util.I18nUtils; -import cn.hutool.core.io.unit.DataSizeUtil; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; @@ -29,7 +27,6 @@ import java.util.Map; public class ResultSetUtils { - public static List getRsHeader(ResultSet rs) { try { ResultSetMetaData resultSetMetaData = rs.getMetaData(); @@ -262,4 +259,12 @@ public class ResultSetUtils { throw new RuntimeException(e); } } + + public static String getStringValue(ResultSet resultSet, int columnIndex) { + try { + return resultSet.getString(columnIndex); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } } \ No newline at end of file