MyCATApache/Mycat-Server · error · java.sql.SQLNonTransientException

ChildTable multi insert not provided

Error message

ChildTable multi insert not provided

What it means

Child (ER) tables support only single-row inserts: routing depends on one joinKey value taken from the single VALUES tuple. isMultiInsert detects multi-row VALUES or insert-from-select, and Mycat refuses with SQLNonTransientException because it cannot route a batch to potentially multiple parent nodes in one statement.

Solutions

  1. Rewrite as one single-row INSERT per values tuple (batch them as separate statements/pipelined requests)
  2. Use a stored procedure or Mycat-compatible bulk path for loads, inserting child rows one at a time
  3. Temporarily disable the ER (childTable) config and shard the table directly if single-row inserts are unacceptable
  4. Split the application's batch insert into a loop sending individual statements

Example fix

// before
INSERT INTO order_detail(order_id,item) VALUES (1,'a'),(2,'b');
// after
INSERT INTO order_detail(order_id,item) VALUES (1,'a');
INSERT INTO order_detail(order_id,item) VALUES (2,'b');
Defensive patterns

Strategy: validation

Validate before calling

// Split multi-row inserts into single-row statements before sending to a child table
List<String> singles = valuesTuples.stream()
    .map(t -> "INSERT INTO " + table + " (" + cols + ") VALUES (" + t + ")")
    .collect(toList());

Try / catch

catch (SQLNonTransientException e) { if (e.getMessage().equals("ChildTable multi insert not provided")) { /* fallback: per-row insert loop */ } throw e; }

Prevention

When it happens

Trigger: INSERT INTO child (...) VALUES (...),(...)... or INSERT ... SELECT ... against a table configured as childTable with a joinKey; RouterUtil.routeByER's isMultiInsert check.

Common situations: Bulk data-load scripts and seed scripts using multi-row inserts; ORM batch inserts with per-row values; migration tools (mysqldump replay) inserting many rows per statement into ER child tables.

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/939c55effe523c01. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/io/mycat/route/util/RouterUtil.java:1937

				String sql = insertStmt.toString();

				final RouteResultset rrs = new RouteResultset(sql, ServerParse.INSERT);
				String joinKey = tc.getJoinKey();
				//因为是Insert语句,用MySqlInsertStatement进行parse
//				MySqlInsertStatement insertStmt = (MySqlInsertStatement) (new MySqlStatementParser(origSQL)).parseInsert();
				//判断条件完整性,取得解析后语句列中的joinkey列的index
				int joinKeyIndex = getJoinKeyIndex(insertStmt.getColumns(), joinKey);
				if (joinKeyIndex == -1) {
					String inf = "joinKey not provided :" + tc.getJoinKey() + "," + insertStmt;
					LOGGER.warn(inf);
					throw new SQLNonTransientException(inf);
				}
				//子表不支持批量插入
				if (isMultiInsert(insertStmt)) {
					String msg = "ChildTable multi insert not provided";
					LOGGER.warn(msg);
					throw new SQLNonTransientException(msg);
				}
				//取得joinkey的值
				String joinKeyVal = insertStmt.getValues().getValues().get(joinKeyIndex).toString();
				//解决bug #938,当关联字段的值为char类型时,去掉前后"'"
				String realVal = joinKeyVal;
				if (joinKeyVal.startsWith("'") && joinKeyVal.endsWith("'") && joinKeyVal.length() > 2) {
					realVal = joinKeyVal.substring(1, joinKeyVal.length() - 1);
				}

				// try to route by ER parent partion key
				//如果是二级子表(父表不再有父表),并且分片字段正好是joinkey字段,调用routeByERParentKey
				RouteResultset theRrs = RouterUtil.routeByERParentKey(sc, schema, ServerParse.INSERT, sql, rrs, tc, realVal);
				if (theRrs != null) {
					boolean processedInsert=false;
					//判断是否需要全局序列号
					if ( sc!=null && tc.isAutoIncrement()) {
						String primaryKey = tc.getPrimaryKey();
						processedInsert=processInsert(sc,schema,ServerParse.INSERT,sql,tc.getName(),primaryKey);

View on GitHub (pinned to 65f8d8beb7)