DeepSeek辅助将用于Windows的dmp文件导出DLL源代码改写成用于Linux
本文记录了将Oracle DMP文件解析工具从Python迁移到C语言的过程。首先尝试让美团龙猫改写Python代码为C语言,但CSV导出存在问题。随后发现GitHub上的OraDB-DUMP-Viewer项目,其核心解析模块使用C语言编写且跨平台。在Linux环境下编译时遇到多个Windows特有语法问题,通过宏定义替换__stdcall、_stricmp等关键字解决。针对缺少main函数的问题
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
更多推荐



所有评论(0)