OtterMind/Chat2DB · error · IllegalArgumentException

Source table DDL is empty

Error message

Source table DDL is empty

What it means

Thrown by SqlServerDBManager.prepareCopyDdlBatches (the table-copy feature) when the supplied source-table DDL string is null or blank. The method rewrites a CREATE TABLE script to target a new table name, so it needs a non-empty DDL to start from.

Source

Thrown at chat2db-community-server/chat2db-community-plugins/chat2db-community-sqlserver/src/main/java/ai/chat2db/plugin/sqlserver/SqlServerDBManager.java:252

            String columnList = String.join(", ", copyableColumns);
            String sourceTable = buildFullTableName(databaseName, schemaName, tableName);
            String targetTable = buildFullTableName(databaseName, schemaName, newTableName);
            String insertSql = buildCopyDataSql(targetTable, columnList, sourceTable);
            log.info("copy table data sql: {}", insertSql);

            if (hasIdentity) {
                executeIdentityCopy(targetTable, insertSql,
                        sql -> DefaultSQLExecutor.getInstance().execute(connection, sql, resultSet -> null));
            } else {
                DefaultSQLExecutor.getInstance().execute(connection, insertSql, resultSet -> null);
            }
        }
    }

    static List<String> prepareCopyDdlBatches(String ddl, String databaseName, String schemaName,
            String tableName, String newTableName) {
        if (StringUtils.isBlank(ddl)) {
            throw new IllegalArgumentException("Source table DDL is empty");
        }

        List<String> sourceReferences = tableReferences(databaseName, schemaName, tableName);
        String targetTable = buildFullTableName(null, schemaName, newTableName);
        List<String> rewrittenBatches = new ArrayList<>();
        boolean createTableRewritten = false;

        for (String batch : splitDdlBatches(ddl)) {
            String rewritten = batch;
            if (startsWithKeyword(batch, "CREATE\\s+TABLE")) {
                rewritten = replaceObjectAfterKeyword(batch, "CREATE\\s+TABLE\\s+", sourceReferences,
                        targetTable);
                rewritten = rewriteSelfReference(rewritten, sourceReferences, tableName, targetTable);
                // Constraint names are schema-scoped, so copied declarations must receive fresh server-generated names.
                rewritten = removeNamedTableConstraints(rewritten);
                createTableRewritten = true;
            } else if (CREATE_INDEX_BATCH.matcher(batch).find()) {
                rewritten = replaceObjectAfterKeyword(batch, "ON\\s+", sourceReferences, targetTable);

View on GitHub (pinned to 5ee1e990e7)

Solutions

  1. Fetch and verify a non-empty DDL for the source table before calling prepareCopyDdlBatches.
  2. Confirm the connected user has VIEW DEFINITION permission on the source table.
  3. Handle a null/empty DDL upstream as a user-facing 'cannot copy: definition unavailable' message rather than letting it throw.

Example fix

// before
String ddl = fetchDdl(table); // returned ""
prepareCopyDdlBatches(ddl, db, schema, table, newTable);
// -> Source table DDL is empty

// after
String ddl = fetchDdl(table);
if (StringUtils.isBlank(ddl)) {
    throw new IllegalStateException("No DDL available for " + table);
}
prepareCopyDdlBatches(ddl, db, schema, table, newTable);
Defensive patterns

Strategy: validation

Validate before calling

if (StringUtils.isBlank(ddl)) {
    throw new IllegalStateException("Cannot copy table: source DDL is unavailable");
}

Try / catch

try {
    prepareCopyDdlBatches(ddl, db, schema, table, newTable);
} catch (IllegalArgumentException e) {
    // surface a user-facing 'definition unavailable' message
    log.warn("Table copy aborted for {}: {}", table, e.getMessage());
}

Prevention

When it happens

Trigger: Invoking the copy-table flow when the source table's DDL could not be fetched (returned null/empty) - e.g. the DB metadata query for the original CREATE TABLE returned nothing, or the caller passed an empty string.

Common situations: The source object is a view/Synonym/temp table whose DDL isn't exposed the same way; permissions prevent reading the definition; an upstream metadata service returned an empty body; the table was dropped between fetch and copy.

Related errors


AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14). Data as JSON: /api/errors/b5571232f6daa15b. Report an issue: GitHub.