2001-05-10 22:41:23 +08:00
|
|
|
/* This program reads in an xbase-dbf file and sends 'inserts' to an
|
|
|
|
PostgreSQL-server with the records in the xbase-file
|
|
|
|
|
2001-12-31 21:32:04 +08:00
|
|
|
M. Boekhold (maarten.boekhold@reuters.com) okt. 1995
|
2001-05-10 22:41:23 +08:00
|
|
|
oktober 1996: merged sources of dbf2msql.c and dbf2pg.c
|
|
|
|
oktober 1997: removed msql support
|
|
|
|
*/
|
2001-10-16 02:49:40 +08:00
|
|
|
#include "postgres_fe.h"
|
|
|
|
|
2001-05-10 22:41:23 +08:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#ifdef HAVE_TERMIOS_H
|
|
|
|
#include <termios.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ICONV_H
|
|
|
|
#include <iconv.h>
|
|
|
|
#endif
|
2002-01-10 09:11:45 +08:00
|
|
|
#ifdef HAVE_GETOPT_H
|
|
|
|
#include <getopt.h>
|
|
|
|
#endif
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-16 02:49:40 +08:00
|
|
|
#include "libpq-fe.h"
|
2001-05-10 22:41:23 +08:00
|
|
|
#include "dbf.h"
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
int verbose = 0,
|
|
|
|
upper = 0,
|
|
|
|
lower = 0,
|
|
|
|
create = 0,
|
|
|
|
fieldlow = 0;
|
|
|
|
int del = 0;
|
|
|
|
unsigned int begin = 0,
|
|
|
|
end = 0;
|
2001-05-10 22:41:23 +08:00
|
|
|
unsigned int t_block = 0;
|
2001-10-16 02:49:40 +08:00
|
|
|
|
2001-05-10 22:41:23 +08:00
|
|
|
#ifdef HAVE_ICONV_H
|
2001-10-25 13:50:21 +08:00
|
|
|
char *charset_from = NULL;
|
|
|
|
char *charset_to = "ISO-8859-1";
|
|
|
|
iconv_t iconv_d;
|
|
|
|
char convert_charset_buff[8192];
|
2001-05-10 22:41:23 +08:00
|
|
|
#endif
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
char *host = NULL;
|
|
|
|
char *dbase = "test";
|
|
|
|
char *table = "test";
|
|
|
|
char *username = NULL;
|
|
|
|
char *password = NULL;
|
|
|
|
char *subarg = NULL;
|
|
|
|
char escape_buff[8192];
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
void do_substitute(char *subarg, dbhead * dbh);
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2002-11-01 03:11:48 +08:00
|
|
|
static inline void strtoupper(char *string);
|
|
|
|
static inline void strtolower(char *string);
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
void do_create(PGconn *, char *, dbhead *);
|
|
|
|
void do_inserts(PGconn *, char *, dbhead *);
|
|
|
|
int check_table(PGconn *, char *);
|
|
|
|
|
|
|
|
char *Escape(char *);
|
2001-05-10 22:41:23 +08:00
|
|
|
|
|
|
|
#ifdef HAVE_ICONV_H
|
2001-10-25 13:50:21 +08:00
|
|
|
char *convert_charset(char *string);
|
2001-05-10 22:41:23 +08:00
|
|
|
#endif
|
2001-10-25 13:50:21 +08:00
|
|
|
void usage(void);
|
2001-05-10 22:41:23 +08:00
|
|
|
unsigned int isinteger(char *);
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
unsigned int
|
|
|
|
isinteger(char *buff)
|
|
|
|
{
|
|
|
|
char *i = buff;
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
while (*i != '\0')
|
|
|
|
{
|
|
|
|
if (i == buff)
|
2001-05-10 22:41:23 +08:00
|
|
|
if ((*i == '-') ||
|
2001-10-25 13:50:21 +08:00
|
|
|
(*i == '+'))
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
continue;
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
2001-12-31 07:09:42 +08:00
|
|
|
if (!isdigit((unsigned char) *i))
|
2001-10-25 13:50:21 +08:00
|
|
|
return 0;
|
2001-05-10 22:41:23 +08:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2002-11-01 03:11:48 +08:00
|
|
|
static inline void
|
2001-10-25 13:50:21 +08:00
|
|
|
strtoupper(char *string)
|
|
|
|
{
|
|
|
|
while (*string != '\0')
|
|
|
|
{
|
2001-12-31 07:09:42 +08:00
|
|
|
*string = toupper((unsigned char) *string);
|
2001-05-10 22:41:23 +08:00
|
|
|
string++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-11-01 03:11:48 +08:00
|
|
|
static inline void
|
2001-10-25 13:50:21 +08:00
|
|
|
strtolower(char *string)
|
|
|
|
{
|
|
|
|
while (*string != '\0')
|
|
|
|
{
|
2001-12-31 07:09:42 +08:00
|
|
|
*string = tolower((unsigned char) *string);
|
2001-05-10 22:41:23 +08:00
|
|
|
string++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: should this check for overflow? */
|
2001-10-25 13:50:21 +08:00
|
|
|
char *
|
|
|
|
Escape(char *string)
|
|
|
|
{
|
|
|
|
char *foo,
|
|
|
|
*bar;
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
foo = escape_buff;
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
bar = string;
|
|
|
|
while (*bar != '\0')
|
|
|
|
{
|
|
|
|
if ((*bar == '\t') ||
|
|
|
|
(*bar == '\n') ||
|
|
|
|
(*bar == '\\'))
|
|
|
|
*foo++ = '\\';
|
|
|
|
*foo++ = *bar++;
|
|
|
|
}
|
|
|
|
*foo = '\0';
|
|
|
|
|
|
|
|
return escape_buff;
|
|
|
|
}
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
#ifdef HAVE_ICONV_H
|
|
|
|
char *
|
|
|
|
convert_charset(char *string)
|
|
|
|
{
|
|
|
|
size_t in_size,
|
|
|
|
out_size,
|
|
|
|
nconv;
|
|
|
|
char *in_ptr,
|
|
|
|
*out_ptr;
|
|
|
|
|
|
|
|
in_size = strlen(string) + 1;
|
|
|
|
out_size = sizeof(convert_charset_buff);
|
|
|
|
in_ptr = string;
|
|
|
|
out_ptr = convert_charset_buff;
|
|
|
|
|
|
|
|
iconv(iconv_d, NULL, &in_size, &out_ptr, &out_size); /* necessary to reset
|
|
|
|
* state information */
|
|
|
|
while (in_size > 0)
|
2001-05-10 22:41:23 +08:00
|
|
|
{
|
|
|
|
nconv = iconv(iconv_d, &in_ptr, &in_size, &out_ptr, &out_size);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (nconv == (size_t) -1)
|
2001-05-10 22:41:23 +08:00
|
|
|
{
|
|
|
|
printf("WARNING: cannot convert charset of string \"%s\".\n",
|
2001-10-25 13:50:21 +08:00
|
|
|
string);
|
|
|
|
strcpy(convert_charset_buff, string);
|
2001-05-10 22:41:23 +08:00
|
|
|
return convert_charset_buff;
|
|
|
|
}
|
|
|
|
}
|
2001-10-25 13:50:21 +08:00
|
|
|
*out_ptr = 0; /* terminate output string */
|
2001-05-10 22:41:23 +08:00
|
|
|
return convert_charset_buff;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
int
|
|
|
|
check_table(PGconn *conn, char *table)
|
|
|
|
{
|
|
|
|
char *q = "select relname from pg_class where "
|
|
|
|
"relkind='r' and relname !~* '^pg'";
|
|
|
|
PGresult *res;
|
|
|
|
int i = 0;
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if (!(res = PQexec(conn, q)))
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("%s\n", PQerrorMessage(conn));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
for (i = 0; i < PQntuples(res); i++)
|
|
|
|
{
|
|
|
|
if (!strcmp(table, PQgetvalue(res, i, PQfnumber(res, "relname"))))
|
2001-05-10 22:41:23 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
void
|
|
|
|
usage(void)
|
|
|
|
{
|
2001-10-16 02:49:40 +08:00
|
|
|
printf("dbf2pg\n"
|
2001-10-25 13:50:21 +08:00
|
|
|
"usage: dbf2pg [-u | -l] [-h hostname] [-W] [-U username]\n"
|
|
|
|
" [-B transaction_size] [-F charset_from [-T charset_to]]\n"
|
2003-07-31 10:12:43 +08:00
|
|
|
" [-s oldname=[newname][,oldname=[newname][...]]] [-d dbase]\n"
|
2001-10-25 13:50:21 +08:00
|
|
|
" [-t table] [-c | -D] [-f] [-v[v]] dbf-file\n");
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* patch submitted by Jeffrey Y. Sue <jysue@aloha.net> */
|
2003-03-11 06:28:22 +08:00
|
|
|
/* Provides functionality for substituting dBase-fieldnames for others */
|
2001-05-10 22:41:23 +08:00
|
|
|
/* Mainly for avoiding conflicts between fieldnames and SQL-reserved */
|
|
|
|
/* keywords */
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
void
|
|
|
|
do_substitute(char *subarg, dbhead * dbh)
|
2001-05-10 22:41:23 +08:00
|
|
|
{
|
2001-10-25 13:50:21 +08:00
|
|
|
/* NOTE: subarg is modified in this function */
|
|
|
|
int i,
|
|
|
|
bad;
|
|
|
|
char *p,
|
|
|
|
*oldname,
|
|
|
|
*newname;
|
|
|
|
|
|
|
|
if (!subarg)
|
|
|
|
return;
|
|
|
|
if (verbose > 1)
|
|
|
|
printf("Substituting new field names\n");
|
|
|
|
/* use strstr instead of strtok because of possible empty tokens */
|
|
|
|
oldname = subarg;
|
|
|
|
while (oldname && strlen(oldname) && (p = strstr(oldname, "=")))
|
|
|
|
{
|
|
|
|
*p = '\0'; /* mark end of oldname */
|
|
|
|
newname = ++p; /* point past \0 of oldname */
|
|
|
|
if (strlen(newname))
|
|
|
|
{ /* if not an empty string */
|
|
|
|
p = strstr(newname, ",");
|
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
*p = '\0'; /* mark end of newname */
|
|
|
|
p++; /* point past where the comma was */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (strlen(newname) >= DBF_NAMELEN)
|
|
|
|
{
|
|
|
|
printf("Truncating new field name %s to %d chars\n",
|
|
|
|
newname, DBF_NAMELEN - 1);
|
|
|
|
newname[DBF_NAMELEN - 1] = '\0';
|
|
|
|
}
|
|
|
|
bad = 1;
|
|
|
|
for (i = 0; i < dbh->db_nfields; i++)
|
|
|
|
{
|
|
|
|
if (strcmp(dbh->db_fields[i].db_name, oldname) == 0)
|
|
|
|
{
|
|
|
|
bad = 0;
|
|
|
|
strcpy(dbh->db_fields[i].db_name, newname);
|
|
|
|
if (verbose > 1)
|
|
|
|
{
|
|
|
|
printf("Substitute old:%s new:%s\n",
|
|
|
|
oldname, newname);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bad)
|
|
|
|
{
|
|
|
|
printf("Warning: old field name %s not found\n",
|
|
|
|
oldname);
|
|
|
|
}
|
|
|
|
oldname = p;
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
2001-10-25 13:50:21 +08:00
|
|
|
} /* do_substitute */
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
void
|
|
|
|
do_create(PGconn *conn, char *table, dbhead * dbh)
|
|
|
|
{
|
|
|
|
char *query;
|
|
|
|
char t[20];
|
|
|
|
int i,
|
|
|
|
length;
|
|
|
|
PGresult *res;
|
|
|
|
|
|
|
|
if (verbose > 1)
|
|
|
|
printf("Building CREATE-clause\n");
|
|
|
|
|
|
|
|
if (!(query = (char *) malloc(
|
|
|
|
(dbh->db_nfields * 40) + 29 + strlen(table))))
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
fprintf(stderr, "Memory allocation error in function do_create\n");
|
|
|
|
PQfinish(conn);
|
|
|
|
close(dbh->db_fd);
|
|
|
|
free(dbh);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(query, "CREATE TABLE %s (", table);
|
|
|
|
length = strlen(query);
|
2001-10-25 13:50:21 +08:00
|
|
|
for (i = 0; i < dbh->db_nfields; i++)
|
|
|
|
{
|
|
|
|
if (!strlen(dbh->db_fields[i].db_name))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
/* skip field if length of name == 0 */
|
|
|
|
}
|
|
|
|
if ((strlen(query) != length))
|
|
|
|
strcat(query, ",");
|
|
|
|
|
|
|
|
if (fieldlow)
|
|
|
|
strtolower(dbh->db_fields[i].db_name);
|
|
|
|
|
|
|
|
strcat(query, dbh->db_fields[i].db_name);
|
|
|
|
switch (dbh->db_fields[i].db_type)
|
|
|
|
{
|
|
|
|
case 'D':
|
|
|
|
strcat(query, " date");
|
|
|
|
break;
|
|
|
|
case 'C':
|
|
|
|
if (dbh->db_fields[i].db_flen > 1)
|
|
|
|
{
|
|
|
|
strcat(query, " varchar");
|
2002-08-15 10:58:29 +08:00
|
|
|
snprintf(t, 20, "(%d)",
|
2002-09-05 04:31:48 +08:00
|
|
|
dbh->db_fields[i].db_flen);
|
2001-10-25 13:50:21 +08:00
|
|
|
strcat(query, t);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
strcat(query, " char");
|
|
|
|
break;
|
|
|
|
case 'N':
|
|
|
|
if (dbh->db_fields[i].db_dec != 0)
|
|
|
|
strcat(query, " real");
|
|
|
|
else
|
|
|
|
strcat(query, " int");
|
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
strcat(query, " char");
|
|
|
|
break;
|
|
|
|
}
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
strcat(query, ")");
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if (verbose > 1)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("Sending create-clause\n");
|
|
|
|
printf("%s\n", query);
|
|
|
|
}
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if ((res = PQexec(conn, query)) == NULL)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
fprintf(stderr, "Error creating table!\n");
|
|
|
|
fprintf(stderr, "Detailed report: %s\n", PQerrorMessage(conn));
|
2001-10-25 13:50:21 +08:00
|
|
|
close(dbh->db_fd);
|
|
|
|
free(dbh);
|
|
|
|
free(query);
|
|
|
|
PQfinish(conn);
|
|
|
|
exit(1);
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
PQclear(res);
|
|
|
|
free(query);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: can be optimized to not use strcat, but it is worth the effort? */
|
2001-10-25 13:50:21 +08:00
|
|
|
void
|
|
|
|
do_inserts(PGconn *conn, char *table, dbhead * dbh)
|
|
|
|
{
|
|
|
|
PGresult *res;
|
|
|
|
field *fields;
|
|
|
|
int i,
|
|
|
|
h,
|
2003-07-31 10:12:43 +08:00
|
|
|
j,
|
2001-10-25 13:50:21 +08:00
|
|
|
result;
|
|
|
|
char *query,
|
|
|
|
*foo;
|
2002-08-15 10:58:29 +08:00
|
|
|
char pgdate[11];
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if (verbose > 1)
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("Inserting records\n");
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
h = 2; /* 2 because of terminating \n\0 */
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
for (i = 0; i < dbh->db_nfields; i++)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
h += dbh->db_fields[i].db_flen > 2 ?
|
2001-10-25 13:50:21 +08:00
|
|
|
dbh->db_fields[i].db_flen :
|
|
|
|
2; /* account for possible NULL values (\N) */
|
|
|
|
h += 1; /* the delimiter */
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
/*
|
|
|
|
* make sure we can build the COPY query, note that we don't need to
|
|
|
|
* just add this value, since the COPY query is a separate query (see
|
|
|
|
* below)
|
|
|
|
*/
|
|
|
|
if (h < 17 + strlen(table))
|
|
|
|
h = 17 + strlen(table);
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if (!(query = (char *) malloc(h)))
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
PQfinish(conn);
|
|
|
|
fprintf(stderr,
|
2001-10-25 13:50:21 +08:00
|
|
|
"Memory allocation error in function do_inserts (query)\n");
|
2001-05-10 22:41:23 +08:00
|
|
|
close(dbh->db_fd);
|
|
|
|
free(dbh);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if ((fields = dbf_build_record(dbh)) == (field *) DBF_ERROR)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"Couldn't allocate memory for record in do_insert\n");
|
2001-05-10 22:41:23 +08:00
|
|
|
PQfinish(conn);
|
2001-10-25 13:50:21 +08:00
|
|
|
free(query);
|
|
|
|
dbf_close(dbh);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (end == 0) /* "end" is a user option, if not
|
|
|
|
* specified, */
|
|
|
|
end = dbh->db_records; /* then all records are processed. */
|
|
|
|
|
|
|
|
if (t_block == 0) /* user not specified transaction block
|
|
|
|
* size */
|
|
|
|
t_block = end - begin; /* then we set it to be the full data */
|
|
|
|
|
|
|
|
for (i = begin; i < end; i++)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
/* we need to start a new transaction and COPY statement */
|
2001-10-25 13:50:21 +08:00
|
|
|
if (((i - begin) % t_block) == 0)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
if (verbose > 1)
|
|
|
|
fprintf(stderr, "Transaction: START\n");
|
|
|
|
res = PQexec(conn, "BEGIN");
|
2001-10-25 13:50:21 +08:00
|
|
|
if (res == NULL)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
fprintf(stderr, "Error starting transaction!\n");
|
|
|
|
fprintf(stderr, "Detailed report: %s\n", PQerrorMessage(conn));
|
2001-10-25 13:50:21 +08:00
|
|
|
exit(1);
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
|
|
|
sprintf(query, "COPY %s FROM stdin", table);
|
|
|
|
res = PQexec(conn, query);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (res == NULL)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
fprintf(stderr, "Error starting COPY!\n");
|
|
|
|
fprintf(stderr, "Detailed report: %s\n", PQerrorMessage(conn));
|
2001-10-25 13:50:21 +08:00
|
|
|
exit(1);
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* build line and submit */
|
2001-10-25 13:50:21 +08:00
|
|
|
result = dbf_get_record(dbh, fields, i);
|
|
|
|
if (result == DBF_VALID)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
query[0] = '\0';
|
2003-08-04 08:43:34 +08:00
|
|
|
j = 0; /* counter for fields in the output */
|
2001-10-25 13:50:21 +08:00
|
|
|
for (h = 0; h < dbh->db_nfields; h++)
|
|
|
|
{
|
2003-08-04 08:43:34 +08:00
|
|
|
if (!strlen(fields[h].db_name)) /* When the new fieldname
|
|
|
|
* is empty, the field is
|
|
|
|
* skipped */
|
2001-05-10 22:41:23 +08:00
|
|
|
continue;
|
2003-07-31 10:12:43 +08:00
|
|
|
else
|
|
|
|
j++;
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2003-07-31 10:12:43 +08:00
|
|
|
if (j > 1) /* not for the first field! */
|
2001-10-25 13:50:21 +08:00
|
|
|
strcat(query, "\t"); /* COPY statement field
|
|
|
|
* separator */
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if (upper)
|
|
|
|
strtoupper(fields[h].db_contents);
|
|
|
|
if (lower)
|
2001-05-10 22:41:23 +08:00
|
|
|
strtolower(fields[h].db_contents);
|
|
|
|
|
|
|
|
foo = fields[h].db_contents;
|
|
|
|
#ifdef HAVE_ICONV_H
|
2001-10-25 13:50:21 +08:00
|
|
|
if (charset_from)
|
2001-05-10 22:41:23 +08:00
|
|
|
foo = convert_charset(foo);
|
|
|
|
#endif
|
|
|
|
foo = Escape(foo);
|
|
|
|
|
|
|
|
/* handle the date first - liuk */
|
2001-10-25 13:50:21 +08:00
|
|
|
if (fields[h].db_type == 'D')
|
|
|
|
{
|
|
|
|
if ((strlen(foo) == 8) && isinteger(foo))
|
|
|
|
{
|
2002-08-15 10:58:29 +08:00
|
|
|
snprintf(pgdate, 11, "%c%c%c%c-%c%c-%c%c",
|
2002-09-05 04:31:48 +08:00
|
|
|
foo[0], foo[1], foo[2], foo[3],
|
|
|
|
foo[4], foo[5], foo[6], foo[7]);
|
2001-10-25 13:50:21 +08:00
|
|
|
strcat(query, pgdate);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* empty field must be inserted as NULL value in
|
|
|
|
* this way
|
|
|
|
*/
|
|
|
|
strcat(query, "\\N");
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((fields[h].db_type == 'N') &&
|
2001-10-25 13:50:21 +08:00
|
|
|
(fields[h].db_dec == 0))
|
|
|
|
{
|
|
|
|
if (isinteger(foo))
|
2001-05-10 22:41:23 +08:00
|
|
|
strcat(query, foo);
|
2001-10-25 13:50:21 +08:00
|
|
|
else
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
strcat(query, "\\N");
|
|
|
|
if (verbose)
|
|
|
|
fprintf(stderr, "Illegal numeric value found "
|
2001-10-25 13:50:21 +08:00
|
|
|
"in record %d, field \"%s\"\n",
|
|
|
|
i, fields[h].db_name);
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
2001-10-25 13:50:21 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
strcat(query, foo); /* must be character */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strcat(query, "\n");
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if ((verbose > 1) && ((i % 100) == 0))
|
|
|
|
{ /* Only show every 100 */
|
|
|
|
printf("Inserting record %d\n", i); /* records. */
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
|
|
|
PQputline(conn, query);
|
|
|
|
|
|
|
|
}
|
|
|
|
/* we need to end this copy and transaction */
|
2001-10-25 13:50:21 +08:00
|
|
|
if (((i - begin) % t_block) == t_block - 1)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
if (verbose > 1)
|
|
|
|
fprintf(stderr, "Transaction: END\n");
|
|
|
|
PQputline(conn, "\\.\n");
|
2001-10-25 13:50:21 +08:00
|
|
|
if (PQendcopy(conn) != 0)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
fprintf(stderr, "Something went wrong while copying. Check "
|
2001-10-25 13:50:21 +08:00
|
|
|
"your tables!\n");
|
2001-05-10 22:41:23 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
res = PQexec(conn, "END");
|
2001-10-25 13:50:21 +08:00
|
|
|
if (res == NULL)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
fprintf(stderr, "Error committing work!\n");
|
|
|
|
fprintf(stderr, "Detailed report: %s\n", PQerrorMessage(conn));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* last row copied in, end copy and transaction */
|
|
|
|
/* remember, i is now 1 greater then when we left the loop */
|
2001-10-25 13:50:21 +08:00
|
|
|
if (((i - begin) % t_block) != 0)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
if (verbose > 1)
|
|
|
|
fprintf(stderr, "Transaction: END\n");
|
|
|
|
PQputline(conn, "\\.\n");
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if (PQendcopy(conn) != 0)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
fprintf(stderr, "Something went wrong while copying. Check "
|
2001-10-25 13:50:21 +08:00
|
|
|
"your tables!\n");
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
|
|
|
res = PQexec(conn, "END");
|
2001-10-25 13:50:21 +08:00
|
|
|
if (res == NULL)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
fprintf(stderr, "Error committing work!\n");
|
|
|
|
fprintf(stderr, "Detailed report: %s\n", PQerrorMessage(conn));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dbf_free_record(dbh, fields);
|
|
|
|
|
|
|
|
free(query);
|
|
|
|
}
|
|
|
|
|
2001-10-19 05:57:11 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
2001-05-10 22:41:23 +08:00
|
|
|
{
|
2001-10-25 13:50:21 +08:00
|
|
|
PGconn *conn;
|
2001-05-10 22:41:23 +08:00
|
|
|
int i;
|
2001-10-25 13:50:21 +08:00
|
|
|
extern int optind;
|
|
|
|
extern char *optarg;
|
|
|
|
char *query;
|
|
|
|
dbhead *dbh;
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2002-01-10 09:11:45 +08:00
|
|
|
while ((i = getopt(argc, argv, "DWflucvh:b:e:d:t:s:B:U:F:T:")) != -1)
|
2001-10-25 13:50:21 +08:00
|
|
|
{
|
|
|
|
switch (i)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
case 'D':
|
2001-10-25 13:50:21 +08:00
|
|
|
if (create)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
usage();
|
|
|
|
printf("Can't use -c and -D at the same time!\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
del = 1;
|
|
|
|
break;
|
|
|
|
case 'W':
|
2001-10-25 13:50:21 +08:00
|
|
|
password = simple_prompt("Password: ", 100, 0);
|
2001-05-10 22:41:23 +08:00
|
|
|
break;
|
|
|
|
case 'f':
|
2001-10-25 13:50:21 +08:00
|
|
|
fieldlow = 1;
|
2001-05-10 22:41:23 +08:00
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
verbose++;
|
|
|
|
break;
|
|
|
|
case 'c':
|
2001-10-25 13:50:21 +08:00
|
|
|
if (del)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
usage();
|
|
|
|
printf("Can't use -c and -D at the same time!\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2001-10-25 13:50:21 +08:00
|
|
|
create = 1;
|
2001-05-10 22:41:23 +08:00
|
|
|
break;
|
|
|
|
case 'l':
|
2001-10-25 13:50:21 +08:00
|
|
|
lower = 1;
|
2001-05-10 22:41:23 +08:00
|
|
|
break;
|
|
|
|
case 'u':
|
2001-10-25 13:50:21 +08:00
|
|
|
if (lower)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
usage();
|
|
|
|
printf("Can't use -u and -l at the same time!\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2001-10-25 13:50:21 +08:00
|
|
|
upper = 1;
|
2001-05-10 22:41:23 +08:00
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
begin = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
end = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'h':
|
2001-10-25 13:50:21 +08:00
|
|
|
host = (char *) strdup(optarg);
|
2001-05-10 22:41:23 +08:00
|
|
|
break;
|
|
|
|
case 'd':
|
2001-10-25 13:50:21 +08:00
|
|
|
dbase = (char *) strdup(optarg);
|
2001-05-10 22:41:23 +08:00
|
|
|
break;
|
|
|
|
case 't':
|
2001-10-25 13:50:21 +08:00
|
|
|
table = (char *) strdup(optarg);
|
|
|
|
break;
|
2001-05-10 22:41:23 +08:00
|
|
|
case 's':
|
2001-10-25 13:50:21 +08:00
|
|
|
subarg = (char *) strdup(optarg);
|
2001-05-10 22:41:23 +08:00
|
|
|
break;
|
|
|
|
case 'B':
|
|
|
|
t_block = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'U':
|
2001-10-25 13:50:21 +08:00
|
|
|
username = (char *) strdup(optarg);
|
2001-05-10 22:41:23 +08:00
|
|
|
break;
|
2001-12-21 12:30:59 +08:00
|
|
|
#ifdef HAVE_ICONV_H
|
2001-05-10 22:41:23 +08:00
|
|
|
case 'F':
|
2001-10-25 13:50:21 +08:00
|
|
|
charset_from = (char *) strdup(optarg);
|
2001-05-10 22:41:23 +08:00
|
|
|
break;
|
|
|
|
case 'T':
|
2001-10-25 13:50:21 +08:00
|
|
|
charset_to = (char *) strdup(optarg);
|
2001-05-10 22:41:23 +08:00
|
|
|
break;
|
2001-12-21 12:30:59 +08:00
|
|
|
#endif
|
2001-05-10 22:41:23 +08:00
|
|
|
case ':':
|
|
|
|
usage();
|
|
|
|
printf("missing argument!\n");
|
|
|
|
exit(1);
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
usage();
|
2001-10-25 13:50:21 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: Ivan thinks this is bad: printf("unknown
|
|
|
|
* argument: %s\n", argv[0]);
|
|
|
|
*/
|
2001-05-10 22:41:23 +08:00
|
|
|
exit(1);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
argc -= optind;
|
|
|
|
argv = &argv[optind];
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if (argc != 1)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
usage();
|
2001-10-25 13:50:21 +08:00
|
|
|
if (username)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(username);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (password)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(password);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_ICONV_H
|
2001-10-25 13:50:21 +08:00
|
|
|
if (charset_from)
|
2001-05-10 22:41:23 +08:00
|
|
|
{
|
2001-10-25 13:50:21 +08:00
|
|
|
if (verbose > 1)
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("Setting conversion from charset \"%s\" to \"%s\".\n",
|
2001-10-25 13:50:21 +08:00
|
|
|
charset_from, charset_to);
|
|
|
|
iconv_d = iconv_open(charset_to, charset_from);
|
|
|
|
if (iconv_d == (iconv_t) - 1)
|
2001-05-10 22:41:23 +08:00
|
|
|
{
|
|
|
|
printf("Cannot convert from charset \"%s\" to charset \"%s\".\n",
|
2001-10-25 13:50:21 +08:00
|
|
|
charset_from, charset_to);
|
2001-05-10 22:41:23 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if (verbose > 1)
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("Opening dbf-file\n");
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if ((dbh = dbf_open(argv[0], O_RDONLY)) == (dbhead *) - 1)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
fprintf(stderr, "Couldn't open xbase-file %s\n", argv[0]);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (username)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(username);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (password)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(password);
|
2001-12-21 12:30:59 +08:00
|
|
|
#ifdef HAVE_ICONV_H
|
2001-10-25 13:50:21 +08:00
|
|
|
if (charset_from)
|
2001-05-10 22:41:23 +08:00
|
|
|
iconv_close(iconv_d);
|
2001-12-21 12:30:59 +08:00
|
|
|
#endif
|
2001-05-10 22:41:23 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fieldlow)
|
2001-10-25 13:50:21 +08:00
|
|
|
for (i = 0; i < dbh->db_nfields; i++)
|
|
|
|
strtolower(dbh->db_fields[i].db_name);
|
2001-05-10 22:41:23 +08:00
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if (verbose)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("dbf-file: %s, PG-dbase: %s, PG-table: %s\n", argv[0],
|
2001-10-25 13:50:21 +08:00
|
|
|
dbase,
|
|
|
|
table);
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("Number of records: %ld\n", dbh->db_records);
|
|
|
|
printf("NAME:\t\tLENGTH:\t\tTYPE:\n");
|
|
|
|
printf("-------------------------------------\n");
|
2001-10-25 13:50:21 +08:00
|
|
|
for (i = 0; i < dbh->db_nfields; i++)
|
|
|
|
{
|
|
|
|
printf("%-12s\t%7d\t\t%5c\n", dbh->db_fields[i].db_name,
|
|
|
|
dbh->db_fields[i].db_flen,
|
|
|
|
dbh->db_fields[i].db_type);
|
2001-05-10 22:41:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if (verbose > 1)
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("Making connection to PG-server\n");
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
conn = PQsetdbLogin(host, NULL, NULL, NULL, dbase, username, password);
|
|
|
|
if (PQstatus(conn) != CONNECTION_OK)
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
fprintf(stderr, "Couldn't get a connection with the ");
|
|
|
|
fprintf(stderr, "designated host!\n");
|
|
|
|
fprintf(stderr, "Detailed report: %s\n", PQerrorMessage(conn));
|
|
|
|
close(dbh->db_fd);
|
|
|
|
free(dbh);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (username)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(username);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (password)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(password);
|
2001-12-21 12:30:59 +08:00
|
|
|
#ifdef HAVE_ICONV_H
|
2001-10-25 13:50:21 +08:00
|
|
|
if (charset_from)
|
2001-05-10 22:41:23 +08:00
|
|
|
iconv_close(iconv_d);
|
2001-12-21 12:30:59 +08:00
|
|
|
#endif
|
2001-05-10 22:41:23 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2002-10-19 02:41:22 +08:00
|
|
|
PQexec(conn, "SET search_path = public");
|
|
|
|
|
2001-05-10 22:41:23 +08:00
|
|
|
/* Substitute field names */
|
|
|
|
do_substitute(subarg, dbh);
|
|
|
|
|
|
|
|
/* create table if specified, else check if target table exists */
|
2001-10-25 13:50:21 +08:00
|
|
|
if (!create)
|
|
|
|
{
|
|
|
|
if (!check_table(conn, table))
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("Table does not exist!\n");
|
2001-10-25 13:50:21 +08:00
|
|
|
if (username)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(username);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (password)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(password);
|
2001-12-21 12:30:59 +08:00
|
|
|
#ifdef HAVE_ICONV_H
|
2001-10-25 13:50:21 +08:00
|
|
|
if (charset_from)
|
2001-05-10 22:41:23 +08:00
|
|
|
iconv_close(iconv_d);
|
2001-12-21 12:30:59 +08:00
|
|
|
#endif
|
2001-05-10 22:41:23 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
2001-10-25 13:50:21 +08:00
|
|
|
if (del)
|
|
|
|
{
|
|
|
|
if (!(query = (char *) malloc(13 + strlen(table))))
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("Memory-allocation error in main (delete)!\n");
|
|
|
|
close(dbh->db_fd);
|
|
|
|
free(dbh);
|
|
|
|
PQfinish(conn);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (username)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(username);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (password)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(password);
|
2001-12-21 12:30:59 +08:00
|
|
|
#ifdef HAVE_ICONV_H
|
2001-10-25 13:50:21 +08:00
|
|
|
if (charset_from)
|
2001-05-10 22:41:23 +08:00
|
|
|
iconv_close(iconv_d);
|
2001-12-21 12:30:59 +08:00
|
|
|
#endif
|
2001-05-10 22:41:23 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
2001-10-25 13:50:21 +08:00
|
|
|
if (verbose > 1)
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("Deleting from original table\n");
|
|
|
|
sprintf(query, "DELETE FROM %s", table);
|
|
|
|
PQexec(conn, query);
|
|
|
|
free(query);
|
|
|
|
}
|
2001-10-25 13:50:21 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!(query = (char *) malloc(12 + strlen(table))))
|
|
|
|
{
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("Memory-allocation error in main (drop)!\n");
|
|
|
|
close(dbh->db_fd);
|
|
|
|
free(dbh);
|
|
|
|
PQfinish(conn);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (username)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(username);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (password)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(password);
|
2001-12-21 12:30:59 +08:00
|
|
|
#ifdef HAVE_ICONV_H
|
2001-10-25 13:50:21 +08:00
|
|
|
if (charset_from)
|
2001-05-10 22:41:23 +08:00
|
|
|
iconv_close(iconv_d);
|
2001-12-21 12:30:59 +08:00
|
|
|
#endif
|
2001-05-10 22:41:23 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
2001-10-25 13:50:21 +08:00
|
|
|
if (verbose > 1)
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("Dropping original table (if one exists)\n");
|
|
|
|
sprintf(query, "DROP TABLE %s", table);
|
|
|
|
PQexec(conn, query);
|
|
|
|
free(query);
|
|
|
|
|
|
|
|
/* Build a CREATE-clause
|
|
|
|
*/
|
|
|
|
do_create(conn, table, dbh);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build an INSERT-clause
|
|
|
|
*/
|
|
|
|
PQexec(conn, "SET DATESTYLE TO 'ISO';");
|
|
|
|
do_inserts(conn, table, dbh);
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
if (verbose > 1)
|
2001-05-10 22:41:23 +08:00
|
|
|
printf("Closing up....\n");
|
|
|
|
|
2001-10-25 13:50:21 +08:00
|
|
|
close(dbh->db_fd);
|
|
|
|
free(dbh);
|
|
|
|
PQfinish(conn);
|
|
|
|
if (username)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(username);
|
2001-10-25 13:50:21 +08:00
|
|
|
if (password)
|
2001-05-10 22:41:23 +08:00
|
|
|
free(password);
|
2001-12-21 12:30:59 +08:00
|
|
|
#ifdef HAVE_ICONV_H
|
2001-10-25 13:50:21 +08:00
|
|
|
if (charset_from)
|
2001-05-10 22:41:23 +08:00
|
|
|
iconv_close(iconv_d);
|
2001-12-21 12:30:59 +08:00
|
|
|
#endif
|
2001-05-10 22:41:23 +08:00
|
|
|
exit(0);
|
|
|
|
}
|