3 #=======================================================================
5 # File ID: 0f3555b6-70fd-11e5-89be-fefdb24f8e10
7 # Sort the rows in an SQLite database.
10 # ©opyleft 2015– Øyvind A. Holm <sunny@sunbase.org>
11 # License: GNU General Public License version 2 or later, see end of
12 # file for legal stuff.
13 #=======================================================================
33 $progname =~ s/^.*\/(.*?)$/$1/;
34 our $VERSION = '0.2.0';
39 my $SQLITE = "sqlite3";
43 Getopt
::Long
::Configure
('bundling');
46 'column|c=s' => \
@Columns,
47 'help|h' => \
$Opt{'help'},
48 'quiet|q+' => \
$Opt{'quiet'},
49 'verbose|v+' => \
$Opt{'verbose'},
50 'version' => \
$Opt{'version'},
52 ) || die("$progname: Option error. Use -h for help.\n");
54 $Opt{'verbose'} -= $Opt{'quiet'};
55 $Opt{'help'} && usage
(0);
56 if ($Opt{'version'}) {
61 my $sql_error = 0; # Is set to !0 if some sqlite3 error happened
66 if (!scalar(@Columns)) {
67 warn("$progname: Missing -c/--column option\n");
70 $ENV{'LC_COLLATE'} = 'C';
71 for my $file (@ARGV) {
72 sort_file
($file, @Columns) || return 1;
79 my ($file, @tabcol) = @_;
80 my $tmptable = "sortsqltmp";
85 if ($c !~ /^(\S+?)\.(\S+)$/) {
86 warn("$progname: \"$c\" is not a valid identifier\n");
91 if (!-r
$file || !-f
$file) {
92 warn("$progname: $file: File is not readable by you or " .
93 "is not a regular file\n");
97 my $backup = sprintf("%s.%s.bck", $file, sec_to_string
(mod_date
($file)));
98 if (!copy
($file, $backup)) {
99 warn("$progname: $backup: Cannot create backup file: $!\n");
103 msg
(1, "Sorting $file");
105 my ($table, $column);
107 if ($c =~ /^(\S+?)\.(\S+)$/) {
108 ($table, $column) = ($1, $2);
110 warn("$progname: This should not happen, invalid identifier " .
111 "\"$c\" even though it has been validated\n");
115 BEGIN EXCLUSIVE TRANSACTION;
117 CREATE TEMPORARY TABLE \"$tmptable\" AS
118 SELECT * FROM \"$table\";
119 DELETE FROM \"$table\";
120 INSERT INTO \"$table\"
121 SELECT * FROM \"$tmptable\" ORDER BY \"$column\";
122 DROP TABLE \"$tmptable\";
128 warn("$progname: $file: $SQLITE error, aborting\n");
137 # Return file modification timestamp {{{
140 my @stat_array = stat($File);
141 if (scalar(@stat_array)) {
142 $Retval = $stat_array[9];
144 warn("$progname: $File: Cannot stat file: $!\n");
151 # Convert seconds since 1970 to "yyyymmddThhmmss[.frac]Z" {{{
152 my ($Seconds, $Sep) = @_;
153 length($Seconds) || return '';
154 ($Seconds =~ /^-?(\d*)(\.\d+)?$/) || return undef;
155 my $Secfrac = ($Seconds =~ /^([\-\d]*)(\.\d+)$/) ?
1.0*$2 : "";
158 defined($Sep) || ($Sep = " ");
159 my @TA = gmtime($Seconds);
160 my($DateString) = sprintf("%04u%02u%02uT%02u%02u%02u%sZ",
161 $TA[5]+1900, $TA[4]+1, $TA[3],
162 $TA[2], $TA[1], $TA[0], $Secfrac);
172 msg
(3, "sql(): db = '$db'");
173 local(*CHLD_IN
, *CHLD_OUT
, *CHLD_ERR
);
175 my $pid = open3
(*CHLD_IN
, *CHLD_OUT
, *CHLD_ERR
, $SQLITE, $db) or (
177 msg
(0, "sql(): open3() error: $!"),
178 return "sql() error",
180 msg
(3, "sql(): sql = '$sql'");
181 print(CHLD_IN
"$sql\n") or msg
(0, "sql(): print CHLD_IN error: $!");
183 @retval = <CHLD_OUT
>;
184 msg
(3, "sql(): retval = '" . join('|', @retval) . "'");
185 my @child_stderr = <CHLD_ERR
>;
186 if (scalar(@child_stderr)) {
187 msg
(0, "$SQLITE error: " . join('', @child_stderr));
190 return join('', @retval);
195 # Print program version {{{
196 print("$progname $VERSION\n");
202 # Send the help message to stdout {{{
205 if ($Opt{'verbose'}) {
211 Sort the rows in an SQLite database. A backup of the previous version is
212 copied to a *.bck file containing the date of the file modification time
215 Usage: $progname [options] SQLite_database_file [...]
219 -c TABLE.COLUMN, --column TABLE.COLUMN
220 Sort COLUMN in TABLE. This option can be repeated to sort several
225 Be more quiet. Can be repeated to increase silence.
227 Increase level of verbosity. Can be repeated.
229 Print version information.
237 # Print a status message to stderr based on verbosity level {{{
238 my ($verbose_level, $Txt) = @_;
240 if ($Opt{'verbose'} >= $verbose_level) {
241 print(STDERR
"$progname: $Txt\n");
249 # This program is free software; you can redistribute it and/or modify
250 # it under the terms of the GNU General Public License as published by
251 # the Free Software Foundation; either version 2 of the License, or (at
252 # your option) any later version.
254 # This program is distributed in the hope that it will be useful, but
255 # WITHOUT ANY WARRANTY; without even the implied warranty of
256 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
257 # See the GNU General Public License for more details.
259 # You should have received a copy of the GNU General Public License
260 # along with this program.
261 # If not, see L<http://www.gnu.org/licenses/>.
263 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :