MyCATApache/Mycat-Server · error · SQLNonTransientException

"joinKey not provided :" + tc.getJoinKey()+ "," + insertStmt

Error message

"joinKey not provided :" + tc.getJoinKey()+ "," + insertStmt

What it means

When inserting into a child (ER-join) table, Mycat requires the parent's join key column to be present in the INSERT column list so it can derive the child row's datanode from the parent row. If the column list lacks joinKey, parserChildTable cannot compute the route and throws.

Solutions

  1. Include the join key column (parent's key, e.g. order_id) explicitly in the INSERT column list and provide a value
  2. Verify the joinKey attribute on the child <table> in schema.xml matches a real column name
  3. If the join key should default (e.g. via trigger/auto-fill), instead insert with the column provided explicitly — Mycat cannot infer it

Example fix

// before
INSERT INTO order_detail (id, item, price) VALUES (1, 'x', 9.9);
// after
INSERT INTO order_detail (id, order_id, item, price) VALUES (1, 100, 'x', 9.9);
Defensive patterns

Strategy: validation

Validate before calling

// ensure join key is present before insert into child table
List<String> declaredColumns = extractInsertColumns(sql);
String joinKey = childTableConfig.getJoinKey();
if (!declaredColumns.contains(joinKey.toUpperCase())) {
    throw new IllegalArgumentException("Insert must include joinKey column: " + joinKey);
}

Type guard

static boolean hasJoinKey(InsertStatement ins, TableConfig tc) {
    return tc.getJoinKey() != null && ins.getColumns().stream()
        .map(c -> c.toString().toUpperCase())
        .anyMatch(c -> c.equals(tc.getJoinKey().toUpperCase()));
}

Try / catch

try {
    insert(childRows);
} catch (SQLNonTransientException e) {
    if (e.getMessage().startsWith("joinKey not provided")) {
        throw new IllegalArgumentException("Child-table insert must include join key column " + joinKey, e);
    }
    throw e;
}

Prevention

When it happens

Trigger: `INSERT INTO child (...) VALUES (...)` where tc.isChildTable() is true and getJoinKeyIndex(insertStmt.getColumns(), joinKey) returns -1 — i.e. the join key column declared in schema.xml (joinKey attr) is not among the explicitly listed insert columns.

Common situations: Inserting into an ER-partitioned order-detail table without supplying parent_id column; omitting columns from the INSERT column list (not using column-list-less VALUES matching full table); joinKey misconfigured in schema.xml pointing at a column never inserted.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

	/**
	 * 是否为批量插入:insert into ...values (),()...或 insert into ...select.....
	 * @param insertStmt
	 * @return
	 */
	private boolean isMultiInsert(MySqlInsertStatement insertStmt) {
		return (insertStmt.getValuesList() != null && insertStmt.getValuesList().size() > 1) || insertStmt.getQuery() != null;
	}
	
	private RouteResultset parserChildTable(SchemaConfig schema, RouteResultset rrs,
			String tableName, MySqlInsertStatement insertStmt) throws SQLNonTransientException {
		TableConfig tc = schema.getTables().get(tableName);
		
		String joinKey = tc.getJoinKey();
		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);
		}
		
		String joinKeyVal = insertStmt.getValues().getValues().get(joinKeyIndex).toString();

		
		String sql = insertStmt.toString();
		
		// try to route by ER parent partion key
		RouteResultset theRrs = RouterUtil.routeByERParentKey(null,schema, ServerParse.INSERT,sql, rrs, tc,joinKeyVal);
		if (theRrs != null) {
			rrs.setFinishedRoute(true);
			return theRrs;
		}

View on GitHub (pinned to 65f8d8beb7)