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

joinKey not provided

Error message

joinKey not provided :${tc.getJoinKey()},${insertStmt}

What it means

When inserting into a child (ER) table, Mycat requires the joinKey column (the FK referencing the parent's partition column) to be present in the INSERT column list, because routing needs its value. getJoinKeyIndex returns -1 when the parsed insert's columns don't include joinKey, and Mycat throws SQLNonTransientException naming the missing joinKey and the statement.

Solutions

  1. Add the joinKey column and its value explicitly to the INSERT column list
  2. Verify joinKey in schema.xml matches the actual column name exactly (case included)
  3. Configure the ORM to always include the FK column in inserts (no 'dynamic-insert' omission for that column)
  4. If the column genuinely isn't needed, remove the childTable/parentKey/joinKey ER config so the table routes as a normal sharded table

Example fix

// before
INSERT INTO order_detail(item) VALUES ('x');
// after
INSERT INTO order_detail(order_id, item) VALUES (42, 'x');
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the joinKey column is in the insert column list before executing
Set<String> cols = insertColumns.stream().map(String::toLowerCase).collect(toSet());
if (!cols.contains(joinKey.toLowerCase())) throw new IllegalStateException("INSERT must include joinKey " + joinKey);

Try / catch

catch (SQLNonTransientException e) { if (e.getMessage().startsWith("joinKey not provided")) { /* add joinKey column and retry */ } throw e; }

Prevention

When it happens

Trigger: INSERT into a childTable where tc.getJoinKey() is defined but the insert's column list omits that column (value supplied by trigger/default/ORM, or column name cased differently).

Common situations: ORMs (Hibernate/JPA) omitting columns with default values; relying on DB triggers or defaults to fill the FK; column-name case mismatch between SQL and schema.xml joinKey; explicit column lists missing the FK in bulk-load scripts.

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/274f2e4a7ed89aa4. Report an issue: GitHub.

Appendix: source

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

			MySqlInsertStatement insertStmt = (MySqlInsertStatement) stmt;
			String tableName = insertStmt.getTableName().getSimpleName().toUpperCase();
			final TableConfig tc = schema.getTables().get(tableName);

			if (null != tc && tc.isChildTable()) {
				erFlag = true;

				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);

View on GitHub (pinned to 65f8d8beb7)