{"record":{"id":"9a8fa456eac61910","repo":"MyCATApache/Mycat-Server","slug":"lock-type-must-be-write-or-read","errorCode":null,"errorMessage":"lock type must be write or read","messagePattern":"lock type must be write or read","errorType":"exception","errorClass":"SQLNonTransientException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/mycat/route/parser/druid/impl/DruidLockTableParser.java","lineNumber":39,"sourceCode":" * @author songdabin\n */\npublic class DruidLockTableParser extends DefaultDruidParser implements DruidParser {\n\t@Override\n\tpublic void statementParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt)\n\t\t\tthrows SQLNonTransientException {\n\t\tMySqlLockTableStatement lockTableStat = (MySqlLockTableStatement)stmt;\n\t\tString table = lockTableStat.getItems().get(0).getTableSource().toString().toUpperCase();\n\t\tTableConfig tableConfig = schema.getTables().get(table);\n\t\tif (tableConfig == null) {\n\t\t\tString msg = \"can't find table define of \" + table + \" in schema:\" + schema.getName();\n\t\t\tLOGGER.warn(msg);\n\t\t\tthrow new SQLNonTransientException(msg);\n\t\t}\n\t\tLockType lockType = lockTableStat.getItems().get(0).getLockType();\n\t\tif (LockType.WRITE != lockType && LockType.READ != lockType) {\n\t\t\tString msg = \"lock type must be write or read\";\n\t\t\tLOGGER.warn(msg);\n\t\t\tthrow new SQLNonTransientException(msg);\n\t\t}\n\t\tList<String> dataNodes = tableConfig.getDataNodes();\n\t\tRouteResultsetNode[] nodes = new RouteResultsetNode[dataNodes.size()];\n\t\tfor (int i = 0; i < dataNodes.size(); i ++) {\n\t\t\tnodes[i] = new RouteResultsetNode(dataNodes.get(i), ServerParse.LOCK, stmt.toString());\n\t\t}\n\t\trrs.setNodes(nodes);\n\t\trrs.setFinishedRoute(true);\n\t}\n\t\n\t@Override\n\tpublic void visitorParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt, MycatSchemaStatVisitor visitor)\n\t\t\tthrows SQLNonTransientException {\n\t\t// 对于lock tables table1 write, table2 read类型的多表锁语句，DruidParser只能解析出table1，\n\t\t// 由于多表锁在分布式场景处理逻辑繁琐，且应用场景较少，因此在此处对这种锁表语句进行拦截。\n\t\t// 多表锁的语句在语义上会有\",\"，这里以此为判断依据\n\t\tString sql = rrs.getStatement();\n\t\tsql = sql.replaceAll(\"\\n\", \" \").replaceAll(\"\\t\", \" \");","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/MyCATApache/Mycat-Server/blob/65f8d8beb752f935752f2a0eec0ab017facab9ef/src/main/java/io/mycat/route/parser/druid/impl/DruidLockTableParser.java#L21-L57","documentation":"DruidLockTableParser only supports MySQL lock types WRITE and READ on the first lock item. Any other LockType (e.g. LOW_PRIORITY WRITE aliases the parser doesn't accept, or FOLD/other parse results) causes SQLNonTransientException 'lock type must be write or read'.","triggerScenarios":"statementParse on LOCK TABLES ... where items.get(0).getLockType() is neither LockType.WRITE nor LockType.READ — e.g. `LOCK TABLES t LOW_PRIORITY WRITE` or an unparsed lock qualifier.","commonSituations":"Scripts using LOW_PRIORITY/other MySQL lock modifiers; client drivers emitting extended lock syntax; copy-pasted Oracle/Postgres lock statements.","solutions":["Rewrite the statement to plain `LOCK TABLES t WRITE` or `LOCK TABLES t READ`","Remove LOW_PRIORITY/other modifiers before the lock keyword","If you need priority semantics, apply them at the MySQL node directly rather than through MyCat"],"exampleFix":"// before\nLOCK TABLES t LOW_PRIORITY WRITE;\n// after\nLOCK TABLES t WRITE;","handlingStrategy":"validation","validationCode":"if (!sql.matches(\"(?is)\\\\s*lock\\\\s+tables?\\\\s+\\\\S+\\\\s+(READ|WRITE)\\\\s*;?\")) throw new IllegalArgumentException(\"only READ/WRITE lock types supported\");","typeGuard":null,"tryCatchPattern":"try { route(sql); } catch (SQLNonTransientException e) { if (e.getMessage().equals(\"lock type must be write or read\")) { rewriteToPlainLock(sql); } else throw e; }","preventionTips":["Use only plain READ/WRITE in LOCK TABLES statements","Strip LOW_PRIORITY and other modifiers before routing through MyCat","Test lock statements against MyCat, not just raw MySQL"],"tags":["sql","lock","unsupported","syntax"],"backgroundTag":"invalid-enum-value","analyzedSha":"65f8d8beb752f935752f2a0eec0ab017facab9ef","analyzedAt":"2026-09-11T00:12:21.696Z","contentChangedAt":"2026-09-11T00:12:21.696Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}