{"record":{"id":"556176c80b673018","repo":"MyCATApache/Mycat-Server","slug":"todo-insert-into-select-not-supported-556176","errorCode":null,"errorMessage":"\"TODO:insert into .... select .... not supported!\"","messagePattern":"\"TODO:insert into \\.\\.\\.\\. select \\.\\.\\.\\. not supported!\"","errorType":"exception","errorClass":"SQLNonTransientException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/mycat/route/parser/druid/impl/DruidInsertParser.java","lineNumber":324,"sourceCode":"\t\t\t\t\t\tnodes[count] = new RouteResultsetNode(tableConfig.getDataNodes().get(nodeIndex),\n\t\t\t\t\t\t\t\trrs.getSqlType(),insertStmt.toString());\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\tif(algorithm instanceof SlotFunction) {\n\t\t\t\t\t\tnodes[count].setSlot(slotsMap.get(nodeIndex));\n\t\t\t\t\t\tnodes[count].setStatement(ParseUtil.changeInsertAddSlot(nodes[count].getStatement(),nodes[count].getSlot()));\n\t\t\t\t\t}\n\t\t\t\t\tnodes[count++].setSource(rrs);\n\n\t\t\t\t}\n\t\t\t\trrs.setNodes(nodes);\n\t\t\t\trrs.setFinishedRoute(true);\n\n\t\t\t}\n\t\t} else if(insertStmt.getQuery() != null) { // insert into .... select ....\n\t\t\tString msg = \"TODO:insert into .... select .... not supported!\";\n\t\t\tLOGGER.warn(msg);\n\t\t\tthrow new SQLNonTransientException(msg);\n\t\t}\n\t}\n\n\tprivate String getShardingValue(SQLExpr expr) throws SQLNonTransientException {\n\t\tString shardingValue = null;\n\t\tif(expr instanceof SQLIntegerExpr) {\n\t\t\tSQLIntegerExpr intExpr = (SQLIntegerExpr)expr;\n\t\t\tshardingValue = intExpr.getNumber() + \"\";\n\t\t} else if (expr instanceof SQLCharExpr) {\n\t\t\tSQLCharExpr charExpr = (SQLCharExpr)expr;\n\t\t\tshardingValue = charExpr.getText();\n\t\t} else if (expr instanceof SQLMethodInvokeExpr) {\n\t\t\tSQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr)expr;\n\t\t\ttry {\n\t\t\t\tshardingValue = tryInvokeSQLMethod(methodInvokeExpr);\n\t\t\t}catch (Exception e){\n\t\t\t\tLOGGER.error(\"\",e);\n\t\t\t}","sourceCodeStart":306,"sourceCodeEnd":342,"githubUrl":"https://github.com/MyCATApache/Mycat-Server/blob/65f8d8beb752f935752f2a0eec0ab017facab9ef/src/main/java/io/mycat/route/parser/druid/impl/DruidInsertParser.java#L306-L342","documentation":"Mycat does not implement routing for INSERT INTO ... SELECT .... parserBatchInsert detects insertStmt.getQuery() != null and throws SQLNonTransientException with a TODO message, marking the feature as unimplemented.","triggerScenarios":"Executing `INSERT INTO t1 (cols) SELECT ... FROM t2` through Mycat — the insert statement carries a query body instead of VALUES.","commonSituations":"Data-migration/ETL scripts copying between tables; dedup/archival jobs (INSERT INTO archive SELECT ...); porting stored-procedure-style SQL from plain MySQL to Mycat.","solutions":["Split into SELECT the data in the application, then batch INSERT the rows via Mycat","Run the INSERT...SELECT directly on the backend MySQL node(s) if both tables live on the same datanode","Precompute the SELECT into a temp staging file/table and insert from the application","Check newer Mycat forks/versions that may add INSERT...SELECT support"],"exampleFix":"// before\nINSERT INTO t2 (a,b) SELECT a,b FROM t1 WHERE x > 10;\n// after\n-- app-side: rows = SELECT a,b FROM t1 WHERE x > 10\nINSERT INTO t2 (a,b) VALUES (?,?),(?,?); -- batch insert of fetched rows","handlingStrategy":"try-catch","validationCode":"// reject INSERT ... SELECT before routing\nString normalized = sql.replaceAll(\"\\\\s+\", \" \").toUpperCase();\nif (normalized.startsWith(\"INSERT\") && normalized.contains(\"SELECT\")) {\n    throw new IllegalArgumentException(\"INSERT ... SELECT not supported via Mycat; split it\");\n}","typeGuard":"static boolean isInsertSelect(SQLStatement stmt) {\n    return stmt instanceof MySqlInsertStatement\n        && ((MySqlInsertStatement) stmt).getQuery() != null;\n}","tryCatchPattern":"try {\n    execute(sql);\n} catch (SQLNonTransientException e) {\n    if (e.getMessage().contains(\"insert into .... select .... not supported\")) {\n        // fallback: fetch rows client-side, then batch insert\n        List<Row> rows = selectAll(sourceSql);\n        batchInsert(target, rows);\n        return;\n    }\n    throw e;\n}","preventionTips":["Never use INSERT ... SELECT through Mycat; split into read + batch write","Run ETL copy jobs directly on backend nodes when possible","Add a SQL lint rule in CI flagging INSERT...SELECT for Mycat-routed datasources"],"tags":["sql","mycat","unsupported-feature","insert-select"],"backgroundTag":"unsupported-operation","analyzedSha":"65f8d8beb752f935752f2a0eec0ab017facab9ef","analyzedAt":"2026-09-11T00:12:21.696Z","contentChangedAt":"2026-09-11T00:12:21.696Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}