fix(chat2db-mysql): optimize valueProcessor

This commit is contained in:
zgq
2024-07-15 21:18:13 +08:00
parent ffc2bc0e14
commit 95db332ad3
12 changed files with 465 additions and 14 deletions

View File

@ -1,9 +1,15 @@
package ai.chat2db.plugin.mariadb;
import ai.chat2db.plugin.mariadb.value.MariaDBValueProcessor;
import ai.chat2db.plugin.mysql.MysqlMetaData;
import ai.chat2db.spi.MetaData;
import ai.chat2db.spi.ValueProcessor;
public class MariaDBMetaData extends MysqlMetaData implements MetaData {
@Override
public ValueProcessor getValueProcessor() {
return new MariaDBValueProcessor();
}
}

View File

@ -0,0 +1,109 @@
package ai.chat2db.plugin.mariadb.value;
import ai.chat2db.plugin.mariadb.value.factory.MariaDBValueProcessorFactory;
import ai.chat2db.plugin.mysql.value.MysqlValueProcessor;
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 org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Objects;
/**
* @author: zgq
* @date: 2024年05月24日 21:02
* <br>
* TODO:
* attribute: [zerofill] example tinyint[5] zerofill 34->00034
*/
public class MariaDBValueProcessor extends MysqlValueProcessor {
private static final Logger log = LoggerFactory.getLogger(MariaDBValueProcessor.class);
@Override
public String getJdbcValue(JDBCDataValue dataValue) {
Object value = dataValue.getObject();
if (Objects.isNull(value)) {
// example: [date]->0000-00-00
String stringValue = dataValue.getStringValue();
if (Objects.nonNull(stringValue)) {
return stringValue;
}
return null;
}
if (value instanceof String emptyStr) {
if (StringUtils.isBlank(emptyStr)) {
return emptyStr;
}
}
return convertJDBCValueByType(dataValue);
}
@Override
public String getJdbcSqlValueString(JDBCDataValue dataValue) {
Object value = dataValue.getObject();
if (Objects.isNull(value)) {
// example: [date]->0000-00-00
String stringValue = dataValue.getStringValue();
if (Objects.nonNull(stringValue)) {
return EasyStringUtils.escapeAndQuoteString(stringValue);
}
return "NULL";
}
if (value instanceof String stringValue) {
if (StringUtils.isBlank(stringValue)) {
return EasyStringUtils.quoteString(stringValue);
}
}
return convertJDBCValueStrByType(dataValue);
}
@Override
public String convertSQLValueByType(SQLDataValue dataValue) {
try {
DefaultValueProcessor valueProcessor = MariaDBValueProcessorFactory.getValueProcessor(dataValue.getDateTypeName());
if (Objects.isNull(valueProcessor)) {
return super.convertSQLValueByType(dataValue);
}
return valueProcessor.convertSQLValueByType(dataValue);
} catch (Exception e) {
log.warn("convertSQLValueByType error", e);
return super.convertSQLValueByType(dataValue);
}
}
@Override
public String convertJDBCValueByType(JDBCDataValue dataValue) {
String type = dataValue.getType();
try {
DefaultValueProcessor valueProcessor = MariaDBValueProcessorFactory.getValueProcessor(type);
if (Objects.isNull(valueProcessor)) {
return super.convertJDBCValueByType(dataValue);
}
return valueProcessor.convertJDBCValueByType(dataValue);
} catch (Exception e) {
log.warn("convertJDBCValueByType error", e);
return super.convertJDBCValueByType(dataValue);
}
}
@Override
public String convertJDBCValueStrByType(JDBCDataValue dataValue) {
String type = dataValue.getType();
try {
DefaultValueProcessor valueProcessor = MariaDBValueProcessorFactory.getValueProcessor(type);
if (Objects.isNull(valueProcessor)) {
return super.convertJDBCValueByType(dataValue);
}
return valueProcessor.convertJDBCValueStrByType(dataValue);
} catch (Exception e) {
log.warn("convertJDBCValueStrByType error", e);
return super.convertJDBCValueStrByType(dataValue);
}
}
}

View File

@ -0,0 +1,61 @@
package ai.chat2db.plugin.mariadb.value.factory;
import ai.chat2db.plugin.mariadb.value.sub.MariaDBBitProcessor;
import ai.chat2db.plugin.mariadb.value.sub.MariaDBGeometryProcessor;
import ai.chat2db.plugin.mariadb.value.sub.MariaDBTimestampProcessor;
import ai.chat2db.plugin.mariadb.value.sub.MariaDBYearProcessor;
import ai.chat2db.plugin.mysql.type.MysqlColumnTypeEnum;
import ai.chat2db.plugin.mysql.value.sub.*;
import ai.chat2db.spi.jdbc.DefaultValueProcessor;
import java.util.Map;
/**
* @author: zgq
* @date: 2024年06月03日 23:16
*/
public class MariaDBValueProcessorFactory {
private static final Map<String, DefaultValueProcessor> PROCESSOR_MAP;
static {
MariaDBGeometryProcessor mariaDBGeometryProcessor = new MariaDBGeometryProcessor();
MysqlVarBinaryProcessor mysqlVarBinaryProcessor = new MysqlVarBinaryProcessor();
MariaDBTimestampProcessor mariaDBTimestampProcessor = new MariaDBTimestampProcessor();
MysqlTextProcessor mysqlTextProcessor = new MysqlTextProcessor();
PROCESSOR_MAP = Map.ofEntries(
//text
Map.entry(MysqlColumnTypeEnum.TEXT.name(), mysqlTextProcessor),
Map.entry(MysqlColumnTypeEnum.TINYTEXT.name(), mysqlTextProcessor),
Map.entry(MysqlColumnTypeEnum.MEDIUMTEXT.name(), mysqlTextProcessor),
Map.entry(MysqlColumnTypeEnum.LONGTEXT.name(), mysqlTextProcessor),
// geometry
Map.entry(MysqlColumnTypeEnum.GEOMETRY.name(), mariaDBGeometryProcessor),
Map.entry(MysqlColumnTypeEnum.POINT.name(), mariaDBGeometryProcessor),
Map.entry(MysqlColumnTypeEnum.LINESTRING.name(), mariaDBGeometryProcessor),
Map.entry(MysqlColumnTypeEnum.POLYGON.name(), mariaDBGeometryProcessor),
Map.entry(MysqlColumnTypeEnum.MULTIPOINT.name(), mariaDBGeometryProcessor),
Map.entry(MysqlColumnTypeEnum.MULTILINESTRING.name(), mariaDBGeometryProcessor),
Map.entry(MysqlColumnTypeEnum.MULTIPOLYGON.name(), mariaDBGeometryProcessor),
Map.entry(MysqlColumnTypeEnum.GEOMETRYCOLLECTION.name(), mariaDBGeometryProcessor),
// binary
Map.entry(MysqlColumnTypeEnum.VARBINARY.name(), mysqlVarBinaryProcessor),
Map.entry(MysqlColumnTypeEnum.BLOB.name(), mysqlVarBinaryProcessor),
Map.entry(MysqlColumnTypeEnum.LONGBLOB.name(), mysqlVarBinaryProcessor),
Map.entry(MysqlColumnTypeEnum.TINYBLOB.name(), mysqlVarBinaryProcessor),
Map.entry(MysqlColumnTypeEnum.MEDIUMBLOB.name(), mysqlVarBinaryProcessor),
// timestamp
Map.entry(MysqlColumnTypeEnum.TIMESTAMP.name(), mariaDBTimestampProcessor),
Map.entry(MysqlColumnTypeEnum.DATETIME.name(), mariaDBTimestampProcessor),
//others
Map.entry(MysqlColumnTypeEnum.YEAR.name(), new MariaDBYearProcessor()),
Map.entry(MysqlColumnTypeEnum.BIT.name(), new MariaDBBitProcessor()),
Map.entry(MysqlColumnTypeEnum.DECIMAL.name(), new MysqlDecimalProcessor()),
Map.entry(MysqlColumnTypeEnum.BINARY.name(), new MysqlBinaryProcessor())
);
}
public static DefaultValueProcessor getValueProcessor(String type) {
return PROCESSOR_MAP.get(type);
}
}

View File

@ -0,0 +1,76 @@
package ai.chat2db.plugin.mariadb.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;
import ai.chat2db.spi.sql.Chat2DBContext;
import org.apache.commons.lang3.StringUtils;
import java.sql.SQLException;
import java.util.Objects;
import java.util.function.Function;
/**
* @author: zgq
* @date: 2024年06月01日 13:08
*/
public class MariaDBBitProcessor extends DefaultValueProcessor {
@Override
public String convertSQLValueByType(SQLDataValue dataValue) {
return getString(dataValue.getValue());
}
@Override
public String convertJDBCValueByType(JDBCDataValue dataValue) {
return getValue(dataValue, s -> s);
}
@Override
public String convertJDBCValueStrByType(JDBCDataValue dataValue) {
return getValue(dataValue, this::wrap);
}
private String getValue(JDBCDataValue dataValue, Function<String, String> function) {
try {
//mariadb tinyint(1)
if ((dataValue.getMetaData().getColumnType(dataValue.getColumnIndex()) == -7)) {
return String.valueOf(dataValue.getInt());
}
} catch (SQLException e) {
super.convertJDBCValueByType(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());
}
}
//bit(m) m: 2~64
return function.apply(EasyStringUtils.getBitString(bytes, precision));
}
public String getString(String value) {
if (Objects.equals("true", value.toLowerCase())) {
return "1";
}
if (Objects.equals("false", value.toLowerCase())) {
return "0";
}
if (StringUtils.isBlank(value)) {
return "NULL";
}
return MysqlDmlValueTemplate.wrapBit(value);
}
private String wrap(String value) {
return MysqlDmlValueTemplate.wrapBit(value);
}
}

View File

@ -0,0 +1,80 @@
package ai.chat2db.plugin.mariadb.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 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;
/**
* @author: zgq
* @date: 2024年06月01日 12:42
*/
public class MariaDBGeometryProcessor extends DefaultValueProcessor {
private static final Logger log = LoggerFactory.getLogger(MariaDBGeometryProcessor.class);
@Override
public String convertSQLValueByType(SQLDataValue dataValue) {
return MysqlDmlValueTemplate.wrapGeometry(dataValue.getValue());
}
@Override
public String convertJDBCValueByType(JDBCDataValue dataValue) {
try {
Geometry dbGeometry = null;
byte[] geometryAsBytes = dataValue.getBytes();
if (geometryAsBytes != null) {
if (geometryAsBytes.length < 5) {
throw new Exception("Invalid geometry inputStream - less than five bytes");
}
//first four bytes of the geometry are the SRID,
//followed by the actual WKB. Determine the SRID
//here
byte[] sridBytes = new byte[4];
System.arraycopy(geometryAsBytes, 0, sridBytes, 0, 4);
boolean bigEndian = (geometryAsBytes[4] == 0x00);
int srid = 0;
if (bigEndian) {
for (int i = 0; i < sridBytes.length; i++) {
srid = (srid << 8) + (sridBytes[i] & 0xff);
}
} else {
for (int i = 0; i < sridBytes.length; i++) {
srid += (sridBytes[i] & 0xff) << (8 * i);
}
}
//use the JTS WKBReader for WKB parsing
WKBReader wkbReader = new WKBReader();
//copy the byte array, removing the first four
//SRID bytes
byte[] wkb = new byte[geometryAsBytes.length - 4];
System.arraycopy(geometryAsBytes, 4, wkb, 0, wkb.length);
dbGeometry = wkbReader.read(wkb);
dbGeometry.setSRID(srid);
}
return dbGeometry != null ? dbGeometry.toString() : null;
} catch (Exception e) {
log.warn("Error converting database geometry", e);
return dataValue.getStringValue();
}
}
@Override
public String convertJDBCValueStrByType(JDBCDataValue dataValue) {
return MysqlDmlValueTemplate.wrapGeometry(convertJDBCValueByType(dataValue));
}
}

View File

@ -0,0 +1,30 @@
package ai.chat2db.plugin.mariadb.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月01日 18:26
*/
public class MariaDBTimestampProcessor extends DefaultValueProcessor {
@Override
public String convertSQLValueByType(SQLDataValue dataValue) {
return EasyStringUtils.quoteString(dataValue.getValue());
}
@Override
public String convertJDBCValueByType(JDBCDataValue dataValue) {
return dataValue.getStringValue();
}
@Override
public String convertJDBCValueStrByType(JDBCDataValue dataValue) {
return EasyStringUtils.quoteString(dataValue.getStringValue());
}
}

View File

@ -0,0 +1,31 @@
package ai.chat2db.plugin.mariadb.value.sub;
import ai.chat2db.spi.jdbc.DefaultValueProcessor;
import ai.chat2db.spi.model.JDBCDataValue;
import ai.chat2db.spi.model.SQLDataValue;
/**
* 功能描述
*
* @author: zgq
* @date: 2024年07月15日 20:19
*/
public class MariaDBYearProcessor extends DefaultValueProcessor {
@Override
public String convertSQLValueByType(SQLDataValue dataValue) {
return dataValue.getValue();
}
@Override
public String convertJDBCValueByType(JDBCDataValue dataValue) {
return dataValue.getStringValue();
}
@Override
public String convertJDBCValueStrByType(JDBCDataValue dataValue) {
return dataValue.getStringValue();
}
}

View File

@ -6,6 +6,8 @@ import ai.chat2db.spi.jdbc.DefaultValueProcessor;
import ai.chat2db.spi.model.JDBCDataValue;
import ai.chat2db.spi.model.SQLDataValue;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Objects;
import java.util.Set;
@ -19,6 +21,7 @@ import java.util.Set;
*/
public class MysqlValueProcessor extends DefaultValueProcessor {
public static final Set<String> FUNCTION_SET = Set.of("now()", "default");
private static final Logger log = LoggerFactory.getLogger(MysqlValueProcessor.class);
@Override
@ -65,18 +68,47 @@ public class MysqlValueProcessor extends DefaultValueProcessor {
if (FUNCTION_SET.contains(dataValue.getValue().toLowerCase())) {
return dataValue.getValue();
}
return MysqlValueProcessorFactory.getValueProcessor(dataValue.getDateTypeName()).convertSQLValueByType(dataValue);
try {
DefaultValueProcessor valueProcessor = MysqlValueProcessorFactory.getValueProcessor(dataValue.getDateTypeName());
if (Objects.nonNull(valueProcessor)) {
return valueProcessor.convertSQLValueByType(dataValue);
}
} catch (Exception e) {
log.warn("convertSQLValueByType error", e);
return super.convertSQLValueByType(dataValue);
}
return super.convertSQLValueByType(dataValue);
}
@Override
public String convertJDBCValueByType(JDBCDataValue dataValue) {
String type = dataValue.getType();
return MysqlValueProcessorFactory.getValueProcessor(type).convertJDBCValueByType(dataValue);
try {
DefaultValueProcessor valueProcessor = MysqlValueProcessorFactory.getValueProcessor(type);
if (Objects.nonNull(valueProcessor)) {
return valueProcessor.convertJDBCValueByType(dataValue);
}
} catch (Exception e) {
log.warn("convertJDBCValueByType error", e);
return super.convertJDBCValueByType(dataValue);
}
return super.convertJDBCValueByType(dataValue);
}
@Override
public String convertJDBCValueStrByType(JDBCDataValue dataValue) {
String type = dataValue.getType();
return MysqlValueProcessorFactory.getValueProcessor(type).convertJDBCValueStrByType(dataValue);
DefaultValueProcessor valueProcessor;
try {
valueProcessor = MysqlValueProcessorFactory.getValueProcessor(type);
if (Objects.nonNull(valueProcessor)) {
return valueProcessor.convertJDBCValueStrByType(dataValue);
}
} catch (Exception e) {
log.warn("convertJDBCValueStrByType error", e);
return super.convertJDBCValueStrByType(dataValue);
}
return super.convertJDBCValueStrByType(dataValue);
}
}

View File

@ -52,7 +52,6 @@ public class MysqlValueProcessorFactory {
}
public static DefaultValueProcessor getValueProcessor(String type) {
DefaultValueProcessor processor = PROCESSOR_MAP.get(type);
return processor == null ? new DefaultValueProcessor() : processor;
return PROCESSOR_MAP.get(type);
}
}

View File

@ -7,6 +7,8 @@ import ai.chat2db.spi.jdbc.DefaultValueProcessor;
import ai.chat2db.spi.model.JDBCDataValue;
import ai.chat2db.spi.model.SQLDataValue;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Objects;
@ -17,6 +19,8 @@ import java.util.Objects;
public class OracleValueProcessor extends DefaultValueProcessor {
private static final Logger log = LoggerFactory.getLogger(OracleValueProcessor.class);
@Override
public String getJdbcValue(JDBCDataValue dataValue) {
if (OracleColumnTypeEnum.LONG_RAW.getColumnType().getTypeName().equalsIgnoreCase(dataValue.getType())) {
@ -54,19 +58,47 @@ public class OracleValueProcessor extends DefaultValueProcessor {
@Override
public String convertSQLValueByType(SQLDataValue dataValue) {
return OracleValueProcessorFactory.getValueProcessor(dataValue.getDateTypeName()).convertSQLValueByType(dataValue);
try {
DefaultValueProcessor valueProcessor = OracleValueProcessorFactory.getValueProcessor(dataValue.getDateTypeName());
if (Objects.nonNull(valueProcessor)) {
return valueProcessor.convertSQLValueByType(dataValue);
}
} catch (Exception e) {
log.warn("convertSQLValueByType error", e);
return super.convertSQLValueByType(dataValue);
}
return super.convertSQLValueByType(dataValue);
}
@Override
public String convertJDBCValueByType(JDBCDataValue dataValue) {
String type = dataValue.getType();
return OracleValueProcessorFactory.getValueProcessor(type).convertJDBCValueByType(dataValue);
try {
DefaultValueProcessor valueProcessor = OracleValueProcessorFactory.getValueProcessor(type);
if (Objects.nonNull(valueProcessor)) {
return valueProcessor.convertJDBCValueByType(dataValue);
}
} catch (Exception e) {
log.warn("convertJDBCValueByType error", e);
return super.convertJDBCValueByType(dataValue);
}
return super.convertJDBCValueByType(dataValue);
}
@Override
public String convertJDBCValueStrByType(JDBCDataValue dataValue) {
return OracleValueProcessorFactory.getValueProcessor(dataValue.getType()).convertJDBCValueStrByType(dataValue);
String type = dataValue.getType();
try {
DefaultValueProcessor valueProcessor = OracleValueProcessorFactory.getValueProcessor(type);
if (Objects.nonNull(valueProcessor)) {
return valueProcessor.convertJDBCValueStrByType(dataValue);
}
} catch (Exception e) {
log.warn("convertJDBCValueStrByType error", e);
return super.convertJDBCValueStrByType(dataValue);
}
return super.convertJDBCValueStrByType(dataValue);
}
}

View File

@ -49,7 +49,7 @@ public class OracleValueProcessorFactory {
}
public static DefaultValueProcessor getValueProcessor(String type) {
return PROCESSOR_MAP.getOrDefault(type, new DefaultValueProcessor());
return PROCESSOR_MAP.get(type);
}
}

View File

@ -52,9 +52,4 @@ public class OracleLongRawProcessor extends DefaultValueProcessor {
return EasyStringUtils.quoteString(blobHexString);
}
public static void main(String[] args) {
String value = "0x123456";
value = value.substring(2);
System.out.println("value = " + value);
}
}