MyCATApache/Mycat-Server · critical · RuntimeException

${e}

Error message

${e}

What it means

loadColumn queries INFORMATION_SCHEMA.COLUMNS to map a table's column ordinals during migration. Any SQLException (connection failure, bad credentials, missing table/schema, SQL syntax) is wrapped in a RuntimeException, so the original JDBC error surfaces as an opaque '${e}' message. It aborts binlog replay because column metadata is mandatory.

Solutions

  1. Verify the MySQL host, port, username and password used by the migration task are correct and the server is reachable (mysql -h ... -P ...).
  2. Confirm the table and database names in the migration task exist on the source node.
  3. Grant the migration user SELECT on INFORMATION_SCHEMA and the target schema.
  4. Unwrap the cause ('Caused by' in the stack trace) to see the actual SQLException and fix accordingly.

Example fix

// before
list = executeQuery(con, "select COLUMN_NAME ... where table_name='" + table + "' and TABLE_SCHEMA='" + database + "'");
// after
// use parameter binding / verify identifiers first
if (!tableExists(con, database, table)) {
    throw new IllegalStateException("Table " + database + "." + table + " not found on source node");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before migration
try (Connection c = DriverManager.getConnection(url, user, pass)) {
    ResultSet rs = c.createStatement().executeQuery(
        "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='" + table + "' AND TABLE_SCHEMA='" + db + "'");
    rs.next();
    if (rs.getInt(1) == 0) throw new IllegalStateException("table/columns missing on source");
}

Try / catch

try { migrationStep(); } catch (RuntimeException e) {
    Throwable cause = e.getCause();
    if (cause instanceof SQLException) { /* reconnect / fix creds / retry */ }
    throw e;
}

Prevention

When it happens

Trigger: DriverManager.getConnection to jdbc:mysql://hostname:port fails; the table or database name is wrong so INFORMATION_SCHEMA returns nothing useful; MySQL rejects the query due to privileges or connectivity loss mid-migration.

Common situations: Wrong MySQL host/port/credentials in migration config; the migrated table was dropped or renamed; network/firewall blocks the data node; user lacks privileges on INFORMATION_SCHEMA for that schema.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


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

Appendix: source

Thrown at src/main/java/io/mycat/migrate/BinlogStream.java:193

        private final Map<Long, TableMapEventData> tablesById = new HashMap<Long, TableMapEventData>();
        private final Map<String, Map<Integer, Map<String, Object>>> tablesColumnMap = new HashMap<>();

        private boolean transactionInProgress;
        private String binlogFilename;


        //当发现ddl语句时 需要更新重新取列名
        private Map<Integer, Map<String, Object>> loadColumn(String database, String table) {
            Map<Integer, Map<String, Object>> rtn = new HashMap<>();
            List<Map<String, Object>> list = null;
            Connection con = null;
            try {
                con = DriverManager.getConnection("jdbc:mysql://" + hostname + ":" + port, username, password);
                list = executeQuery(con, "select  COLUMN_NAME, ORDINAL_POSITION, DATA_TYPE, CHARACTER_SET_NAME from INFORMATION_SCHEMA.COLUMNS where table_name='" + table + "' and TABLE_SCHEMA='" + database + "'");

            } catch (SQLException e) {
                throw new RuntimeException(e);
            } finally {
                JdbcUtils.close(con);
            }
            for (Map<String, Object> stringObjectMap : list) {
                BigInteger pos = (BigInteger) stringObjectMap.get("ORDINAL_POSITION");
                rtn.put(pos.intValue(), stringObjectMap);
            }
            return rtn;
        }

        @Override
        public void onEvent(Event event) {
            logger.debug("----->migrate binlog event:" + event.toString());
            EventType eventType = event.getHeader().getEventType();
            switch (eventType) {
                case TABLE_MAP:
                    TableMapEventData tableMapEventData = event.getData();
                    tablesById.put(tableMapEventData.getTableId(), tableMapEventData);

View on GitHub (pinned to 65f8d8beb7)