example cleanup
[migration-tools.git] / text / csv2sql
1 #!/usr/bin/perl -w
2 use Getopt::Long;
3 use Text::CSV::Auto;
4 use Data::Dumper;
5 use DBI;
6 use File::Basename;
7
8 my $dbh;
9 my $cfg;
10 my $csv_config;
11
12 sub init {
13         our %config;
14         do '/openils/conf/offline-config.pl';
15         $dbh = DBI->connect( $config{dsn}, $config{usr}, $config{pw} ) or die $DBI::errstr;
16         $cfg = {
17                 schema => 'm_foo',
18                 auto_options => {
19                 }
20         };
21         our %CSV_options = (
22             binary => 1,
23             auto_diag => 1,
24             diag_verbose => 1,
25         );
26         $cfg->{auto_options}->{csv_options} = \%CSV_options;
27
28         GetOptions(
29                 'config=s' => \$csv_config,
30                 'no-legacy-prefix' => \($cfg->{no_legacy_prefix}),
31                 'use-no-headers-file' => \($cfg->{use_no_headers_file}),
32                 'add-x-migrate' => \($cfg->{add_x_migrate}),
33         'outfile=s' => \($cfg->{outfile}),
34                 'schema=s' => \($cfg->{schema}),
35                 'parent=s' => \($cfg->{parent}),
36                 'help|?' => \$help
37         );
38         if ($help || ((@ARGV == 0) && (-t STDIN))) {
39                 die qq^\n\t$0 [--config <CONFIG>] [--add-x-migrate] [--no-legacy-prefix] [--schema <schema>] [--parent <base table>] [--outfile <file to create>] <"clean" file from clean_csv script>\n\n^;
40         }
41         if ($csv_config && ! -e $csv_config) {
42                 die "$csv_config does not exist\n";
43         }
44         if ($csv_config && -e $csv_config) {
45                 do $csv_config;
46         }
47         if (! -e $ARGV[0]) {
48                 die "$ARGV[0] does not exist\n";
49         }
50 }
51
52 sub write_sql_sample {
53         my $cfg = shift;
54         my $info = shift;
55         my $fn = $cfg->{outfile} || $cfg->{auto_options}->{file} . '.sql';
56
57         print "\twriting $fn\n";
58         local *SQL;
59         open SQL, ">$fn";
60         print SQL "-- $cfg->{auto_options}->{file}\n/*\n";
61         open IN, $cfg->{auto_options}->{file};
62         foreach (1..5) {
63                 my $line = <IN>;
64                 print SQL $line;
65         }
66         close IN;
67         print SQL "*/\n";
68         return *SQL;
69 }
70
71 sub write_sql_table {
72         my $sql = shift;
73         my $cfg = shift;
74         my $info = shift;
75         my $fn = $cfg->{auto_options}->{file};
76         my @indices = ();
77
78         print "\twriting table definition\n";
79     if ($cfg->{parent}) {
80         $cfg->{table_name} = $cfg->{parent} . '_legacy';
81     } else {
82             $cfg->{table_name} = lc(basename($fn)); $cfg->{table_name} =~ s/[\-\. ]/_/g;
83     }
84         print $sql "DROP TABLE IF EXISTS $cfg->{schema}.$cfg->{table_name};\n";
85         print $sql "CREATE UNLOGGED TABLE $cfg->{schema}.$cfg->{table_name} (\n";
86         my $idx = 0;
87         if ($cfg->{add_x_migrate}) {
88                 print $sql "    x_migrate BOOLEAN\n";
89                 $idx++;
90                 push @indices, 'x_migrate';
91         }
92         foreach my $column (@{ $info }) {
93                 my $cn = $column->{'header'};
94                 if ($cn =~ /^x_/) {
95                         push @indices, $cn;
96                 }
97                 my $col_info = Dumper($column);
98                 $col_info =~ s/^\$VAR1 = //;
99                 print $sql "   " . ($idx++ ? ',' : ' ');
100                 print $sql "l_" unless $cfg->{no_legacy_prefix} or $column->{'header'} =~ /^x_/ or $column->{'header'} =~ /^l_/;
101         print $sql "$cn " . ($cn eq 'x_eg_bib_id' ? 'BIGINT' : 'TEXT');
102         print $sql " /*\n         $col_info   */\n";
103         }
104     if ($cfg->{parent}) {
105             print $sql ') INHERITS (' . $cfg->{schema} . '.' . $cfg->{parent} . ");\n";
106     } else {
107             print $sql ");\n";
108     }
109         foreach my $cn (@indices) {
110                 print $sql "CREATE INDEX ON $cfg->{schema}.$cfg->{table_name} ($cn);\n";
111         }
112 }
113
114 sub write_sql_loader {
115         my $sql = shift;
116         my $cfg = shift;
117         my $auto = shift;
118         my $info = shift;
119         my $fn = $cfg->{auto_options}->{file} . ($cfg->{use_no_headers_file} ? '.no_headers' : '');
120
121         print "\twriting copy statement\n";
122         print $sql "\n\\COPY $cfg->{schema}.$cfg->{table_name} (";
123     my $idx = 0;
124     foreach my $column (@{ $info }) {
125         print $sql ($idx++ ? ',' : '');
126         print $sql "l_" unless $cfg->{no_legacy_prefix} or $column->{'header'} =~ /^x_/ or $column->{'header'} =~ /^l_/;
127         print $sql $column->{'header'};
128     }
129     print $sql ") FROM '$fn'";
130     if ($auto->csv->sep_char eq chr(9) && ! defined $auto->csv->quote_char && ! defined $auto->csv->escape_char) {
131         # true .tsv, don't treat as csv
132     } elsif ($auto->csv->sep_char eq chr(9)) {
133         # probably good enough .tsv, don't treat as csv
134     } else {
135         print $sql " WITH csv " . ($cfg->{use_no_headers_file} ? "" : "header");
136         print $sql " delimiter " . $dbh->quote( $auto->csv->sep_char ) unless $dbh->quote( $auto->csv->sep_char ) eq 'NULL';
137         print $sql " quote " . $dbh->quote( $auto->csv->quote_char ) unless $dbh->quote( $auto->csv->quote_char ) eq 'NULL';
138         print $sql " escape " . $dbh->quote( $auto->csv->escape_char ) unless $dbh->quote( $auto->csv->escape_char ) eq 'NULL';
139     }
140         print $sql "\n";
141 }
142
143 sub main {
144         init();
145         foreach my $fn (@ARGV) {
146                 print "processing $fn\n";
147                 $cfg->{auto_options}->{file} = $fn;
148                 my $auto = Text::CSV::Auto->new($cfg->{auto_options});
149
150                 my $info = $auto->analyze();
151                 my $sql = write_sql_sample($cfg,$info);
152                 write_sql_table($sql,$cfg,$info);
153                 write_sql_loader($sql,$cfg,$auto,$info);
154                 close $sql;
155
156                 print "\tdone.\n";
157         }
158 }
159
160 main();
161