{"record":{"id":"38d8336f16234fa1","repo":"MyCATApache/Mycat-Server","slug":"joinkey-not-provided-tc-getjoinkey","errorCode":null,"errorMessage":"\"joinKey not provided :\" + tc.getJoinKey()+ \",\" + insertStmt","messagePattern":"\"joinKey not provided :\" \\+ tc\\.getJoinKey\\(\\)\\+ \",\" \\+ insertStmt","errorType":"exception","errorClass":"SQLNonTransientException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/mycat/route/parser/druid/impl/DruidInsertParser.java","lineNumber":128,"sourceCode":"\t/**\n\t * 是否为批量插入：insert into ...values (),()...或 insert into ...select.....\n\t * @param insertStmt\n\t * @return\n\t */\n\tprivate boolean isMultiInsert(MySqlInsertStatement insertStmt) {\n\t\treturn (insertStmt.getValuesList() != null && insertStmt.getValuesList().size() > 1) || insertStmt.getQuery() != null;\n\t}\n\t\n\tprivate RouteResultset parserChildTable(SchemaConfig schema, RouteResultset rrs,\n\t\t\tString tableName, MySqlInsertStatement insertStmt) throws SQLNonTransientException {\n\t\tTableConfig tc = schema.getTables().get(tableName);\n\t\t\n\t\tString joinKey = tc.getJoinKey();\n\t\tint joinKeyIndex = getJoinKeyIndex(insertStmt.getColumns(), joinKey);\n\t\tif(joinKeyIndex == -1) {\n\t\t\tString inf = \"joinKey not provided :\" + tc.getJoinKey()+ \",\" + insertStmt;\n\t\t\tLOGGER.warn(inf);\n\t\t\tthrow new SQLNonTransientException(inf);\n\t\t}\n\t\tif(isMultiInsert(insertStmt)) {\n\t\t\tString msg = \"ChildTable multi insert not provided\" ;\n\t\t\tLOGGER.warn(msg);\n\t\t\tthrow new SQLNonTransientException(msg);\n\t\t}\n\t\t\n\t\tString joinKeyVal = insertStmt.getValues().getValues().get(joinKeyIndex).toString();\n\n\t\t\n\t\tString sql = insertStmt.toString();\n\t\t\n\t\t// try to route by ER parent partion key\n\t\tRouteResultset theRrs = RouterUtil.routeByERParentKey(null,schema, ServerParse.INSERT,sql, rrs, tc,joinKeyVal);\n\t\tif (theRrs != null) {\n\t\t\trrs.setFinishedRoute(true);\n\t\t\treturn theRrs;\n\t\t}","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/MyCATApache/Mycat-Server/blob/65f8d8beb752f935752f2a0eec0ab017facab9ef/src/main/java/io/mycat/route/parser/druid/impl/DruidInsertParser.java#L110-L146","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Include the join key column (parent's key, e.g. order_id) explicitly in the INSERT column list and provide a value","Verify the joinKey attribute on the child <table> in schema.xml matches a real column name","If the join key should default (e.g. via trigger/auto-fill), instead insert with the column provided explicitly — Mycat cannot infer it"],"exampleFix":"// before\nINSERT INTO order_detail (id, item, price) VALUES (1, 'x', 9.9);\n// after\nINSERT INTO order_detail (id, order_id, item, price) VALUES (1, 100, 'x', 9.9);","handlingStrategy":"validation","validationCode":"// ensure join key is present before insert into child table\nList<String> declaredColumns = extractInsertColumns(sql);\nString joinKey = childTableConfig.getJoinKey();\nif (!declaredColumns.contains(joinKey.toUpperCase())) {\n    throw new IllegalArgumentException(\"Insert must include joinKey column: \" + joinKey);\n}","typeGuard":"static boolean hasJoinKey(InsertStatement ins, TableConfig tc) {\n    return tc.getJoinKey() != null && ins.getColumns().stream()\n        .map(c -> c.toString().toUpperCase())\n        .anyMatch(c -> c.equals(tc.getJoinKey().toUpperCase()));\n}","tryCatchPattern":"try {\n    insert(childRows);\n} catch (SQLNonTransientException e) {\n    if (e.getMessage().startsWith(\"joinKey not provided\")) {\n        throw new IllegalArgumentException(\"Child-table insert must include join key column \" + joinKey, e);\n    }\n    throw e;\n}","preventionTips":["Always list columns explicitly in INSERTs into child tables, including the join key","Review schema.xml joinKey attributes against actual column names","Warn in code review when child-table inserts omit any columns"],"tags":["sql","mycat","er-partition","insert"],"backgroundTag":"missing-required-argument","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"}