MyCATApache/Mycat-Server · warning · SQLNonTransientException

TODO:insert into .... select .... not supported!

Error message

TODO:insert into .... select .... not supported!

What it means

DruidInsertParser does not implement routing for INSERT INTO ... SELECT statements. When the parsed SQLInsertStatement has a query part (a SELECT source instead of VALUES), it throws SQLNonTransientException with a literal TODO message.

Solutions

  1. Rewrite as a plain INSERT with explicit VALUES
  2. Split into SELECT first, then INSERT per row from the application
  3. Execute the INSERT...SELECT directly on the datanode's MySQL, bypassing MyCat routing
  4. Upgrade MyCat versions — check release notes for INSERT-SELECT support

Example fix

// before
INSERT INTO t SELECT id, name FROM src;
// after
SELECT id, name FROM src; -- then INSERT INTO t VALUES (...) per row from client
Defensive patterns

Strategy: try-catch

Validate before calling

if (sql.matches("(?is)\\s*insert\\s+.*\\bselect\\b.*")) throw new UnsupportedSqlException("INSERT...SELECT not supported by MyCat router");

Try / catch

try { route(sql); } catch (SQLNonTransientException e) { if (e.getMessage().contains("insert into .... select")) { fallbackToClientSideInsert(sql); } else throw e; }

Prevention

When it happens

Trigger: statementParse -> parserBatchInsert (or the insert parse path) receives `INSERT INTO t SELECT ...` — insertStmt.getQuery() != null.

Common situations: Migration scripts using INSERT...SELECT to copy data; ORM or ETL tools generating INSERT-SELECT; developers assuming MyCat passes arbitrary SQL through to MySQL.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11). Data as JSON: /api/errors/372675f16c9635d2. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/io/mycat/route/parser/druid/impl/DruidInsertParser.java:324

						nodes[count] = new RouteResultsetNode(tableConfig.getDataNodes().get(nodeIndex),
								rrs.getSqlType(),insertStmt.toString());
					}
					
					if(algorithm instanceof SlotFunction) {
						nodes[count].setSlot(slotsMap.get(nodeIndex));
						nodes[count].setStatement(ParseUtil.changeInsertAddSlot(nodes[count].getStatement(),nodes[count].getSlot()));
					}
					nodes[count++].setSource(rrs);

				}
				rrs.setNodes(nodes);
				rrs.setFinishedRoute(true);

			}
		} else if(insertStmt.getQuery() != null) { // insert into .... select ....
			String msg = "TODO:insert into .... select .... not supported!";
			LOGGER.warn(msg);
			throw new SQLNonTransientException(msg);
		}
	}

	private String getShardingValue(SQLExpr expr) throws SQLNonTransientException {
		String shardingValue = null;
		if(expr instanceof SQLIntegerExpr) {
			SQLIntegerExpr intExpr = (SQLIntegerExpr)expr;
			shardingValue = intExpr.getNumber() + "";
		} else if (expr instanceof SQLCharExpr) {
			SQLCharExpr charExpr = (SQLCharExpr)expr;
			shardingValue = charExpr.getText();
		} else if (expr instanceof SQLMethodInvokeExpr) {
			SQLMethodInvokeExpr methodInvokeExpr = (SQLMethodInvokeExpr)expr;
			try {
				shardingValue = tryInvokeSQLMethod(methodInvokeExpr);
			}catch (Exception e){
				LOGGER.error("",e);
			}

View on GitHub (pinned to 65f8d8beb7)