python版本依赖python环境,我让美团龙猫改写成C语言,导出schema正确了,导出csv文件有错。修改了几轮,没有解决。
在github上看到有个较新的开源项目,https://github.com/OraDB-DUMP-Viewer/OraDB-DUMP-Viewer/ 它是面向Windows的,用vb.net编写,但是核心的dmp文件解析是用C语言编的,而且不依赖Windows,正好用来改造。

第一步是编译
进入源代码的Logics/DumpParser目录,gcc *.c -I .报了如下错误。

odv_types.h:354:24: error: expected ')' before '*' token
  354 | typedef void (__stdcall *ODV_ROW_CALLBACK)(
      |                        ^~
      |                        )

odv_types.h:363:24: error: expected ')' before '*' token
  363 | typedef void (__stdcall *ODV_PROGRESS_CALLBACK)(
      |                        ^~
      |                        )

这是因为__stdcall不是Linux的c关键字,用#define __stdcall屏蔽。

odv_exp.c:1640:41: error: implicit declaration of function '_stricmp'; did you mean 'strncmp'? [-Wimplicit-function-declaration]
 1640 |                                     if (_stricmp(s->table.name, ft) != 0)
      |                                         ^~~~~~~~
      |                                         strncmp

Windows中_stricmp函数对应Linux的strcasecmp函数用#define _stricmp strcasecmp替换。

odv_expdp.c:338:9: error: implicit declaration of function '_strnicmp'; did you mean 'strncmp'? [-Wimplicit-function-declaration]
  338 |     if (_strnicmp(t->name, "SYS_EXPORT_", 11) == 0) return 1;
      |         ^~~~~~~~~
      |         strncmp

Windows中_strnicmp函数对应Linux的strncasecmp函数用#define _strnicmp strncasecmp替换。

odv_api.h:25:19: error: expected declaration specifiers before '__declspec'
   25 |   #define ODV_API __declspec(dllimport)
      |                   ^~~~~~~~~~

这是因为__declspec(dllimport)不是Linux的c关键字,用#define ODV_API屏蔽。注意要写在原定义之后。

这样修改后,编译就通过了,在链接时报缺少main函数。我把odv_csv.c传给DeepSeek,提示

编写C语言main函数,调用附件中的函数,实现将dmp文件中的一个或多个表导出csv文件

结果他给出的代码有很多编译错误,主要是关于会话之类的函数名错误,再把odv_api.h也传给他,再次给出的代码就基本不出错了,我添加了一个main.c的源文件到原目录,编译通过,也能导出个别dmp文件,有的dmp文件还是有错,需要进一步研究。

/*****************************************************************************
    OraDB DUMP Viewer - Main Program
    
    Usage: odv_export <dump_file> [options]
    
    Options:
        -o <dir>        Output directory (default: current directory)
        -t <table>      Export specific table (can be used multiple times)
        -a              Export all tables (default)
        -d <delimiter>  CSV delimiter character (default: ',')
        -H              Write header row (default: enabled)
        -T              Write column types row after header
        -h              Show this help message
    
    Examples:
        odv_export export.dmp -o ./output -a
        odv_export export.dmp -t TABLE1 -t TABLE2 -o ./csv_files
        odv_export export.dmp -t EMPLOYEES -d '|' -H
 *****************************************************************************/

#include "odv_api.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> 
#include <getopt.h> 
#ifdef _WIN32
    #include <direct.h>
    #define MKDIR(dir) _mkdir(dir)
#else
    #include <sys/stat.h>
    #define MKDIR(dir) mkdir(dir, 0755)
#endif

/*---------------------------------------------------------------------------
    Global variables
 ---------------------------------------------------------------------------*/
static const char *g_output_dir = ".";
static char **g_table_list = NULL;
static int g_table_count = 0;
static char g_delimiter = ',';
static int g_write_header = 1;
static int g_write_types = 0;
static int g_export_all = 1;
static int64_t g_total_rows_estimate = 0;

/*---------------------------------------------------------------------------
    print_usage
 ---------------------------------------------------------------------------*/
static void print_usage(const char *program_name)
{
    printf("Usage: %s <dump_file> [options]\n\n", program_name);
    printf("Options:\n");
    printf("  -o <dir>        Output directory (default: current directory)\n");
    printf("  -t <td>      Export specific table (can be used multiple times)\n");
    printf("  -a              Export all tables (default)\n");
    printf("  -d <delimiter>  CSV delimiter character (default: ',')\n");
    printf("  -H              Write header row (default: enabled)\n");
    printf("  -T              Write column types row after header\n");
    printf("  -h              Show this help message\n\n");
    printf("Examples:\n");
    printf("  %s export.dmp -o ./output -a\n", program_name);
    printf("  %s export.dmp -t TABLE1 -t TABLE2 -o ./csv_files\n", program_name);
    printf("  %s export.dmp -t EMPLOYEES -d '|' -H\n", program_name);
}

/*---------------------------------------------------------------------------
    create_directory
 ---------------------------------------------------------------------------*/
static int create_directory(const char *path)
{
    if (MKDIR(path) == 0) {
        return 1;
    }
    return 1; /* Assume directory exists */
}

/*---------------------------------------------------------------------------
    sanitize_filename
 ---------------------------------------------------------------------------*/
static void sanitize_filename(const char *input, char *output, int output_size)
{
    int i, j = 0;
    
    for (i = 0; input[i] && j < output_size - 1; i++) {
        char c = input[i];
        if (c == '/' || c == '\\' || c == ':' || c == '*' || 
            c == '?' || c == '"' || c == '<' || c == '>' || c == '|') {
            output[j++] = '_';
        } else {
            output[j++] = c;
        }
    }
    output[j] = '\0';
}

/*---------------------------------------------------------------------------
    build_output_path
 ---------------------------------------------------------------------------*/
static char* build_output_path(const char *output_dir, const char *table_name)
{
    char *full_path = NULL;
    char safe_table_name[256];
    int len;
    
    sanitize_filename(table_name, safe_table_name, sizeof(safe_table_name));
    
    len = strlen(output_dir) + strlen(safe_table_name) + 10;
    full_path = (char*)malloc(len);
    if (full_path) {
        sprintf(full_path, "%s/%s.csv", output_dir, safe_table_name);
    }
    
    return full_path;
}

/*---------------------------------------------------------------------------
    table_callback

    Called for each table when listing tables.
    Stores table info and row count.
 ---------------------------------------------------------------------------*/
typedef struct {
    char **table_names;
    int64_t *row_counts;
    int count;
    int capacity;
} TABLE_INFO;

static TABLE_INFO g_table_info = {NULL, NULL, 0, 0};

static void __stdcall 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_t row_count,
    int64_t data_offset,
    void *user_data)
{
    /* Just print table info */
    printf("  Table: %s", table);
    if (schema && schema[0]) {
        printf(" (schema: %s)", schema);
    }
    printf(", columns: %d, rows: %lld\n", col_count, (long long)row_count);
    
    /* Store for later use if needed */
    if (g_table_info.count >= g_table_info.capacity) {
        int new_cap = g_table_info.capacity + 10;
        char **new_names = (char**)realloc(g_table_info.table_names, sizeof(char*) * new_cap);
        int64_t *new_counts = (int64_t*)realloc(g_table_info.row_counts, sizeof(int64_t) * new_cap);
        if (new_names && new_counts) {
            g_table_info.table_names = new_names;
            g_table_info.row_counts = new_counts;
            g_table_info.capacity = new_cap;
        } else {
            return;
        }
    }
    
    g_table_info.table_names[g_table_info.count] = strdup(table);
    g_table_info.row_counts[g_table_info.count] = row_count;
    g_table_info.count++;
    
    /* Update total rows estimate */
    g_total_rows_estimate += row_count;
}

/*---------------------------------------------------------------------------
    progress_callback

    Called periodically during parsing to show progress.
 ---------------------------------------------------------------------------*/
static void __stdcall progress_callback(
    int64_t rows_processed,
    const char *current_table,
    void *user_data)
{
    int pct = odv_get_progress_pct((ODV_SESSION*)user_data);
    
    if (pct >= 0 && pct <= 100) {
        printf("\rProgress: %d%% (%lld rows processed, current table: %s)", 
               pct, (long long)rows_processed, current_table ? current_table : "unknown");
    } else {
        printf("\rProcessed: %lld rows (current table: %s)", 
               (long long)rows_processed, current_table ? current_table : "unknown");
    }
    fflush(stdout);
}

/*---------------------------------------------------------------------------
    row_callback_for_count

    Simple callback to count rows (used for estimating progress)
 ---------------------------------------------------------------------------*/
static int64_t g_row_count = 0;

static void __stdcall row_callback_for_count(
    const char *schema,
    const char *table,
    int col_count,
    const char **col_names,
    const char **col_values,
    void *user_data)
{
    g_row_count++;
    if (g_row_count % 1000 == 0) {
        printf("\rCounting rows: %lld", (long long)g_row_count);
        fflush(stdout);
    }
}

/*---------------------------------------------------------------------------
    export_table

    Export a single table to CSV file.
 ---------------------------------------------------------------------------*/
static int export_table(ODV_SESSION *session, const char *table_name, const char *output_path)
{
    int rc;
    
    /* Set CSV options */
    odv_set_csv_options(session, g_write_header, g_write_types);
    
    /* Set CSV delimiter */
    odv_set_csv_delimiter(session, g_delimiter);
    
    /* Export to CSV */
    rc = odv_export_csv(session, table_name, output_path);
    
    return rc;
}

/*---------------------------------------------------------------------------
    export_all_tables

    Get all table names from dump and export each to separate CSV file.
 ---------------------------------------------------------------------------*/
static int export_all_tables(ODV_SESSION *session, const char *output_dir)
{
    int rc;
    int exported = 0;
    int i;
    
    printf("Getting table list from dump file...\n");
    
    /* Set table callback to collect table names */
    odv_set_table_callback(session, table_callback, NULL);
    
    /* List all tables */
    rc = odv_list_tables(session);
    if (rc != ODV_OK) {
        printf("Failed to get table list: %s\n", odv_get_last_error(session));
        return rc;
    }
    
    if (g_table_info.count == 0) {
        printf("No tables found in dump file.\n");
        return ODV_OK;
    }
    
    printf("\nFound %d tables in dump file.\n\n", g_table_info.count);
    
    /* Create output directory */
    create_directory(output_dir);
    
    /* Export each table */
    for (i = 0; i < g_table_info.count; i++) {
        char *output_path = build_output_path(output_dir, g_table_info.table_names[i]);
        if (!output_path) {
            fprintf(stderr, "Memory allocation failed\n");
            continue;
        }
        
        printf("[%d/%d] Exporting table: %s -> %s\n", 
               i + 1, g_table_info.count, g_table_info.table_names[i], output_path);
        
        /* Export to CSV */
        rc = export_table(session, g_table_info.table_names[i], output_path);
        
        if (rc == ODV_OK) {
            printf("  ✓ Successfully exported (%lld rows)\n", 
                   (long long)g_table_info.row_counts[i]);
            exported++;
        } else {
            printf("  ✗ Failed: %s\n", odv_get_last_error(session));
        }
        
        free(output_path);
    }
    
    printf("\nExport completed: %d/%d tables exported successfully.\n", 
           exported, g_table_info.count);
    
    return (exported > 0) ? ODV_OK : ODV_ERR;
}

/*---------------------------------------------------------------------------
    export_selected_tables

    Export only specified tables to CSV files.
 ---------------------------------------------------------------------------*/
static int export_selected_tables(ODV_SESSION *session, const char *output_dir,
                                   char **table_list, int table_count)
{
    int exported = 0;
    int i;
    int rc;
    
    printf("Exporting %d specified tables...\n\n", table_count);
    
    /* Create output directory */
    create_directory(output_dir);
    
    /* Export each table */
    for (i = 0; i < table_count; i++) {
        char *output_path = build_output_path(output_dir, table_list[i]);
        if (!output_path) {
            fprintf(stderr, "Memory allocation failed for table %s\n", table_list[i]);
            continue;
        }
        
        printf("[%d/%d] Exporting table: %s -> %s\n", 
               i + 1, table_count, table_list[i], output_path);
        
        /* Export to CSV */
        rc = export_table(session, table_list[i], output_path);
        
        if (rc == ODV_OK) {
            printf("  ✓ Successfully exported\n");
            exported++;
        } else {
            printf("  ✗ Failed: %s\n", odv_get_last_error(session));
        }
        
        free(output_path);
    }
    
    printf("\nExport completed: %d/%d tables exported successfully.\n", 
           exported, table_count);
    
    return (exported > 0) ? ODV_OK : ODV_ERR;
}

/*---------------------------------------------------------------------------
    main
 ---------------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
    ODV_SESSION *session = NULL;
    const char *dump_file = NULL;
    int opt;
    int rc;
    int dump_type;
    
    /* Parse command line arguments */
    while ((opt = getopt(argc, argv, "o:t:d:HTah")) != -1) {
        switch (opt) {
        case 'o':
            g_output_dir = optarg;
            break;
        case 't':
            if (!g_table_list) {
                g_table_list = (char**)malloc(sizeof(char*) * 10);
            }
            g_table_list[g_table_count] = strdup(optarg);
            g_table_count++;
            g_export_all = 0;
            break;
        case 'd':
            g_delimiter = optarg[0];
            break;
        case 'H':
            g_write_header = 1;
            break;
        case 'T':
            g_write_types = 1;
            break;
        case 'a':
            g_export_all = 1;
            break;
        case 'h':
            print_usage(argv[0]);
            return EXIT_SUCCESS;
        default:
            print_usage(argv[0]);
            return EXIT_FAILURE;
        }
    }
    
    /* Check if dump file is specified */
    if (optind >= argc) {
        fprintf(stderr, "Error: Dump file not specified\n\n");
        print_usage(argv[0]);
        return EXIT_FAILURE;
    }
    
    dump_file = argv[optind];
    
    /* Check if file exists */
    FILE *test = fopen(dump_file, "rb");
    if (!test) {
        fprintf(stderr, "Error: Cannot open dump file: %s\n", dump_file);
        return EXIT_FAILURE;
    }
    fclose(test);
    
    printf("========================================\n");
    printf("OraDB DUMP Viewer - CSV Exporter\n");
    printf("Version: %s\n", odv_get_version());
    printf("========================================\n");
    printf("Dump file: %s\n", dump_file);
    printf("Output directory: %s\n", g_output_dir);
    printf("CSV delimiter: '%c'\n", g_delimiter);
    printf("Write header: %s\n", g_write_header ? "Yes" : "No");
    printf("Write types: %s\n", g_write_types ? "Yes" : "No");
    printf("========================================\n\n");
    
    /* Create session */
    rc = odv_create_session(&session);
    if (rc != ODV_OK || !session) {
        fprintf(stderr, "Error: Failed to create session\n");
        return EXIT_FAILURE;
    }
    
    /* Set dump file */
    rc = odv_set_dump_file(session, dump_file);
    if (rc != ODV_OK) {
        fprintf(stderr, "Error setting dump file: %s\n", odv_get_last_error(session));
        odv_destroy_session(session);
        return EXIT_FAILURE;
    }
    
    /* Detect dump type */
    rc = odv_check_dump_kind(session, &dump_type);
    if (rc == ODV_OK) {
        const char *type_str = "Unknown";
        switch (dump_type) {
        case ODV_DUMP_EXPDP:
            type_str = "Oracle EXPDP";
            break;
        case ODV_DUMP_EXPDP_COMPRESS:
            type_str = "Oracle EXPDP (Compressed)";
            break;
        case ODV_DUMP_EXP:
            type_str = "Oracle EXP";
            break;
        case ODV_DUMP_EXP_DIRECT:
            type_str = "Oracle EXP (Direct)";
            break;
        default:
            type_str = "Unknown";
            break;
        }
        printf("Dump type: %s\n", type_str);
    }
    
    /* Set progress callback */
    odv_set_progress_callback(session, progress_callback, session);
    
    /* Set CSV options */
    odv_set_csv_options(session, g_write_header, g_write_types);
    odv_set_csv_delimiter(session, g_delimiter);
    
    printf("\n");
    
    /* Export tables */
    if (g_export_all) {
        rc = export_all_tables(session, g_output_dir);
    } else if (g_table_count > 0) {
        rc = export_selected_tables(session, g_output_dir, g_table_list, g_table_count);
    } else {
        fprintf(stderr, "Error: No tables specified for export\n");
        rc = ODV_ERR;
    }
    
    /* Cleanup */
    if (g_table_list) {
        for (int i = 0; i < g_table_count; i++) {
            free(g_table_list[i]);
        }
        free(g_table_list);
    }
    
    if (g_table_info.table_names) {
        for (int i = 0; i < g_table_info.count; i++) {
            free(g_table_info.table_names[i]);
        }
        free(g_table_info.table_names);
        free(g_table_info.row_counts);
    }
    
    /* Destroy session */
    odv_destroy_session(session);
    
    if (rc == ODV_OK) {
        printf("\nExport completed successfully!\n");
        return EXIT_SUCCESS;
    } else {
        printf("\nExport failed.\n");
        return EXIT_FAILURE;
    }
}

输出结果

./main /par/test.dmp -o /par/out2 -t T2
========================================
OraDB DUMP Viewer - CSV Exporter
Version: 3.1.0
========================================
Dump file: /par/test.dmp
Output directory: /par/out2
CSV delimiter: ','
Write header: Yes
Write types: No
========================================

Dump type: Oracle EXP

Exporting 1 specified tables...

[1/1] Exporting table: T2 -> /par/out2/T2.csv
Progress: 53% (1 rows processed, current table: T2)  ✓ Successfully exported

Export completed: 1/1 tables exported successfully.

Export completed successfully!

导出的csv

cat out2/T2.csv
A,B,C
1,abc,2022/02/22 00:00:00
Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐