Syntax: $program [-m|-s REGEXP [-t TABLE] [-c0 1] ] [SQL QUERY] [-q] [-h]
-m /REGEXP/ Match lines and store the captured values for matching lines.
-s /REGEXP/ Split lines and store the split values. Use either -m or -s.
-c0 Default. Store the entire line in column "c0".
-t TABLE Default "t".
-q Quiet. Nothing on STDERR.
-h Display even more help.
SQL QUERY Execute the query and output the matching line values.
####
texql.pl "--m=/^(\([^:]+):(\\w+)/" < debuglog.txt
cat some_random_file | texql.pl -s /:/ select c0 from t where c1 = 0
texql.pl --t=another_table -m /^(\\w+)+/ < all_names.txt
texql.pl 'select distinct(c1) from another_table' > distinct_name.txt
####
#!/use/local/bin/perl -w
$|++;
use strict;
use Getopt::Long;
use DBI;
our $PROGRAM = "TexQL";
our $VERSION = "0.0.1";
our $DATE = "2004-03-28";
our $AUTHOR = "johanl\@DarSerMan.com";
my $program = lc($PROGRAM);
my $syntax = qq {$PROGRAM - $VERSION - $DATE - $AUTHOR
Load text into a table and query it using SQL.
Syntax: $program [-m|-s REGEXP [-t TABLE] [-c0 1] ] [SQL QUERY] [-q] [-h]
-m /REGEXP/ Match lines and store the captured values for matching lines.
-s /REGEXP/ Split lines and store the split values. Use either -m or -s.
-c0 Default. Store the entire line in column "c0".
-t TABLE Default "t".
-q Quiet. Nothing on STDERR.
-h Display even more help.
SQL QUERY Execute the query and output the matching line values.
Read lines from STDIN and populate the table specified by -
t. The table is automatically re-created with the columns
c1, c2, c3, etc. matching the result of the m// or split().
If -c0 is specified, the column c0 contains the entire line.
};
my $helpText = qq {
= Examples =
texql.pl "--m=/^(\([^:]+):(\\w+)/" < debuglog.txt
cat some_random_file | texql.pl -s /:/ select c0 from t where c1 = 0
texql.pl --t=another_table -m /^(\\w+)+/ < all_names.txt
texql.pl 'select distinct(c1) from another_table' > distinct_name.txt
= Matching =
How many columns are stored in the table? The first line
stored determines the number of columns.
= Database location =
The text is stored in an SQLite database file (the location
is determined by the enviroment variable TEXQL_PATH or
USERPROFILE or HOME or TEMP or "." ). };
main();
sub main {
my ($sMatch, $rexMatch) = ("", undef);
my ($sSplit, $rexSplit) = ("", undef);
my $table = "t";
my $c0 = 1;
my $quiet = 0;
my $help = 0;
my $commitEvery = 1000;
GetOptions(
"m:s" => \$sMatch,
"s:s" => \$sSplit,
"c0" => \$c0,
"t:s" => \$table,
"q" => \$quiet,
"h" => \$help,
);
$help and die("$syntax$helpText\n");
$table and $table =~ s/\W//gs;
my $firstColNumber = $c0 ? 0 : 1;
$sMatch and $sSplit and die("$syntax\nUse EITHER -m or -s\n");
my $sqlQuery = join(" ", @ARGV);
($sMatch || $sSplit || $sqlQuery) or die($syntax);
close(STDERR) if($quiet);
#Establish database environment
my $fileDb = ($ENV{uc($PROGRAM) . "_PATH"} || $ENV{USERPROFILE} || $ENV{HOME} || $ENV{TEMP} || ".") . "/." . lc($PROGRAM) . ".dat";
my $connect = "dbi:SQLite:dbname=$fileDb";
my $oDbh = DBI->connect($connect, "", "") or die("Could not connect to database ($connect)\n");
$oDbh->{RaiseError} = 1;
$oDbh->{AutoCommit} = 0;
if($sMatch || $sSplit) {
if($sMatch) {
$rexMatch = eval "qr$sMatch";
die("Invalid match rex ($sMatch) ($@)\n") if($@);
} else {
$rexSplit = eval "qr$sSplit";
die("Invalid split rex ($sSplit) ($@)\n") if($@);
}
#Parse STDIN
my ($isTableCreated, $lineMatchCount, $lineCount) = (0, 0, 0);
my $valueCount = undef;
my $oSth = undef;
while(my $line = ) {
chomp($line);
$lineCount++;
my @aVal;
if($rexMatch) {
@aVal = ($line =~ $rexMatch) or next;
} else {
no warnings;
@aVal = split($rexSplit, $line, $valueCount);
}
$lineMatchCount++;
$valueCount = @aVal if(!defined($valueCount));
@aVal = @aVal[0 .. $valueCount - 1];
$isTableCreated ||= createTable($oDbh, $table, $valueCount, $firstColNumber) or die("Could not create table\n");
#Insert
if(!$oSth) {
my $placeholders = join(", ", map { "?" } $firstColNumber .. $valueCount);
$oSth = $oDbh->prepare("INSERT INTO $table VALUES ( $placeholders )") or die("Could not prepare insert\n");
}
unshift(@aVal, $line) if($c0);
$oSth->execute(@aVal) or die("Insert failed\n");
if($lineMatchCount % $commitEvery == 0) {
$oDbh->commit() or die("Could not commit\n");
}
# print join("|", @aVal) . "\n";
}
$oDbh->commit() or die("Could not commit\n");
print STDERR sprintf("%3.1f%% $lineMatchCount/$lineCount lines\n", ($lineMatchCount / ($lineCount || 1) * 100)) if($rexMatch);
print STDERR "$lineCount lines\n" if($rexSplit);
}
$sqlQuery and runQuery($oDbh, $sqlQuery); #or die
$oDbh->commit() or die("Could not commit\n");
$oDbh->disconnect() or die("Could not disconnect from database\n");
return(1);
}
=head2 createTable($oDbh, $table, $colCount, $firstColNumber)
Set up the basic database contents.
$firstColNumber: 0|1
Return 1 on success, else errors.
=cut
sub createTable {
my ($oDbh, $table, $colCount, $firstColNumber) = @_;
local $oDbh->{RaiseError} = 0;
local $oDbh->{PrintError} = 0;
$oDbh->do(qq{DROP TABLE $table});
my $cols = join(", ", map { "C$_ VARCHAR" } $firstColNumber .. $colCount);
my $sql = qq{CREATE TABLE $table ( $cols ) };
$oDbh->do($sql) or return(0);
return(1);
}
=head2 runQuery($oDbh, $sql)
Run the query $sql and print the result.
Return 1. Die on fatal errors.
=cut
sub runQuery {
my ($oDbh, $sql) = @_;
local $oDbh->{RaiseError} = 1;
local $oDbh->{PrintError} = 0;
eval {
my $oSth = $oDbh->prepare($sql);
$oSth->execute();
my $count = 0;
while(my $raVal = $oSth->fetchrow_arrayref()) {
$count++;
print join("\t", map { defined($_) ? $_ : "" } @$raVal) . "\n";
}
print STDERR "Row count: $count\n";
};
die("$sql\nERROR: " . ($oDbh->errstr || ""). "\n") if($@);
return(1);
}
__END__