Files
webmin/postgresql/postgresql-lib.pl.bak
2007-04-12 20:24:50 +00:00

364 lines
8.7 KiB
Perl

# postgresql-lib.pl
# Common PostgreSQL functions
do '../web-lib.pl';
&init_config();
if ($config{'plib'}) {
$ENV{$gconfig{'ld_env'}} .= ':' if ($ENV{$gconfig{'ld_env'}});
$ENV{$gconfig{'ld_env'}} .= $config{'plib'};
}
if ($config{'psql'} =~ /^(.*)\/bin\/psql$/ && $1 ne '' && $1 ne '/usr') {
$ENV{$gconfig{'ld_env'}} .= ':' if ($ENV{$gconfig{'ld_env'}});
$ENV{$gconfig{'ld_env'}} .= "$1/lib";
}
%access = &get_module_acl();
if (!$config{'nodbi'}) {
# Check if we have DBD::Pg
eval <<EOF;
use DBI;
\$driver_handle = DBI->install_driver("Pg");
EOF
}
# is_postgresql_running()
# Returns 1 if yes, 0 if no, -1 if the login is invalid, -2 if there
# is a library problem
sub is_postgresql_running
{
local $temp = &tempname();
local $host = $config{'host'} ? "-h $config{'host'}" : "";
local $cmd;
if ($config{'login'}) {
open(TEMP, ">$temp");
print TEMP "$config{'login'}\n$config{'pass'}\n";
close(TEMP);
local $out;
$cmd = "$config{'psql'} -u -c '' $host $config{'basedb'} <$temp";
}
else {
$cmd = "$config{'psql'} -c '' $host $config{'basedb'}";
}
if ($config{'unix'} && getpwnam($config{'unix'})) {
$cmd = "su $config{'unix'} -c \"$cmd\"";
}
open(OUT, "$cmd 2>&1 |");
while(<OUT>) { $out .= $_; }
close(OUT);
unlink($temp);
if ($out =~ /setuserid:/i || $out =~ /no\s+password\s+supplied/i ||
$out =~ /no\s+postgres\s+username/i || $out =~ /authentication\s+failed/i ||
$out =~ /password:.*password:/i || $out =~ /database.*does.*not/i) {
return -1;
}
elsif ($out =~ /connect.*failed/i || $out =~ /could not connect to server:/) {
return 0;
}
elsif ($out =~ /lib\S+\.so/i) {
return -2;
}
else {
return 1;
}
}
# get_postgresql_version()
sub get_postgresql_version
{
local $v = &execute_sql($config{'basedb'}, 'select version()');
$v = $v->{'data'}->[0]->[0];
if ($v =~ /postgresql\s+([0-9\.]+)/i) {
return $1;
}
else {
return undef;
}
}
# list_databases()
# Returns a list of all databases
sub list_databases
{
local $t = &execute_sql($config{'basedb'}, 'select * from pg_database order by datname');
return map { $_->[0] } @{$t->{'data'}};
}
# list_tables(database)
# Returns a list of tables in some database
sub list_tables
{
#local $t = &execute_sql($_[0], 'select relname from pg_class where relkind = \'r\' and relname not like \'pg_%\' and relhasrules = \'f\' order by relname');
local $t = &execute_sql($_[0], 'select tablename from pg_tables where tablename not like \'pg_%\' order by tablename');
return map { $_->[0] } @{$t->{'data'}};
}
# list_types()
# Returns a list of all available field types
sub list_types
{
local $t = &execute_sql($config{'basedb'}, 'select typname from pg_type where typrelid = 0 and typname !~ \'^_.*\' order by typname');
return map { $_->[0] } @{$t->{'data'}};
}
# table_structure(database, table)
# Returns a list of hashes detailing the structure of a table
sub table_structure
{
local $t = &execute_sql($_[0], "select a.attnum, a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef FROM pg_class c, pg_attribute a, pg_type t WHERE c.relname = '$_[1]' and a.attnum > 0 and a.attrelid = c.oid and a.atttypid = t.oid order by attnum");
local (@rv, $r);
foreach $r (@{$t->{'data'}}) {
local $arr;
$arr++ if ($r->[2] =~ s/^_//);
local $sz = $r->[4] - 4;
if ($sz >= 65536) {
$sz = int($sz/65536).",".($sz%65536);
}
push(@rv, { 'field' => $r->[1],
'arr' => $arr ? 'YES' : 'NO',
'type' => $r->[4] < 0 ? $r->[2]
: $r->[2]."($sz)",
'null' => $r->[5] =~ /f|0/ ? 'YES' : 'NO' } );
}
return @rv;
}
# execute_sql(database, sql)
sub execute_sql
{
if ($driver_handle && !$config{'unix'} &&
$_[1] !~ /^(create|drop)\s+database/ && $_[1] !~ /^\\/) {
# Use the DBI interface
local $cstr = "dbname=$_[0]";
$cstr .= ";host=$config{'host'}" if ($config{'host'});
local $dbh = $driver_handle->connect($cstr,
$config{'login'}, $config{'pass'});
$dbh || &error("DBI connect failed : ",$DBI::errstr);
$dbh->{'AutoCommit'} = 0;
local $cmd = $dbh->prepare($_[1]);
if (!$cmd->execute()) {
&error(&text('esql', "<tt>".&html_escape($_[1])."</tt>",
"<tt>".&html_escape($dbh->errstr)."</tt>"));
}
local (@data, @row);
local @titles = @{$cmd->{'NAME'}};
while(@row = $cmd->fetchrow()) {
push(@data, [ @row ]);
}
$cmd->finish();
$dbh->commit();
$dbh->disconnect();
return { 'titles' => \@titles,
'data' => \@data };
}
else {
# Call the psql program
local $temp = &tempname();
open(TEMP, ">$temp");
print TEMP "$config{'login'}\n$config{'pass'}\n";
close(TEMP);
local $host = $config{'host'} ? "-h $config{'host'}" : "";
local $cmd = "$config{'psql'} -u -c \"$_[1]\" $host $_[0] <$temp";
if ($config{'unix'}) {
$cmd =~ s/"/\\"/g;
$cmd = "su $config{'unix'} -c \"$cmd\"";
}
open(OUT, "$cmd <$temp 2>&1 |");
local ($line, $rv, @data);
do {
$line = <OUT>;
} while($line =~ /^(username|password|user name):/i ||
$line =~ /(warning|notice):/i || $line !~ /\S/);
if ($line =~ /^ERROR:\s+(.*)/ || $line =~ /FATAL.*:\s+(.*)/) {
&error(&text('esql', "<tt>$_[1]</tt>", "<tt>$1</tt>"));
}
else {
local $dash = <OUT>;
if ($dash =~ /^\s*\+\-/) {
# mysql-style output
$line = <OUT>;
$line =~ s/^[\s\|]+//; $line =~ s/[\s\|]+$//;
local @titles = split(/\|/, $line);
map { s/^\s+//; s/\s+$// } @titles;
$line = <OUT>; # skip useless dashes
while(1) {
$line = <OUT>;
last if (!$line || $line =~ /^\s*\+/);
$line =~ s/^[\s\|]+//; $line =~ s/[\s\|]+$//;
local @row = split(/\|/, $line);
map { s/^\s+//; s/\s+$// } @row;
push(@data, \@row);
}
$rv = { 'titles' => \@titles, 'data' => \@data };
}
elsif ($dash !~ /^-/) {
# no output, such as from an insert
$rv = undef;
}
else {
# psql-style output
local @titles = split(/\|/, $line);
map { s/^\s+//; s/\s+$// } @titles;
while(1) {
$line = <OUT>;
last if (!$line || $line =~ /^\(\d+\s+\S+\)/);
local @row = split(/ \| /, $line);
map { s/^\s+//; s/\s+$// } @row;
push(@data, \@row);
}
$rv = { 'titles' => \@titles, 'data' => \@data };
}
}
close(OUT);
unlink($temp);
return $rv;
}
}
# execute_sql_logged(database, command)
sub execute_sql_logged
{
&additional_log('sql', $_[0], $_[1]);
return &execute_sql(@_);
}
# run_as_postgres(command)
sub run_as_postgres
{
pipe(OUTr, OUTw);
local $pid = fork();
if (!$pid) {
untie(*STDIN);
untie(*STDOUT);
untie(*STDERR);
close(STDIN);
open(STDOUT, ">&OUTw");
open(STDERR, ">&OUTw");
local @u = getpwnam($config{'user'});
$( = $u[3]; $) = "$u[3] $u[3]";
($>, $<) = ($u[2], $u[2]);
exec(@_);
print "Exec failed : $!\n";
exit 1;
}
close(OUTw);
return OUTr;
}
sub can_edit_db
{
local $d;
return 1 if ($access{'dbs'} eq '*');
foreach $d (split(/\s+/, $access{'dbs'})) {
return 1 if ($d eq $_[0]);
}
return 0;
}
# get_hba_config()
# Parses the postgres host access config file
sub get_hba_config
{
local $lnum = 0;
open(HBA, $config{'hba_conf'});
while(<HBA>) {
s/\r|\n//g;
s/^\s*#.*$//g;
if (/^\s*host\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)(\s+(\S+))?/) {
push(@rv, { 'type' => 'host',
'index' => scalar(@rv),
'line' => $lnum,
'db' => $1,
'address' => $2,
'netmask' => $3,
'auth' => $4,
'arg' => $6 } );
}
elsif (/^\s*local\s+(\S+)\s+(\S+)(\s+(\S+))?/) {
push(@rv, { 'type' => 'local',
'index' => scalar(@rv),
'line' => $lnum,
'db' => $1,
'auth' => $2,
'arg' => $4 } );
}
$lnum++;
}
close(HBA);
return @rv;
}
# create_hba(&hba)
sub create_hba
{
local $lref = &read_file_lines($config{'hba_conf'});
push(@$lref, &hba_line($_[0]));
&flush_file_lines();
}
# delete_hba(&hba)
sub delete_hba
{
local $lref = &read_file_lines($config{'hba_conf'});
splice(@$lref, $_[0]->{'line'}, 1);
&flush_file_lines();
}
# modify_hba(&hba)
sub modify_hba
{
local $lref = &read_file_lines($config{'hba_conf'});
splice(@$lref, $_[0]->{'line'}, 1, &hba_line($_[0]));
&flush_file_lines();
}
# swap_hba(&hba1, &hba2)
sub swap_hba
{
local $lref = &read_file_lines($config{'hba_conf'});
local $line0 = $lref->[$_[0]->{'line'}];
local $line1 = $lref->[$_[1]->{'line'}];
$lref->[$_[1]->{'line'}] = $line0;
$lref->[$_[0]->{'line'}] = $line1;
&flush_file_lines();
}
sub hba_line
{
if ($_[0]->{'type'} eq 'host') {
return join(" ", 'host', $_[0]->{'db'}, $_[0]->{'address'},
$_[0]->{'netmask'}, $_[0]->{'auth'},
$_[0]->{'arg'} ? ( $_[0]->{'arg'} ) : () );
}
else {
return join(" ", 'local', $_[0]->{'db'}, $_[0]->{'auth'},
$_[0]->{'arg'} ? ( $_[0]->{'arg'} ) : () );
}
}
# split_array(value)
sub split_array
{
if ($_[0] =~ /^\{(.*)\}$/) {
local @a = split(/,/, $1);
return @a;
}
else {
return ( $_[0] );
}
}
# join_array(values ..)
sub join_array
{
local $alpha;
map { $alpha++ if (!/^-?[0-9\.]+/) } @_;
return $alpha ? '{'.join(',', map { "'$_'" } @_).'}'
: '{'.join(',', @_).'}';
}
1;