From fa2fed7d1b67309c2764dfc648bde3e031711f88 Mon Sep 17 00:00:00 2001 From: yanhuqing Date: Wed, 1 Nov 2017 11:03:05 +0800 Subject: [PATCH 1/5] read only message #308 --- .../com/actiontech/dble/config/ErrorCode.java | 1 + .../dble/manager/ManagerQueryHandler.java | 5 +++++ .../actiontech/dble/net/FrontendConnection.java | 3 ++- .../dble/net/handler/FrontendQueryHandler.java | 2 ++ .../dble/server/ServerQueryHandler.java | 16 ++++++++++++---- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/actiontech/dble/config/ErrorCode.java b/src/main/java/com/actiontech/dble/config/ErrorCode.java index 7cb4e705a..d3e925d98 100644 --- a/src/main/java/com/actiontech/dble/config/ErrorCode.java +++ b/src/main/java/com/actiontech/dble/config/ErrorCode.java @@ -536,5 +536,6 @@ public final class ErrorCode { public static final int ER_DROP_PARTITION_WHEN_FK_DEFINED = 1493; public static final int ER_PLUGIN_IS_NOT_LOADED = 1494; public static final int ER_USER_READ_ONLY = 1495; + public static final int ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION = 1792; } diff --git a/src/main/java/com/actiontech/dble/manager/ManagerQueryHandler.java b/src/main/java/com/actiontech/dble/manager/ManagerQueryHandler.java index d6c01b7ee..e2eeb709b 100644 --- a/src/main/java/com/actiontech/dble/manager/ManagerQueryHandler.java +++ b/src/main/java/com/actiontech/dble/manager/ManagerQueryHandler.java @@ -28,9 +28,14 @@ public class ManagerQueryHandler implements FrontendQueryHandler { this.source = source; } + @Override public void setReadOnly(Boolean readOnly) { } + @Override + public void setSessionReadOnly(boolean sessionReadOnly) { + } + @Override public void query(String sql) { ManagerConnection c = this.source; diff --git a/src/main/java/com/actiontech/dble/net/FrontendConnection.java b/src/main/java/com/actiontech/dble/net/FrontendConnection.java index 2520e6e56..26066dec7 100644 --- a/src/main/java/com/actiontech/dble/net/FrontendConnection.java +++ b/src/main/java/com/actiontech/dble/net/FrontendConnection.java @@ -310,7 +310,8 @@ public abstract class FrontendConnection extends AbstractConnection { // execute if (queryHandler != null) { - queryHandler.setReadOnly(userReadOnly || sessionReadOnly); + queryHandler.setReadOnly(userReadOnly); + queryHandler.setSessionReadOnly(sessionReadOnly); queryHandler.query(sql); } else { writeErrMessage(ErrorCode.ER_UNKNOWN_COM_ERROR, "Query unsupported!"); diff --git a/src/main/java/com/actiontech/dble/net/handler/FrontendQueryHandler.java b/src/main/java/com/actiontech/dble/net/handler/FrontendQueryHandler.java index 60570f361..73252faf4 100644 --- a/src/main/java/com/actiontech/dble/net/handler/FrontendQueryHandler.java +++ b/src/main/java/com/actiontech/dble/net/handler/FrontendQueryHandler.java @@ -15,4 +15,6 @@ public interface FrontendQueryHandler { void query(String sql); void setReadOnly(Boolean readOnly); + + void setSessionReadOnly(boolean sessionReadOnly); } diff --git a/src/main/java/com/actiontech/dble/server/ServerQueryHandler.java b/src/main/java/com/actiontech/dble/server/ServerQueryHandler.java index 0df6a2cdb..488ded799 100644 --- a/src/main/java/com/actiontech/dble/server/ServerQueryHandler.java +++ b/src/main/java/com/actiontech/dble/server/ServerQueryHandler.java @@ -20,12 +20,18 @@ public class ServerQueryHandler implements FrontendQueryHandler { private static final Logger LOGGER = LoggerFactory.getLogger(ServerQueryHandler.class); private final ServerConnection source; - protected Boolean readOnly = true; - + private Boolean readOnly = true; + private boolean sessionReadOnly = true; + @Override public void setReadOnly(Boolean readOnly) { this.readOnly = readOnly; } + @Override + public void setSessionReadOnly(boolean sessionReadOnly) { + this.sessionReadOnly = sessionReadOnly; + } + public ServerQueryHandler(ServerConnection source) { this.source = source; } @@ -107,8 +113,10 @@ public class ServerQueryHandler implements FrontendQueryHandler { break; default: if (readOnly) { - LOGGER.warn("User readonly:" + sql); - c.writeErrMessage(ErrorCode.ER_USER_READ_ONLY, "User readonly"); + c.writeErrMessage(ErrorCode.ER_USER_READ_ONLY, "User READ ONLY"); + break; + } else if (sessionReadOnly) { + c.writeErrMessage(ErrorCode.ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION, "Cannot execute statement in a READ ONLY transaction."); break; } c.execute(sql, rs & 0xff); From 9f8676fd2a9545123ad7cefbc7e19b0a901d9a2f Mon Sep 17 00:00:00 2001 From: yanhuqing Date: Wed, 1 Nov 2017 11:42:07 +0800 Subject: [PATCH 2/5] not support set tx without session #309 --- .../com/actiontech/dble/server/handler/SetHandler.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/actiontech/dble/server/handler/SetHandler.java b/src/main/java/com/actiontech/dble/server/handler/SetHandler.java index c8de89fa2..6a2d8b348 100644 --- a/src/main/java/com/actiontech/dble/server/handler/SetHandler.java +++ b/src/main/java/com/actiontech/dble/server/handler/SetHandler.java @@ -88,6 +88,7 @@ public final class SetHandler { } } } + private static boolean handleSetStatement(String stmt, ServerConnection c, List>> contextTask) throws SQLSyntaxErrorException { SQLStatement statement = parseSQL(stmt); if (statement instanceof SQLSetStatement) { @@ -360,8 +361,16 @@ public final class SetHandler { case COLLATION_CONNECTION: return handleCollationConnection(c, valueExpr); case TX_READ_ONLY: + if (!stmt.toLowerCase().contains("session")) { + c.writeErrMessage(ErrorCode.ERR_NOT_SUPPORTED, "setting transaction without any SESSION or GLOBAL keyword is not supported now"); + return false; + } return handleTxReadOnly(c, valueExpr); case TX_ISOLATION: + if (!stmt.toLowerCase().contains("session")) { + c.writeErrMessage(ErrorCode.ERR_NOT_SUPPORTED, "setting transaction without any SESSION or GLOBAL keyword is not supported now"); + return false; + } return handleTxIsolation(c, valueExpr); case SYSTEM_VARIABLES: if (key.startsWith("@@")) { From 7ec42e0bf9f26e7f2bdf3776fe912a63d74cb808 Mon Sep 17 00:00:00 2001 From: yanhuqing Date: Wed, 1 Nov 2017 13:34:36 +0800 Subject: [PATCH 3/5] ER_COLLATION_CHARSET_MISMATCH #310 --- .../dble/backend/mysql/CharsetUtil.java | 15 ++++++++++ .../dble/server/handler/SetHandler.java | 29 ++++++++++++++----- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/actiontech/dble/backend/mysql/CharsetUtil.java b/src/main/java/com/actiontech/dble/backend/mysql/CharsetUtil.java index 74c4edcb1..fa3b23461 100644 --- a/src/main/java/com/actiontech/dble/backend/mysql/CharsetUtil.java +++ b/src/main/java/com/actiontech/dble/backend/mysql/CharsetUtil.java @@ -320,6 +320,21 @@ public final class CharsetUtil { } } + public static int getCollationIndexByCharset(String charset, String collation) { + if (collation == null || collation.length() == 0) { + return 0; + } else { + CollationInfo info = COLLATION_TO_INDEX.get(collation.toLowerCase()); + if (info == null) { + return 0; + } else if (!info.charset.equals(charset)) { + return -1; + } else { + return info.id; + } + } + } + public static int getCharsetDefaultIndex(String charset) { if (charset == null || charset.length() == 0) { return 0; diff --git a/src/main/java/com/actiontech/dble/server/handler/SetHandler.java b/src/main/java/com/actiontech/dble/server/handler/SetHandler.java index 6a2d8b348..f5e5e18ce 100644 --- a/src/main/java/com/actiontech/dble/server/handler/SetHandler.java +++ b/src/main/java/com/actiontech/dble/server/handler/SetHandler.java @@ -135,8 +135,13 @@ public final class SetHandler { private static boolean handleSetNamesInMultiStmt(ServerConnection c, String charset, String collate, List>> contextTask) { String[] charsetInfo = checkSetNames(charset, collate); if (charsetInfo != null) { - contextTask.add(new Pair<>(KeyType.NAMES, new Pair<>(charsetInfo[0], charsetInfo[1]))); - return true; + if (charsetInfo[1] != null) { + contextTask.add(new Pair<>(KeyType.NAMES, new Pair<>(charsetInfo[0], charsetInfo[1]))); + return true; + } else { + c.writeErrMessage(ErrorCode.ER_COLLATION_CHARSET_MISMATCH, "COLLATION '" + collate + "' is not valid for CHARACTER SET '" + charset + "'"); + return false; + } } else { c.writeErrMessage(ErrorCode.ER_UNKNOWN_CHARACTER_SET, "Unknown character set '" + charset + " or collate '" + collate + "'"); return false; @@ -146,9 +151,14 @@ public final class SetHandler { private static boolean handleSingleSetNames(String stmt, ServerConnection c, MySqlSetNamesStatement statement) { String[] charsetInfo = checkSetNames(statement.getCharSet(), statement.getCollate()); if (charsetInfo != null) { - c.setNames(charsetInfo[0], charsetInfo[1]); - c.write(c.writeToBuffer(OkPacket.OK, c.allocate())); - return true; + if (charsetInfo[1] != null) { + c.setNames(charsetInfo[0], charsetInfo[1]); + c.write(c.writeToBuffer(OkPacket.OK, c.allocate())); + return true; + } else { + c.writeErrMessage(ErrorCode.ER_COLLATION_CHARSET_MISMATCH, "COLLATION '" + statement.getCollate() + "' is not valid for CHARACTER SET '" + statement.getCharSet() + "'"); + return false; + } } else { c.writeErrMessage(ErrorCode.ER_UNKNOWN_CHARACTER_SET, "Unknown character set in statement '" + stmt + ""); return false; @@ -769,8 +779,13 @@ public final class SetHandler { collate = collate.toLowerCase(); if (collate.equals("default")) { collate = CharsetUtil.getDefaultCollation(charset); - } else if (CharsetUtil.getCollationIndex(collate) <= 0) { - return null; + } else { + int collateIndex = CharsetUtil.getCollationIndexByCharset(charset, collate); + if (collateIndex == 0) { + return null; + } else if (collateIndex < 0) { + return new String[]{charset, null}; + } } } return new String[]{charset, collate}; From 2040b45314085161ec4c54a809aa2e2377ad5c46 Mon Sep 17 00:00:00 2001 From: yanhuqing Date: Wed, 1 Nov 2017 14:03:03 +0800 Subject: [PATCH 4/5] set names default --- .../dble/server/handler/SetHandler.java | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/actiontech/dble/server/handler/SetHandler.java b/src/main/java/com/actiontech/dble/server/handler/SetHandler.java index f5e5e18ce..ba412754c 100644 --- a/src/main/java/com/actiontech/dble/server/handler/SetHandler.java +++ b/src/main/java/com/actiontech/dble/server/handler/SetHandler.java @@ -101,7 +101,7 @@ public final class SetHandler { } else if (statement instanceof MySqlSetNamesStatement) { MySqlSetNamesStatement setNamesStatement = (MySqlSetNamesStatement) statement; if (contextTask.size() > 0 || stmt.contains(",")) { - if (handleSetNamesInMultiStmt(c, setNamesStatement.getCharSet(), setNamesStatement.getCollate(), contextTask)) { + if (handleSetNamesInMultiStmt(c, setNamesStatement.isDefault(), setNamesStatement.getCharSet(), setNamesStatement.getCollate(), contextTask)) { int index = stmt.indexOf(","); String newStmt = "set " + stmt.substring(index + 1); return handleSetStatement(newStmt, c, contextTask); @@ -114,7 +114,7 @@ public final class SetHandler { } else if (statement instanceof MySqlSetCharSetStatement) { MySqlSetCharSetStatement setCharSetStatement = (MySqlSetCharSetStatement) statement; if (contextTask.size() > 0 || stmt.contains(",")) { - if (handleCharsetInMultiStmt(c, setCharSetStatement.getCharSet(), contextTask)) { + if (handleCharsetInMultiStmt(c, setCharSetStatement.isDefault(), setCharSetStatement.getCharSet(), contextTask)) { int index = stmt.indexOf(","); String newStmt = "set " + stmt.substring(index + 1); return handleSetStatement(newStmt, c, contextTask); @@ -132,8 +132,8 @@ public final class SetHandler { } } - private static boolean handleSetNamesInMultiStmt(ServerConnection c, String charset, String collate, List>> contextTask) { - String[] charsetInfo = checkSetNames(charset, collate); + private static boolean handleSetNamesInMultiStmt(ServerConnection c, boolean isDefault, String charset, String collate, List>> contextTask) { + String[] charsetInfo = checkSetNames(isDefault, charset, collate); if (charsetInfo != null) { if (charsetInfo[1] != null) { contextTask.add(new Pair<>(KeyType.NAMES, new Pair<>(charsetInfo[0], charsetInfo[1]))); @@ -149,7 +149,7 @@ public final class SetHandler { } private static boolean handleSingleSetNames(String stmt, ServerConnection c, MySqlSetNamesStatement statement) { - String[] charsetInfo = checkSetNames(statement.getCharSet(), statement.getCollate()); + String[] charsetInfo = checkSetNames(statement.isDefault(), statement.getCharSet(), statement.getCollate()); if (charsetInfo != null) { if (charsetInfo[1] != null) { c.setNames(charsetInfo[0], charsetInfo[1]); @@ -166,7 +166,7 @@ public final class SetHandler { } private static boolean handleSingleSetCharset(String stmt, ServerConnection c, MySqlSetCharSetStatement statement) { - String charset = getCharset(statement.getCharSet()); + String charset = getCharset(statement.isDefault(), statement.getCharSet()); if (charset != null) { c.setCharacterSet(charset); c.write(c.writeToBuffer(OkPacket.OK, c.allocate())); @@ -215,12 +215,12 @@ public final class SetHandler { case NAMES: { String charset = parseStringValue(valueExpr); //TODO:druid lost collation info - if (!handleSetNamesInMultiStmt(c, charset, null, contextTask)) return false; + if (!handleSetNamesInMultiStmt(c, false, charset, null, contextTask)) return false; break; } case CHARSET: { String charset = parseStringValue(valueExpr); - if (!handleCharsetInMultiStmt(c, charset, contextTask)) return false; + if (!handleCharsetInMultiStmt(c, false, charset, contextTask)) return false; break; } case CHARACTER_SET_CLIENT: @@ -260,8 +260,8 @@ public final class SetHandler { return true; } - private static boolean handleCharsetInMultiStmt(ServerConnection c, String charset, List>> contextTask) { - String charsetInfo = getCharset(charset); + private static boolean handleCharsetInMultiStmt(ServerConnection c, boolean isDefault, String charset, List>> contextTask) { + String charsetInfo = getCharset(isDefault, charset); if (charsetInfo != null) { contextTask.add(new Pair<>(KeyType.CHARSET, new Pair(charsetInfo, null))); return true; @@ -600,7 +600,8 @@ public final class SetHandler { private static boolean checkValue(SQLExpr valueExpr) { return (valueExpr instanceof SQLCharExpr) || (valueExpr instanceof SQLIdentifierExpr) || - (valueExpr instanceof SQLIntegerExpr) || (valueExpr instanceof SQLNumberExpr) || (valueExpr instanceof SQLBooleanExpr); + (valueExpr instanceof SQLIntegerExpr) || (valueExpr instanceof SQLNumberExpr) || + (valueExpr instanceof SQLBooleanExpr) || (valueExpr instanceof SQLDefaultExpr); } private static KeyType parseKeyType(String key, boolean origin, KeyType defaultVariables) { @@ -680,6 +681,9 @@ public final class SetHandler { } else if (valueExpr instanceof SQLBooleanExpr) { SQLBooleanExpr value = (SQLBooleanExpr) valueExpr; strValue = String.valueOf(value.getValue()); + } else if (valueExpr instanceof SQLDefaultExpr) { + SQLDefaultExpr value = (SQLDefaultExpr) valueExpr; + strValue = value.toString(); } return strValue; } @@ -695,6 +699,9 @@ public final class SetHandler { } else if (valueExpr instanceof SQLIntegerExpr) { SQLIntegerExpr value = (SQLIntegerExpr) valueExpr; strValue = value.getNumber().toString(); + } else if (valueExpr instanceof SQLDefaultExpr) { + SQLDefaultExpr value = (SQLDefaultExpr) valueExpr; + strValue = value.toString(); } return strValue; } @@ -751,24 +758,22 @@ public final class SetHandler { return ci > 0; } - private static String getCharset(String charset) { - charset = charset.toLowerCase(); - if (charset.equals("default")) { + private static String getCharset(boolean isDefault, String charset) { + if (isDefault || charset.toLowerCase().equals("default")) { charset = DbleServer.getInstance().getConfig().getSystem().getCharset(); } - charset = StringUtil.removeApostropheOrBackQuote(charset); + charset = StringUtil.removeApostropheOrBackQuote(charset.toLowerCase()); if (checkCharset(charset)) { return charset; } return null; } - private static String[] checkSetNames(String charset, String collate) { - charset = charset.toLowerCase(); - if (charset.equals("default")) { + private static String[] checkSetNames(boolean isDefault, String charset, String collate) { + if (isDefault || charset.toLowerCase().equals("default")) { charset = DbleServer.getInstance().getConfig().getSystem().getCharset(); } else { - charset = StringUtil.removeApostropheOrBackQuote(charset); + charset = StringUtil.removeApostropheOrBackQuote(charset.toLowerCase()); if (!checkCharset(charset)) { return null; } From bbcccf035e9f0940efa4aec2146b17e9c81e8b04 Mon Sep 17 00:00:00 2001 From: yanhuqing Date: Wed, 1 Nov 2017 15:44:47 +0800 Subject: [PATCH 5/5] set names syntax bug #310 --- .../dble/server/handler/SetHandler.java | 62 +++++++++++++------ .../dble/server/handler/SetHandlerTest.java | 23 ++++++- 2 files changed, 63 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/actiontech/dble/server/handler/SetHandler.java b/src/main/java/com/actiontech/dble/server/handler/SetHandler.java index ba412754c..0459713cb 100644 --- a/src/main/java/com/actiontech/dble/server/handler/SetHandler.java +++ b/src/main/java/com/actiontech/dble/server/handler/SetHandler.java @@ -32,6 +32,8 @@ import com.alibaba.druid.sql.parser.SQLStatementParser; import java.sql.SQLSyntaxErrorException; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * SetHandler @@ -101,8 +103,8 @@ public final class SetHandler { } else if (statement instanceof MySqlSetNamesStatement) { MySqlSetNamesStatement setNamesStatement = (MySqlSetNamesStatement) statement; if (contextTask.size() > 0 || stmt.contains(",")) { - if (handleSetNamesInMultiStmt(c, setNamesStatement.isDefault(), setNamesStatement.getCharSet(), setNamesStatement.getCollate(), contextTask)) { - int index = stmt.indexOf(","); + int index = stmt.indexOf(","); + if (handleSetNamesInMultiStmt(c, stmt.substring(0, index), setNamesStatement.isDefault(), setNamesStatement.getCharSet(), setNamesStatement.getCollate(), contextTask)) { String newStmt = "set " + stmt.substring(index + 1); return handleSetStatement(newStmt, c, contextTask); } else { @@ -132,35 +134,42 @@ public final class SetHandler { } } - private static boolean handleSetNamesInMultiStmt(ServerConnection c, boolean isDefault, String charset, String collate, List>> contextTask) { - String[] charsetInfo = checkSetNames(isDefault, charset, collate); + private static boolean handleSetNamesInMultiStmt(ServerConnection c, String stmt, boolean isDefault, String charset, String collate, List>> contextTask) { + String[] charsetInfo = checkSetNames(stmt, isDefault, charset, collate); if (charsetInfo != null) { - if (charsetInfo[1] != null) { - contextTask.add(new Pair<>(KeyType.NAMES, new Pair<>(charsetInfo[0], charsetInfo[1]))); - return true; - } else { - c.writeErrMessage(ErrorCode.ER_COLLATION_CHARSET_MISMATCH, "COLLATION '" + collate + "' is not valid for CHARACTER SET '" + charset + "'"); + if (charsetInfo[0] == null) { + c.writeErrMessage(ErrorCode.ER_UNKNOWN_CHARACTER_SET, "Unknown character set '" + charset + " or collate '" + collate + "'"); return false; } + if (charsetInfo[1] == null) { + c.writeErrMessage(ErrorCode.ER_COLLATION_CHARSET_MISMATCH, "COLLATION '" + collate + "' is not valid for CHARACTER SET '" + charset + "'"); + return false; + } else { + contextTask.add(new Pair<>(KeyType.NAMES, new Pair<>(charsetInfo[0], charsetInfo[1]))); + return true; + } } else { - c.writeErrMessage(ErrorCode.ER_UNKNOWN_CHARACTER_SET, "Unknown character set '" + charset + " or collate '" + collate + "'"); + c.writeErrMessage(ErrorCode.ER_PARSE_ERROR, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the SQL: " + stmt); return false; } } private static boolean handleSingleSetNames(String stmt, ServerConnection c, MySqlSetNamesStatement statement) { - String[] charsetInfo = checkSetNames(statement.isDefault(), statement.getCharSet(), statement.getCollate()); + String[] charsetInfo = checkSetNames(stmt, statement.isDefault(), statement.getCharSet(), statement.getCollate()); if (charsetInfo != null) { - if (charsetInfo[1] != null) { + if (charsetInfo[0] == null) { + c.writeErrMessage(ErrorCode.ER_UNKNOWN_CHARACTER_SET, "Unknown character set in statement '" + stmt + ""); + return false; + } else if (charsetInfo[1] == null) { + c.writeErrMessage(ErrorCode.ER_COLLATION_CHARSET_MISMATCH, "COLLATION '" + statement.getCollate() + "' is not valid for CHARACTER SET '" + statement.getCharSet() + "'"); + return false; + } else { c.setNames(charsetInfo[0], charsetInfo[1]); c.write(c.writeToBuffer(OkPacket.OK, c.allocate())); return true; - } else { - c.writeErrMessage(ErrorCode.ER_COLLATION_CHARSET_MISMATCH, "COLLATION '" + statement.getCollate() + "' is not valid for CHARACTER SET '" + statement.getCharSet() + "'"); - return false; } } else { - c.writeErrMessage(ErrorCode.ER_UNKNOWN_CHARACTER_SET, "Unknown character set in statement '" + stmt + ""); + c.writeErrMessage(ErrorCode.ER_PARSE_ERROR, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the SQL: " + stmt); return false; } } @@ -215,7 +224,8 @@ public final class SetHandler { case NAMES: { String charset = parseStringValue(valueExpr); //TODO:druid lost collation info - if (!handleSetNamesInMultiStmt(c, false, charset, null, contextTask)) return false; + if (!handleSetNamesInMultiStmt(c, "SET NAMES " + charset, false, charset, null, contextTask)) + return false; break; } case CHARSET: { @@ -769,13 +779,25 @@ public final class SetHandler { return null; } - private static String[] checkSetNames(boolean isDefault, String charset, String collate) { + + private static boolean checkSetNamesSyntax(String stmt) { + //druid parser can't find syntax error,use regex to check again, but it is not strict + String regex = "^\\s*set\\s+names\\s+[`\\']?[a-zA-Z_0-9]+[`\\']?(\\s+collate\\s+[`\\']?[a-zA-Z_0-9]+[`\\']?)?;?\\s*$"; + Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + Matcher ma = pattern.matcher(stmt); + return ma.matches(); + } + + private static String[] checkSetNames(String stmt, boolean isDefault, String charset, String collate) { + if (collate == null && !(checkSetNamesSyntax(stmt))) { + return null; + } if (isDefault || charset.toLowerCase().equals("default")) { charset = DbleServer.getInstance().getConfig().getSystem().getCharset(); } else { charset = StringUtil.removeApostropheOrBackQuote(charset.toLowerCase()); if (!checkCharset(charset)) { - return null; + return new String[]{null, null}; } } if (collate == null) { @@ -787,7 +809,7 @@ public final class SetHandler { } else { int collateIndex = CharsetUtil.getCollationIndexByCharset(charset, collate); if (collateIndex == 0) { - return null; + return new String[]{null, null}; } else if (collateIndex < 0) { return new String[]{charset, null}; } diff --git a/src/test/java/com/actiontech/dble/server/handler/SetHandlerTest.java b/src/test/java/com/actiontech/dble/server/handler/SetHandlerTest.java index 894243899..fce49949f 100644 --- a/src/test/java/com/actiontech/dble/server/handler/SetHandlerTest.java +++ b/src/test/java/com/actiontech/dble/server/handler/SetHandlerTest.java @@ -12,8 +12,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class SetHandlerTest { - - @Test public void testConvertCharsetKeyWord() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Method convertCharsetKeyWord = SetHandler.class.getDeclaredMethod("convertCharsetKeyWord", String.class); @@ -23,4 +21,25 @@ public class SetHandlerTest { Assert.assertEquals("SET names utf8,character set UTF8,character set gbk,@@tx_readonly=1", convertCharsetKeyWord.invoke(null, "SET names utf8,CHARSET UTF8,CHARSET gbk,@@tx_readonly=1")); Assert.assertEquals("SET names utf8,character set UTF8,character set gbk,@@tx_readonly=1", convertCharsetKeyWord.invoke(null, "SET names utf8,CHARSET UTF8,CHARSET gbk,@@tx_readonly=1")); } + + @Test + public void testCheckSetNamesSyntax() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method checkSetNamesSyntax = SetHandler.class.getDeclaredMethod("checkSetNamesSyntax", String.class); + checkSetNamesSyntax.setAccessible(true); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "SET NAMES utf8")); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "set names utf8")); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "set names 'utf8'")); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "set names `utf8`")); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "set names DEFAULT")); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "set names utf8 COLLATE utf8_bin")); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "set names utf8 COLLATE default")); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "set names 'utf8' COLLATE utf8_bin")); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "set names `utf8` COLLATE default")); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "set names utf8 COLLATE 'utf8_bin'")); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "set names utf8 COLLATE `utf8_bin`")); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "set names 'utf8' COLLATE 'utf8_bin'")); + Assert.assertEquals(true, checkSetNamesSyntax.invoke(null, "set names `utf8` COLLATE `utf8_bin`")); + Assert.assertEquals(false, checkSetNamesSyntax.invoke(null, "set names utf8 2")); + Assert.assertEquals(false, checkSetNamesSyntax.invoke(null, "set names utf8 COLLATION utf8_bin")); + } }