Skip to content

Commit

Permalink
fix(chat2db-mysql): optimize valueProcessor
Browse files Browse the repository at this point in the history
  • Loading branch information
pdxzzz committed Jul 15, 2024
1 parent ffc2bc0 commit 95db332
Show file tree
Hide file tree
Showing 12 changed files with 465 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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));
}

}
Original file line number Diff line number Diff line change
@@ -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());
}
}
Loading

0 comments on commit 95db332

Please sign in to comment.