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.1';
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
);
176 my $pid = open3
(*CHLD_IN
, *CHLD_OUT
, *CHLD_ERR
, $SQLITE, $db) or (
178 msg
(0, "sql(): open3() error: $!"),
179 return "sql() error",
181 msg
(3, "sql(): sql = '$sql'");
182 print(CHLD_IN
"$sql\n") or msg
(0, "sql(): print CHLD_IN error: $!");
184 @retval = <CHLD_OUT
>;
185 msg
(3, "sql(): retval = '" . join('|', @retval) . "'");
186 my @child_stderr = <CHLD_ERR
>;
187 if (scalar(@child_stderr)) {
188 msg
(0, "$SQLITE error: " . join('', @child_stderr));
191 return join('', @retval);
196 # Print program version {{{
197 print("$progname $VERSION\n");
203 # Send the help message to stdout {{{
206 if ($Opt{'verbose'}) {
212 Sort the rows in an SQLite database. A backup of the previous version is
213 copied to a *.bck file containing the date of the file modification time
216 Usage: $progname [options] SQLite_database_file [...]
220 -c TABLE.COLUMN, --column TABLE.COLUMN
221 Sort COLUMN in TABLE. This option can be repeated to sort several
226 Be more quiet. Can be repeated to increase silence.
228 Increase level of verbosity. Can be repeated.
230 Print version information.
238 # Print a status message to stderr based on verbosity level {{{
239 my ($verbose_level, $Txt) = @_;
241 if ($Opt{'verbose'} >= $verbose_level) {
242 print(STDERR
"$progname: $Txt\n");
250 # This program is free software; you can redistribute it and/or modify
251 # it under the terms of the GNU General Public License as published by
252 # the Free Software Foundation; either version 2 of the License, or (at
253 # your option) any later version.
255 # This program is distributed in the hope that it will be useful, but
256 # WITHOUT ANY WARRANTY; without even the implied warranty of
257 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
258 # See the GNU General Public License for more details.
260 # You should have received a copy of the GNU General Public License
261 # along with this program.
262 # If not, see L<http://www.gnu.org/licenses/>.
264 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :