修改OraDB-DUMP-Viewer-3.1.1的windows dll 版本test_export示例为Linux

github存储库地址:https://github.com/OraDB-DUMP-Viewer/OraDB-DUMP-Viewer/releases/tag/v3.1.1

原文件位于test_dumps目录。

主要就是用#define将函数指针改为函数名映射,删除一些windows专有函数,改为Linux版本。修改结果如下:

c 复制代码
/*****************************************************************************
    OraDB DUMP Viewer - Export Test Harness
    テスト用ダンプファイルから CSV/SQL を生成し、結果を検証する
 *****************************************************************************/
#include "odv_api.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
//#include <windows.h>
#define __stdcall
#define __int64 __int64_t

/* --- DLL function pointers --- */
typedef struct _odv_session ODV_SESSION;

typedef void (__stdcall *ODV_TABLE_CALLBACK)(
    const char *schema, const char *table, int col_count,
    const char **col_names, const char **col_types,
    const int *col_not_nulls, const char **col_defaults,
    int constraint_count, const char *constraints_json,
    __int64 row_count, __int64 data_offset, void *user_data);

#define     fn_create        odv_create_session
#define     fn_destroy       odv_destroy_session
#define     fn_set_file      odv_set_dump_file
#define     fn_set_table_cb  odv_set_table_callback
#define     fn_check_kind    odv_check_dump_kind
#define     fn_list_tables   odv_list_tables
#define     fn_export_csv    odv_export_csv
#define     fn_export_sql    odv_export_sql
#define     fn_set_csv_opts  odv_set_csv_options
#define     fn_set_sql_opts  odv_set_sql_options
#define     fn_set_date_fmt  odv_set_date_format
#define     fn_get_version   odv_get_version
#define     fn_get_error     odv_get_last_error 
/* --- Table list state --- */
#define MAX_TABLES 200
typedef struct {
    int count;
    char names[MAX_TABLES][256];
    char schemas[MAX_TABLES][256];
    __int64 row_counts[MAX_TABLES];
} TableList;

static void __stdcall on_table(const char *schema, const char *table,
    int col_count, const char **col_names, const char **col_types,
    const int *col_not_nulls, const char **col_defaults,
    int constraint_count, const char *constraints_json,
    __int64 row_count, __int64 data_offset, void *ud)
{
    TableList *tl = (TableList *)ud;
    if (tl->count < MAX_TABLES) {
        strncpy(tl->schemas[tl->count], schema, 255);
        strncpy(tl->names[tl->count], table, 255);
        tl->row_counts[tl->count] = row_count;
        tl->count++;
    }
}

/* Count lines in a file */
static int count_lines(const char *path) {
    FILE *f = fopen(path, "rb");
    if (!f) return -1;
    int count = 0;
    char buf[8192];
    while (fgets(buf, sizeof(buf), f)) count++;
    fclose(f);
    return count;
}

/* Count INSERT statements in a SQL file */
static int count_inserts(const char *path) {
    FILE *f = fopen(path, "rb");
    if (!f) return -1;
    int count = 0;
    char buf[65536];
    while (fgets(buf, sizeof(buf), f)) {
        if (strncmp(buf, "INSERT INTO", 11) == 0) count++;
    }
    fclose(f);
    return count;
}

/* Check if file contains CREATE TABLE */
static int has_create_table(const char *path) {
    FILE *f = fopen(path, "rb");
    if (!f) return 0;
    char buf[65536];
    while (fgets(buf, sizeof(buf), f)) {
        if (strstr(buf, "CREATE TABLE") != NULL) {
            fclose(f);
            return 1;
        }
    }
    fclose(f);
    return 0;
}

/* Count COMMENT ON statements in a SQL file */
static int count_comment_on(const char *path) {
    FILE *f = fopen(path, "rb");
    if (!f) return 0;
    int count = 0;
    char buf[65536];
    while (fgets(buf, sizeof(buf), f)) {
        if (strncmp(buf, "COMMENT ON", 10) == 0) count++;
    }
    fclose(f);
    return count;
}

/* Count CREATE INDEX statements in a SQL file */
static int count_create_indexes(const char *path) {
    FILE *f = fopen(path, "rb");
    if (!f) return 0;
    int count = 0;
    char buf[65536];
    while (fgets(buf, sizeof(buf), f)) {
        if (strncmp(buf, "CREATE INDEX", 12) == 0) count++;
    }
    fclose(f);
    return count;
}

/* Get file size */
static long get_file_size(const char *path) {
    FILE *f = fopen(path, "rb");
    if (!f) return -1;
    fseek(f, 0, SEEK_END);
    long size = ftell(f);
    fclose(f);
    return size;
}

/* DBMS type names */
static const char *dbms_name(int t) {
    switch (t) {
        case 0: return "Oracle";
        case 4: return "PostgreSQL";
        case 5: return "MySQL";
        case 6: return "SQLServer";
        default: return "Unknown";
    }
}

int main(int argc, char *argv[]) {
    //SetConsoleOutputCP(65001);

    printf("OraDB DUMP Viewer - Export Test Harness\n");
    printf("========================================\n");


  
    /* Create output directory */
    //CreateDirectoryA("export_output", NULL);
    mkdir("export_output", 0755);
    /* Test dump file */
    const char *dump_file = "./exp_index_test.dmp";

    /* Step 1: List tables */
    printf("Phase 1: Listing tables in %s\n", dump_file);
    printf("----------------------------------------\n");

    ODV_SESSION *s = NULL;
    TableList tables;
    memset(&tables, 0, sizeof(tables));

    fn_create(&s);
    fn_set_file(s, dump_file);
    int dump_type;
    fn_check_kind(s, &dump_type);
    fn_set_table_cb(s, on_table, &tables);
    fn_list_tables(s);
    fn_destroy(s);

    printf("Found %d tables\n\n", tables.count);

    /* Select test tables (mix of types) */
    const char *test_tables[] = {
        "T_BASIC_TYPES",
        "T_NUMERIC_TYPES",
        "T_DATETIME_TYPES",
        "T_NCHAR_TYPES",
        "T_TRAILING_NULLS",
        "T_SPECIAL_CHARS",
        "T_SINGLE_ROW",
        "T_EMPTY",
        "T_WIDE_TABLE",
        NULL
    };

    /* Also test Japanese tables */
    const char *jp_test_tables[] = {
        "\xe7\xa4\xbe\xe5\x93\xa1\xe3\x83\x9e\xe3\x82\xb9\xe3\x82\xbf",  /* 社員マスタ */
        "\xe9\x83\xa8\xe7\xbd\xb2\xe3\x83\x9e\xe3\x82\xb9\xe3\x82\xbf",  /* 部署マスタ */
        "\xe5\x8f\x97\xe6\xb3\xa8\xe3\x83\x87\xe3\x83\xbc\xe3\x82\xbf",  /* 受注データ */
        NULL
    };

    int pass = 0, fail = 0;

    /* ================================================================
       Phase 2: CSV Export Tests
       ================================================================ */
    printf("Phase 2: CSV Export Tests\n");
    printf("========================================\n");

    for (int i = 0; test_tables[i]; i++) {
        char out_path[512];
        snprintf(out_path, 512, "export_output/%s.csv", test_tables[i]);

        s = NULL;
        fn_create(&s);
        fn_set_file(s, dump_file);
        fn_check_kind(s, &dump_type);
        fn_set_table_cb(s, on_table, &tables);
        fn_list_tables(s);
        if (fn_set_csv_opts) fn_set_csv_opts(s, 1, 1);  /* header + types */

        int rc = fn_export_csv(s, test_tables[i], out_path);
        if (rc == 0) {
            long fsize = get_file_size(out_path);
            int lines = count_lines(out_path);
            printf("  CSV %-25s -> %s (%ld bytes, %d lines) OK\n",
                   test_tables[i], out_path, fsize, lines);
            pass++;
        } else {
            printf("  CSV %-25s -> FAIL: %s\n", test_tables[i],
                   fn_get_error ? fn_get_error(s) : "unknown error");
            fail++;
        }
        fn_destroy(s);
    }

    /* Japanese table CSV */
    for (int i = 0; jp_test_tables[i]; i++) {
        char out_path[512];
        snprintf(out_path, 512, "export_output/jp_%d.csv", i);

        s = NULL;
        fn_create(&s);
        fn_set_file(s, dump_file);
        fn_check_kind(s, &dump_type);
        fn_set_table_cb(s, on_table, &tables);
        fn_list_tables(s);
        if (fn_set_csv_opts) fn_set_csv_opts(s, 1, 0);

        int rc = fn_export_csv(s, jp_test_tables[i], out_path);
        if (rc == 0) {
            long fsize = get_file_size(out_path);
            printf("  CSV %-25s -> %s (%ld bytes) OK\n",
                   jp_test_tables[i], out_path, fsize);
            pass++;
        } else {
            printf("  CSV %-25s -> FAIL: %s\n", jp_test_tables[i],
                   fn_get_error ? fn_get_error(s) : "unknown error");
            fail++;
        }
        fn_destroy(s);
    }

    printf("\n");

    /* ================================================================
       Phase 3: SQL Export Tests (All 4 DBMS types)
       ================================================================ */
    int dbms_types[] = {0, 4, 5, 6};  /* Oracle, PostgreSQL, MySQL, SQL Server */

    for (int d = 0; d < 4; d++) {
        int dbms = dbms_types[d];
        printf("Phase 3.%d: SQL Export - %s\n", d+1, dbms_name(dbms));
        printf("----------------------------------------\n");

        for (int i = 0; test_tables[i]; i++) {
            char out_path[512];
            snprintf(out_path, 512, "export_output/%s_%s.sql",
                     test_tables[i], dbms_name(dbms));

            s = NULL;
            fn_create(&s);
            fn_set_file(s, dump_file);
            fn_check_kind(s, &dump_type);
            fn_set_table_cb(s, on_table, &tables);
            fn_list_tables(s);
            if (fn_set_sql_opts) fn_set_sql_opts(s, 1);  /* include CREATE TABLE */

            int rc = fn_export_sql(s, test_tables[i], out_path, dbms);
            if (rc == 0) {
                long fsize = get_file_size(out_path);
                int inserts = count_inserts(out_path);
                int has_ddl = has_create_table(out_path);
                printf("  SQL %-25s -> %s (%ld bytes, %d INSERTs, DDL=%s) OK\n",
                       test_tables[i], out_path, fsize, inserts,
                       has_ddl ? "YES" : "NO");
                pass++;
            } else {
                printf("  SQL %-25s -> FAIL: %s\n", test_tables[i],
                       fn_get_error ? fn_get_error(s) : "unknown error");
                fail++;
            }
            fn_destroy(s);
        }

        /* Japanese table SQL */
        for (int i = 0; jp_test_tables[i]; i++) {
            char out_path[512];
            snprintf(out_path, 512, "export_output/jp_%d_%s.sql", i, dbms_name(dbms));

            s = NULL;
            fn_create(&s);
            fn_set_file(s, dump_file);
            fn_check_kind(s, &dump_type);
            fn_set_table_cb(s, on_table, &tables);
            fn_list_tables(s);
            if (fn_set_sql_opts) fn_set_sql_opts(s, 1);

            int rc = fn_export_sql(s, jp_test_tables[i], out_path, dbms);
            if (rc == 0) {
                long fsize = get_file_size(out_path);
                int inserts = count_inserts(out_path);
                printf("  SQL %-25s -> %s (%ld bytes, %d INSERTs) OK\n",
                       jp_test_tables[i], out_path, fsize, inserts);
                pass++;
            } else {
                printf("  SQL %-25s -> FAIL: %s\n", jp_test_tables[i],
                       fn_get_error ? fn_get_error(s) : "unknown error");
                fail++;
            }
            fn_destroy(s);
        }
        printf("\n");
    }

    /* ================================================================
       Phase 4: EXP format test
       ================================================================ */
    const char *exp_file = "./exp_user.dmp";
    printf("Phase 4: EXP Format Export Tests (%s)\n", exp_file);
    printf("========================================\n");

    const char *exp_tables[] = {"T_BASIC_TYPES", "T_NUMERIC_TYPES", "T_DATETIME_TYPES", NULL};
    for (int i = 0; exp_tables[i]; i++) {
        for (int d = 0; d < 4; d++) {
            int dbms = dbms_types[d];
            char out_path[512];
            snprintf(out_path, 512, "export_output/exp_%s_%s.sql",
                     exp_tables[i], dbms_name(dbms));

            s = NULL;
            fn_create(&s);
            fn_set_file(s, exp_file);
            fn_check_kind(s, &dump_type);
            fn_set_table_cb(s, on_table, &tables);
            fn_list_tables(s);
            if (fn_set_sql_opts) fn_set_sql_opts(s, 1);

            int rc = fn_export_sql(s, exp_tables[i], out_path, dbms);
            if (rc == 0) {
                int inserts = count_inserts(out_path);
                printf("  EXP SQL %-20s [%s] -> %d INSERTs OK\n",
                       exp_tables[i], dbms_name(dbms), inserts);
                pass++;
            } else {
                printf("  EXP SQL %-20s [%s] -> FAIL: %s\n",
                       exp_tables[i], dbms_name(dbms),
                       fn_get_error ? fn_get_error(s) : "unknown error");
                fail++;
            }
            fn_destroy(s);
        }
    }

    /* ================================================================
       Phase 5: EXP INDEX Export Test (exp_index_test.dmp)
       ================================================================ */
    const char *idx_file = "./exp_index_test.dmp";
    printf("\nPhase 5: INDEX Export Test (%s)\n", idx_file);
    printf("========================================\n");

    for (int d = 0; d < 4; d++) {
        int dbms = dbms_types[d];
        char out_path[512];
        snprintf(out_path, 512, "export_output/idx_T_INDEX_TEST_%s.sql",
                 dbms_name(dbms));

        s = NULL;
        fn_create(&s);
        fn_set_file(s, idx_file);
        fn_check_kind(s, &dump_type);
        fn_set_table_cb(s, on_table, &tables);
        fn_list_tables(s);
        if (fn_set_sql_opts) fn_set_sql_opts(s, 1);

        int rc = fn_export_sql(s, "T_INDEX_TEST", out_path, dbms);
        if (rc == 0) {
            int inserts = count_inserts(out_path);
            int indexes = count_create_indexes(out_path);
            int has_ddl = has_create_table(out_path);
            printf("  IDX SQL [%-10s] -> %d INSERTs, DDL=%s, %d CREATE INDEX",
                   dbms_name(dbms), inserts, has_ddl ? "YES" : "NO", indexes);
            if (indexes == 3) {
                printf(" OK\n");
                pass++;
            } else {
                printf(" FAIL (expected 3 CREATE INDEX)\n");
                fail++;
            }
        } else {
            printf("  IDX SQL [%-10s] -> FAIL: %s\n", dbms_name(dbms),
                   fn_get_error ? fn_get_error(s) : "unknown error");
            fail++;
        }
        fn_destroy(s);
    }

    /* ================================================================
       Phase 6: EXP COMMENT Export Test (exp_comment_test.dmp)
       ================================================================ */
    const char *cmt_file = "./exp_comment_test.dmp";
    printf("\nPhase 6: COMMENT Export Test (%s)\n", cmt_file);
    printf("========================================\n");

    /* Oracle and PostgreSQL should have COMMENT ON statements */
    for (int d = 0; d < 4; d++) {
        int dbms = dbms_types[d];
        char out_path[512];
        snprintf(out_path, 512, "export_output/cmt_T_COMMENT_TEST_%s.sql",
                 dbms_name(dbms));

        s = NULL;
        fn_create(&s);
        fn_set_file(s, cmt_file);
        fn_check_kind(s, &dump_type);
        fn_set_table_cb(s, on_table, &tables);
        fn_list_tables(s);
        if (fn_set_sql_opts) fn_set_sql_opts(s, 1);

        int rc = fn_export_sql(s, "T_COMMENT_TEST", out_path, dbms);
        if (rc == 0) {
            int inserts = count_inserts(out_path);
            int comments = count_comment_on(out_path);
            int has_ddl = has_create_table(out_path);
            printf("  CMT SQL [%-10s] -> %d INSERTs, DDL=%s, %d COMMENT ON",
                   dbms_name(dbms), inserts, has_ddl ? "YES" : "NO", comments);
            /* Oracle/PostgreSQL: 1 table comment + 4 column comments = 5 */
            if ((dbms == 0 || dbms == 4) && comments == 5) {
                printf(" OK\n");
                pass++;
            } else if ((dbms == 5 || dbms == 6) && comments == 0) {
                /* MySQL/SQL Server: comments as SQL comments, not COMMENT ON */
                printf(" OK (as SQL comments)\n");
                pass++;
            } else {
                printf(" FAIL (expected %d COMMENT ON)\n",
                       (dbms == 0 || dbms == 4) ? 5 : 0);
                fail++;
            }
        } else {
            printf("  CMT SQL [%-10s] -> FAIL: %s\n", dbms_name(dbms),
                   fn_get_error ? fn_get_error(s) : "unknown error");
            fail++;
        }
        fn_destroy(s);
    }

    printf("\n========================================\n");
    printf("EXPORT TEST RESULTS: %d passed, %d failed (total %d)\n", pass, fail, pass + fail);
    printf("========================================\n");

    //FreeLibrary(dll);
    return fail > 0 ? 1 : 0;
}

执行结果如下:

复制代码
./a.out
OraDB DUMP Viewer - Export Test Harness
========================================
Phase 1: Listing tables in ./exp_index_test.dmp
----------------------------------------
Found 1 tables

Phase 2: CSV Export Tests
========================================
。。。

Phase 3.1: SQL Export - Oracle
----------------------------------------
  SQL T_BASIC_TYPES             -> export_output/T_BASIC_TYPES_Oracle.sql (0 bytes, 0 INSERTs, DDL=NO) OK
  SQL T_NUMERIC_TYPES           -> export_output/T_NUMERIC_TYPES_Oracle.sql (0 bytes, 0 INSERTs, DDL=NO) OK
  SQL T_DATETIME_TYPES          -> export_output/T_DATETIME_TYPES_Oracle.sql (0 bytes, 0 INSERTs, DDL=NO) OK
  SQL T_NCHAR_TYPES             -> export_output/T_NCHAR_TYPES_Oracle.sql (0 bytes, 0 INSERTs, DDL=NO) OK
  SQL T_TRAILING_NULLS          -> export_output/T_TRAILING_NULLS_Oracle.sql (0 bytes, 0 INSERTs, DDL=NO) OK
  SQL T_SPECIAL_CHARS           -> export_output/T_SPECIAL_CHARS_Oracle.sql (0 bytes, 0 INSERTs, DDL=NO) OK
  SQL T_SINGLE_ROW              -> export_output/T_SINGLE_ROW_Oracle.sql (0 bytes, 0 INSERTs, DDL=NO) OK
  SQL T_EMPTY                   -> export_output/T_EMPTY_Oracle.sql (0 bytes, 0 INSERTs, DDL=NO) OK
  SQL T_WIDE_TABLE              -> export_output/T_WIDE_TABLE_Oracle.sql (0 bytes, 0 INSERTs, DDL=NO) OK
  SQL 社員マスタ           -> export_output/jp_0_Oracle.sql (0 bytes, 0 INSERTs) OK
  SQL 部署マスタ           -> export_output/jp_1_Oracle.sql (0 bytes, 0 INSERTs) OK
  SQL 受注データ           -> export_output/jp_2_Oracle.sql (0 bytes, 0 INSERTs) OK

Phase 3.2: SQL Export - PostgreSQL
----------------------------------------
。。。

Phase 3.3: SQL Export - MySQL
----------------------------------------
。。。

Phase 3.4: SQL Export - SQLServer
----------------------------------------
。。。

Phase 4: EXP Format Export Tests (./exp_user.dmp)
========================================
。。。

Phase 5: INDEX Export Test (./exp_index_test.dmp)
========================================
  IDX SQL [Oracle    ] -> 3 INSERTs, DDL=YES, 3 CREATE INDEX OK
  IDX SQL [PostgreSQL] -> 3 INSERTs, DDL=YES, 3 CREATE INDEX OK
  IDX SQL [MySQL     ] -> 3 INSERTs, DDL=YES, 3 CREATE INDEX OK
  IDX SQL [SQLServer ] -> 3 INSERTs, DDL=YES, 3 CREATE INDEX OK

Phase 6: COMMENT Export Test (./exp_comment_test.dmp)
========================================
  CMT SQL [Oracle    ] -> 3 INSERTs, DDL=YES, 5 COMMENT ON OK
  CMT SQL [PostgreSQL] -> 3 INSERTs, DDL=YES, 5 COMMENT ON OK
  CMT SQL [MySQL     ] -> 3 INSERTs, DDL=YES, 0 COMMENT ON OK (as SQL comments)
  CMT SQL [SQLServer ] -> 3 INSERTs, DDL=YES, 0 COMMENT ON OK (as SQL comments)

========================================
EXPORT TEST RESULTS: 68 passed, 12 failed (total 80)
========================================

其中生成的一个SQL文件如下(idx_T_INDEX_TEST_Oracle.sql)

复制代码
-- Table: ODV_TEST.T_INDEX_TEST
-- Generated by OraDB DUMP Viewer

BEGIN EXECUTE IMMEDIATE 'DROP TABLE "ODV_TEST"."T_INDEX_TEST" CASCADE CONSTRAINTS PURGE'; EXCEPTION WHEN OTHERS THEN NULL; END;
/

CREATE TABLE "ODV_TEST"."T_INDEX_TEST" (
    "ID" NUMBER(10, 0),
    "COL_NAME" VARCHAR2(100),
    "COL_EMAIL" VARCHAR2(200),
    "COL_DEPT" VARCHAR2(50),
    "COL_SALARY" NUMBER(10, 2),
    "COL_CREATED" DATE
);

INSERT INTO "ODV_TEST"."T_INDEX_TEST" ("ID", "COL_NAME", "COL_EMAIL", "COL_DEPT", "COL_SALARY", "COL_CREATED") VALUES (1, 'Alice', 'alice@ex.com', 'Engineering', 85000, '2026/03/20 00:49:54');
INSERT INTO "ODV_TEST"."T_INDEX_TEST" ("ID", "COL_NAME", "COL_EMAIL", "COL_DEPT", "COL_SALARY", "COL_CREATED") VALUES (2, 'Bob', 'bob@ex.com', 'Sales', 72000, '2026/03/20 00:49:54');
INSERT INTO "ODV_TEST"."T_INDEX_TEST" ("ID", "COL_NAME", "COL_EMAIL", "COL_DEPT", "COL_SALARY", "COL_CREATED") VALUES (3, 'Charlie', 'charlie@ex.com', 'Engineering', 92000, '2026/03/20 00:49:54');
CREATE INDEX "IDX_INDEX_TEST_NAME" ON "ODV_TEST"."T_INDEX_TEST" ("COL_NAME" );
CREATE INDEX "IDX_INDEX_TEST_DEPT_SAL" ON "ODV_TEST"."T_INDEX_TEST" ("COL_DEPT" , "COL_SALARY" );
CREATE INDEX "IDX_INDEX_TEST_UPPER_EMAIL" ON "ODV_TEST"."T_INDEX_TEST" (UPPER("COL_EMAIL") );
相关推荐
暂未成功人士!2 小时前
语义分割标注工具(isat-sam):利用 AI 辅助完成深度学习语义分割的图像数据标注
人工智能·深度学习·语义分割·数据标注
多年小白2 小时前
AI 日报 - 2026年4月6日
网络·人工智能·科技·矩阵
云上码厂2 小时前
SOLIDWORKS 2025 全套工具深度解析:从设计到管理全流程攻略
人工智能·仿真
oi..2 小时前
Linux入门(2)
linux·笔记·测试工具·安全·网络安全
鄃鳕2 小时前
vscode远程连接virtualBox上的Ubuntu
linux·运维·ubuntu
枫叶林FYL2 小时前
【Python高级工程与架构实战】项目三:实时数据管道(Kafka + Polars + Delta Lake)(二)
人工智能·机器学习
IT_陈寒2 小时前
SpringBoot自动配置的坑,我调试到凌晨三点才爬出来
前端·人工智能·后端
Yvonne爱编码2 小时前
数据库---Day7 数据表设计
数据库·oracle
lifallen2 小时前
Flink Agent 与 Checkpoint:主循环闭环与 Mailbox 事件驱动模型
java·大数据·人工智能·python·语言模型·flink