MyCATApache/Mycat-Server · error · RuntimeException
number of columns error
Error message
number of columns error
What it means
InsertData() validates an INSERT statement before building MongoDB BasicDBObjects. If the VALUES clause contains zero value expressions, it throws RuntimeException("number of columns error"). This guards against INSERT statements with an empty VALUES list, which cannot be translated to a Mongo document insert.
Solutions
- Ensure every INSERT statement includes at least one row of values
- Validate the generated SQL before executing: values list must be non-empty
- Catch RuntimeException around executeUpdate and surface a clearer 'empty VALUES clause' message to the caller
- If rows are optional, skip execution when the values list is empty instead of issuing the INSERT
Example fix
// before
String sql = "INSERT INTO users (name) VALUES ()";
stmt.executeUpdate(sql); // throws
// after
if (values.length == 0) {
return 0; // nothing to insert
}
stmt.executeUpdate("INSERT INTO users (name) VALUES ('" + values[0] + "')"); Defensive patterns
Strategy: validation
Validate before calling
SQLStatement st = SQLUtils.parseSingleStatement(sql, dbType);
if (st instanceof SQLInsertStatement) {
SQLInsertStatement ins = (SQLInsertStatement) st;
if (ins.getValues() == null || ins.getValues().getValues().isEmpty()) {
throw new IllegalArgumentException("INSERT requires a non-empty VALUES clause");
}
} Try / catch
try {
return stmt.executeUpdate(sql);
} catch (RuntimeException e) {
if ("number of columns error".equals(e.getMessage())) {
throw new SQLException("INSERT has empty VALUES clause: " + sql, e);
}
throw e;
} Prevention
- Validate INSERT SQL with a parser before execution
- Skip execution entirely when there are zero rows to insert
- Avoid building INSERT strings by string concatenation; use a builder that pairs columns and values
When it happens
Trigger: Executing INSERT INTO t () VALUES () or any INSERT whose values clause parses to an empty list, via executeUpdate on the MongoDB handler.
Common situations: Dynamically generated INSERT SQL where the value list was filtered to empty; SQL builders emitting INSERT with no rows; mistyped SQL with missing VALUES contents.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- number of values and columns have to match
- not a query sql statement
- not where of sql
- like SQL error
- Can't identify the operation of of where
AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11).
Data as JSON: /api/errors/4f19a1147e907319.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/backend/jdbc/mongodb/MongoSQLParser.java:178
}
if (statement instanceof SQLUpdateStatement) {
return UpData((SQLUpdateStatement)statement);
}
if (statement instanceof SQLDropTableStatement) {
return dropTable((SQLDropTableStatement)statement);
}
if (statement instanceof SQLDeleteStatement) {
return DeleteDate((SQLDeleteStatement)statement);
}
if (statement instanceof SQLCreateTableStatement) {
return 1;
}
return 1;
}
private int InsertData(SQLInsertStatement state) {
if (state.getValues().getValues().size() ==0 ){
throw new RuntimeException("number of columns error");
}
if (state.getValues().getValues().size() != state.getColumns().size()){
throw new RuntimeException("number of values and columns have to match");
}
SQLTableSource table=state.getTableSource();
BasicDBObject[] oList = new BasicDBObject[state.getValuesList().size()];
int i = 0;
for(SQLInsertStatement.ValuesClause values : state.getValuesList()){
int j = 0;
BasicDBObject o = new BasicDBObject();
oList[i++] = o ;
for(SQLExpr col : state.getColumns()) {
o.put(getFieldName2(col), getExpValue(values.getValues().get(j++)));
}
}
DBCollection coll =this._db.getCollection(table.toString());
WriteResult result = coll.insert(oList);
View on GitHub (pinned to 65f8d8beb7)