diff --git a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/RwSplitSelectVariablesHandler.java b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/RwSplitSelectVariablesHandler.java new file mode 100644 index 0000000000..bfa8b9f323 --- /dev/null +++ b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/RwSplitSelectVariablesHandler.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016-2021 ActionTech. + * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher. + */ + +package com.actiontech.dble.backend.mysql.nio.handler; + +import com.actiontech.dble.net.mysql.CharsetNames; +import com.actiontech.dble.net.mysql.FieldPacket; +import com.actiontech.dble.net.mysql.RowDataPacket; +import com.actiontech.dble.net.service.AbstractService; +import com.actiontech.dble.services.rwsplit.Callback; +import com.actiontech.dble.services.rwsplit.RWSplitHandler; +import com.actiontech.dble.services.rwsplit.RWSplitService; +import com.actiontech.dble.util.StringUtil; + +import java.util.*; + +public class RwSplitSelectVariablesHandler extends RWSplitHandler { + private CharsetNames charsetName; + private List columnNames = new ArrayList<>(); + + public RwSplitSelectVariablesHandler(RWSplitService service, boolean isUseOriginPacket, byte[] originPacket, Callback callback) { + super(service, isUseOriginPacket, originPacket, callback); + charsetName = service.getCharset(); + } + + @Override + public void fieldEofResponse(byte[] header, List fields, List fieldPacketsNull, byte[] eof, + boolean isLeft, AbstractService service) { + for (byte[] field : fields) { + FieldPacket fieldPacket = new FieldPacket(); + fieldPacket.read(field); + String columnName = StringUtil.decode(fieldPacket.getName(), charsetName.getResults()); + columnNames.add(columnName); + } + super.fieldEofResponse(header, fields, fieldPacketsNull, eof, isLeft, service); + } + + @Override + public boolean rowResponse(byte[] row, RowDataPacket rowPacket, boolean isLeft, AbstractService service) { + int index = columnNames.size(); + RowDataPacket rowDataPacket = new RowDataPacket(index); + String charset = charsetName.getResults(); + rowDataPacket.read(row); + Map variables = getVariables(); + for (int i = 0; i < index; i++) { + String columnName = columnNames.get(i); + if (variables.containsKey(columnName)) { + rowDataPacket.setValue(i, StringUtil.encode(variables.get(columnName), charset)); + } + } + return super.rowResponse(rowDataPacket.toBytes(), rowPacket, isLeft, service); + } + + private Map getVariables() { + Map variables = new HashMap<>(); + variables.put("character_set_client", charsetName.getClient()); + variables.put("collation_connection", charsetName.getCollation()); + variables.put("character_set_results", charsetName.getResults()); + variables.put("character_set_connection", charsetName.getCollation()); + return variables; + } +} diff --git a/src/main/java/com/actiontech/dble/rwsplit/RWSplitNonBlockingSession.java b/src/main/java/com/actiontech/dble/rwsplit/RWSplitNonBlockingSession.java index 9e621216cf..2c1565f876 100644 --- a/src/main/java/com/actiontech/dble/rwsplit/RWSplitNonBlockingSession.java +++ b/src/main/java/com/actiontech/dble/rwsplit/RWSplitNonBlockingSession.java @@ -9,6 +9,7 @@ import com.actiontech.dble.backend.datasource.PhysicalDbGroup; import com.actiontech.dble.backend.datasource.PhysicalDbInstance; import com.actiontech.dble.backend.mysql.ByteUtil; +import com.actiontech.dble.backend.mysql.nio.handler.RwSplitSelectVariablesHandler; import com.actiontech.dble.config.ErrorCode; import com.actiontech.dble.config.model.SystemConfig; import com.actiontech.dble.config.util.ConfigException; @@ -219,6 +220,38 @@ private boolean isWriteStatistical(boolean writeStatistical) { return writeStatistical; } + /** + * jdbc compatible pre-delivery statements + * @param master + * @param originPacket + * @param callback + * @param writeStatistical + * @param localRead + */ + public void selectCompatibilityVariables(Boolean master, byte[] originPacket, Callback callback, boolean writeStatistical, boolean localRead) { + try { + RWSplitHandler handler = getRwSplitSelectVariablesHandler(originPacket != null ? originPacket : getService().getExecuteSqlBytes(), callback); + if (handler == null) return; + getConnection(handler, master, isWriteStatistical(writeStatistical), localRead); + } catch (SQLSyntaxErrorException | IOException se) { + rwSplitService.writeErrMessage(ErrorCode.ER_UNKNOWN_ERROR, se.getMessage()); + } + } + + @Nullable + private RWSplitHandler getRwSplitSelectVariablesHandler(byte[] originPacket, Callback callback) throws SQLSyntaxErrorException, IOException { + if (conn != null && !conn.isClosed()) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("select bind conn[id={}]", conn.getId()); + } + RWSplitHandler handler = new RwSplitSelectVariablesHandler(rwSplitService, true, originPacket, callback); + checkDest(!conn.getInstance().isReadInstance()); + handler.execute(conn); + return null; + } + return new RwSplitSelectVariablesHandler(rwSplitService, true, originPacket, callback); + } + private Boolean canRunOnMaster(Boolean master) { if ((rwSplitService.isInTransaction() && !rwSplitService.isReadOnly()) || rwSplitService.isUsingTmpTable()) { return true; diff --git a/src/main/java/com/actiontech/dble/services/rwsplit/handle/RwSplitSelectHandler.java b/src/main/java/com/actiontech/dble/services/rwsplit/handle/RwSplitSelectHandler.java index 06ee3cc909..8a3a11c5fc 100644 --- a/src/main/java/com/actiontech/dble/services/rwsplit/handle/RwSplitSelectHandler.java +++ b/src/main/java/com/actiontech/dble/services/rwsplit/handle/RwSplitSelectHandler.java @@ -6,7 +6,6 @@ package com.actiontech.dble.services.rwsplit.handle; import com.actiontech.dble.server.parser.RwSplitServerParseSelect; -import com.actiontech.dble.server.response.SelectVariables; import com.actiontech.dble.services.rwsplit.RWSplitService; @@ -20,7 +19,7 @@ private RwSplitSelectHandler() { public static void handle(String stmt, RWSplitService service, int offset) { switch (RwSplitServerParseSelect.parse(stmt, offset)) { case RwSplitServerParseSelect.SELECT_VAR_ALL: - SelectVariables.execute(service, stmt); + service.getSession2().selectCompatibilityVariables(true, null, null, false, false); break; default: { int rs2 = RwSplitServerParseSelect.parseSpecial(stmt);