diff -pubr CGI-Wiki-0.50_01/bin/cgi-wiki-setupdb CGI-Wiki-Knew/bin/cgi-wiki-setupdb --- CGI-Wiki-0.50_01/bin/cgi-wiki-setupdb Thu Apr 24 18:09:28 2003 +++ CGI-Wiki-Knew/bin/cgi-wiki-setupdb Thu Dec 4 16:39:31 2003 @@ -2,12 +2,13 @@ use strict; use Getopt::Long; -my ($dbtype, $dbname, $dbuser, $dbpass, $dbhost, $help, $preclear); +my ($dbtype, $dbname, $dbuser, $dbpass, $dbhost, $table_prefix, $help, $preclear); GetOptions( "type=s" => \$dbtype, "name=s" => \$dbname, "user=s" => \$dbuser, "pass=s" => \$dbpass, "host=s" => \$dbhost, + "table-prefix=s" => \$table_prefix, "help" => \$help, "force-preclear" => \$preclear ); @@ -49,12 +50,16 @@ if ( $@ ) { if ($preclear) { no strict 'refs'; - &{$class."::cleardb"}($dbname, $dbuser, $dbpass, $dbhost); + &{$class."::cleardb"}(dbname => $dbname, dbuser => $dbuser, + dbpass => $dbpass, dbhost => $dbhost, + table_prefix => $table_prefix); } { no strict 'refs'; - &{$class."::setup"}($dbname, $dbuser, $dbpass, $dbhost); + &{$class."::setup"}(dbname => $dbname, dbuser => $dbuser, + dbpass => $dbpass, dbhost => $dbhost, + table_prefix => $table_prefix); } =head1 NAME @@ -83,7 +88,7 @@ cgi-wiki-setupdb - Set up a database sto =head1 DESCRIPTION -Takes three mandatory arguments: +Takes two mandatory arguments: =over 4 @@ -95,17 +100,17 @@ The database type. Should be one of 'po The database name. -=item user - -The user that connects to the database. It must have permission -to create and drop tables in the database. - =back -two optional arguments: +four optional arguments: =over 4 +=item user + +The user that connects to the database. It must have permission +to create and drop tables in the database. + =item pass The user's database password. @@ -114,6 +119,11 @@ The user's database password. The hostname of the machine the database server is running on (omit for local databases). + +=item table-prefix + +A prefix to add to all table names, thus allowing the co-existence of +multiple wikis within one database. =back diff -pubr CGI-Wiki-0.50_01/bin/user-setup-mysql-dbixfts.pl CGI-Wiki-Knew/bin/user-setup-mysql-dbixfts.pl --- CGI-Wiki-0.50_01/bin/user-setup-mysql-dbixfts.pl Sat Nov 9 19:13:51 2002 +++ CGI-Wiki-Knew/bin/user-setup-mysql-dbixfts.pl Thu Dec 4 16:39:37 2003 @@ -4,10 +4,12 @@ use strict; use Getopt::Long; use CGI::Wiki::Setup::DBIxFTSMySQL; -my ($dbname, $dbuser, $dbpass, $help); +my ($dbname, $dbuser, $dbpass, $dbhost, $table_prefix, $help); GetOptions("name=s" => \$dbname, "user=s" => \$dbuser, "pass=s" => \$dbpass, + "host=s" => \$dbhost, + "table-prefix=s" => \$table_prefix, "help" => \$help,); unless (defined($dbname)) { @@ -16,12 +18,18 @@ unless (defined($dbname)) { exit 1; } +unless (defined($dbuser)) { + print "You must supply a database user with the --user option\n"; + print "further help can be found by typing 'perldoc $0'\n"; + exit 1; +} + if ($help) { print "Help can be found by typing 'perldoc $0'\n"; exit 0; } -CGI::Wiki::Setup::DBIxFTSMySQL::setup($dbname, $dbuser, $dbpass); +CGI::Wiki::Setup::DBIxFTSMySQL::setup($dbname, $dbuser, $dbpass, $dbhost, $table_prefix); =head1 NAME @@ -32,10 +40,11 @@ user-setup-mysql-dbixfts - set up a DBIx user-setup-mysql-dbixfts --name mywiki \ --user wiki \ --pass wiki \ + --host 'db.example.com' =head1 DESCRIPTION -Takes three arguments: +Takes two mandatory arguments: =over 4 @@ -48,9 +57,25 @@ The database name. The user that connects to the database. It must have permission to create and drop tables in the database. +=back + +and three optional arguments: + +over 4 + =item pass The user's database password. + +=item host + +The hostname of the machine the database server is running on (omit +for local databases). + +=item table-prefix + +A prefix to add to all table names, thus allowing the co-existence of +multiple wikis within one database. =back diff -pubr CGI-Wiki-0.50_01/lib/CGI/Wiki/Setup/DBIxFTSMySQL.pm CGI-Wiki-Knew/lib/CGI/Wiki/Setup/DBIxFTSMySQL.pm --- CGI-Wiki-0.50_01/lib/CGI/Wiki/Setup/DBIxFTSMySQL.pm Thu Nov 20 14:25:57 2003 +++ CGI-Wiki-Knew/lib/CGI/Wiki/Setup/DBIxFTSMySQL.pm Mon Nov 24 20:49:15 2003 @@ -16,7 +16,7 @@ CGI::Wiki::Setup::DBIxFTSMySQL - set up =head1 SYNOPSIS use CGI::Wiki::Setup::DBIxFTSMySQL; - CGI::Wiki::Setup::DBIxFTSMySQL::setup($dbname, $dbuser, $dbpass, $dbhost); + CGI::Wiki::Setup::DBIxFTSMySQL::setup($dbname, $dbuser, $dbpass, $dbhost, $table_prefix); Omit $dbhost if the database is local. @@ -29,6 +29,9 @@ drop tables in the database. The $dbhost argument is optional -- omit it if the database is local. +The $table_prefix argument is optional -- it is only needed if you wish +to share one database between multiple CGI::Wiki systems. + Note that any pre-existing L indexes stored in the database will be I by this function, so if you have existing data you probably want to use the C parameter to get it re-indexed. @@ -37,7 +40,7 @@ probably want to use the C parame sub setup { - my ($dbname, $dbuser, $dbpass, $dbhost) = (@_); + my ($dbname, $dbuser, $dbpass, $dbhost, $table_prefix) = (@_); my $dsn = "dbi:mysql:$dbname"; $dsn .= ";host=$dbhost" if $dbhost; @@ -46,30 +49,34 @@ sub setup AutoCommit => 1 } ) or croak DBI::errstr; + $table_prefix = $table_prefix || ''; + # Drop FTS indexes if they already exist. - my $fts = DBIx::FullTextSearch->open($dbh, "_content_and_title_fts"); + my $fts = DBIx::FullTextSearch->open($dbh, $table_prefix . "_content_and_title_fts"); $fts->drop if $fts; - $fts = DBIx::FullTextSearch->open($dbh, "_title_fts"); + $fts = DBIx::FullTextSearch->open($dbh, $table_prefix . "_title_fts"); $fts->drop if $fts; + my $node_table = $table_prefix . "node"; + # Set up FullText indexes and index anything already extant. - my $fts_all = DBIx::FullTextSearch->create($dbh, "_content_and_title_fts", + my $fts_all = DBIx::FullTextSearch->create($dbh, $table_prefix . "_content_and_title_fts", frontend => "table", backend => "phrase", - table_name => "node", + table_name => $node_table, column_name => ["name","text"], column_id_name => "name", stemmer => "en-uk"); - my $fts_title = DBIx::FullTextSearch->create($dbh, "_title_fts", + my $fts_title = DBIx::FullTextSearch->create($dbh, $table_prefix . "_title_fts", frontend => "table", backend => "phrase", - table_name => "node", + table_name => $node_table, column_name => "name", column_id_name => "name", stemmer => "en-uk"); - my $sql = "SELECT name FROM node"; + my $sql = "SELECT name FROM $node_table"; my $sth = $dbh->prepare($sql); $sth->execute(); while (my ($name, $version) = $sth->fetchrow_array) { diff -pubr CGI-Wiki-0.50_01/lib/CGI/Wiki/Setup/MySQL.pm CGI-Wiki-Knew/lib/CGI/Wiki/Setup/MySQL.pm --- CGI-Wiki-0.50_01/lib/CGI/Wiki/Setup/MySQL.pm Thu Nov 20 14:39:27 2003 +++ CGI-Wiki-Knew/lib/CGI/Wiki/Setup/MySQL.pm Mon Nov 24 20:49:15 2003 @@ -55,7 +55,7 @@ CGI::Wiki::Setup::MySQL - Set up tables =head1 SYNOPSIS use CGI::Wiki::Setup::MySQL; - CGI::Wiki::Setup::MySQL::setup($dbname, $dbuser, $dbpass, $dbhost); + CGI::Wiki::Setup::MySQL::setup($dbname, $dbuser, $dbpass, $dbhost, $table_prefix); Omit $dbhost if the database is local. @@ -70,7 +70,7 @@ Set up a MySQL database for use as a CGI =item B use CGI::Wiki::Setup::MySQL; - CGI::Wiki::Setup::MySQL::setup($dbname, $dbuser, $dbpass, $dbhost); + CGI::Wiki::Setup::MySQL::setup($dbname, $dbuser, $dbpass, $dbhost, $table_prefix); Takes three mandatory arguments -- the database name, the username and the password. The username must be able to create and drop tables in the @@ -87,7 +87,7 @@ again with a fresh database, run C 1 } ) or croak DBI::errstr; + $table_prefix = $table_prefix || ''; + # Check whether tables exist, set them up if not. my $sth = $dbh->prepare("SHOW TABLES") or croak $dbh->errstr; $sth->execute; @@ -105,11 +107,15 @@ sub setup { } foreach my $required ( keys %create_sql ) { - if ( $tables{$required} ) { - print "Table $required already exists... skipping...\n"; + if ( $tables{$table_prefix . $required} ) { + print "Table $table_prefix$required already exists... skipping...\n"; } else { - print "Creating table $required... done\n"; + print "Creating MySQL table $table_prefix$required... done\n"; foreach my $sql ( @{ $create_sql{$required} } ) { + my $_sql = $sql; + $_sql =~ s/TABLE $required/TABLE $table_prefix$required/; + $_sql =~ s/INDEX $required/INDEX $table_prefix$required/; + $_sql =~ s/ON $required/ON $table_prefix$required/; $dbh->do($sql) or croak $dbh->errstr; } } @@ -124,8 +130,8 @@ sub setup { use CGI::Wiki::Setup::MySQL; # Clear out the old database completely, then set up tables afresh. - CGI::Wiki::Setup::MySQL::cleardb($dbname, $dbuser, $dbpass, $dbhost); - CGI::Wiki::Setup::MySQL::setup($dbname, $dbuser, $dbpass, $dbhost); + CGI::Wiki::Setup::MySQL::cleardb($dbname, $dbuser, $dbpass, $dbhost, $table_prefix); + CGI::Wiki::Setup::MySQL::setup($dbname, $dbuser, $dbpass, $dbhost, $table_prefix); Takes three mandatory arguments -- the database name, the username and the password. The username must be able to drop tables in the database. @@ -143,7 +149,7 @@ which search backend you're using. =cut sub cleardb { - my ($dbname, $dbuser, $dbpass, $dbhost) = _get_args(@_); + my ($dbname, $dbuser, $dbpass, $dbhost, $table_prefix) = _get_args(@_); my $dsn = "dbi:mysql:$dbname"; $dsn .= ";host=$dbhost" if $dbhost; @@ -152,8 +158,10 @@ sub cleardb { AutoCommit => 1 } ) or croak DBI::errstr; - print "Dropping tables... "; - $dbh->do("DROP TABLE IF EXISTS " . join( ",", keys %create_sql ) ) + $table_prefix = $table_prefix || ''; + + print "Dropping MySQL tables($table_prefix)... "; + $dbh->do("DROP TABLE IF EXISTS " . $table_prefix . join( ",$table_prefix", keys %create_sql ) ) or croak $dbh->errstr; print "done\n"; @@ -164,7 +172,7 @@ sub cleardb { sub _get_args { if ( ref $_[0] ) { my %hash = %{$_[0]}; - return @hash{ qw( dbname dbuser dbpass dbhost ) }; + return @hash{ qw( dbname dbuser dbpass dbhost table_prefix ) }; } else { return @_; } @@ -176,14 +184,15 @@ sub _get_args { As requested by Podmaster. Instead of passing arguments to the methods as - ($dbname, $dbuser, $dbpass, $dbhost) + ($dbname, $dbuser, $dbpass, $dbhost, $table_prefix) you can pass them as ( { dbname => $dbname, dbuser => $dbuser, dbpass => $dbpass, - dbhost => $dbhost + dbhost => $dbhost, + table_prefix => $table_prefix, } ) diff -pubr CGI-Wiki-0.50_01/lib/CGI/Wiki/Setup/Pg.pm CGI-Wiki-Knew/lib/CGI/Wiki/Setup/Pg.pm --- CGI-Wiki-0.50_01/lib/CGI/Wiki/Setup/Pg.pm Thu Nov 20 12:53:07 2003 +++ CGI-Wiki-Knew/lib/CGI/Wiki/Setup/Pg.pm Mon Nov 24 20:49:15 2003 @@ -61,7 +61,7 @@ CGI::Wiki::Setup::Pg - Set up tables for =head1 SYNOPSIS use CGI::Wiki::Setup::Pg; - CGI::Wiki::Setup::Pg::setup($dbname, $dbuser, $dbpass, $dbhost); + CGI::Wiki::Setup::Pg::setup($dbname, $dbuser, $dbpass, $dbhost, $table_prefix); Omit $dbhost if the database is local. @@ -76,7 +76,7 @@ Set up a Postgres database for use as a =item B use CGI::Wiki::Setup::Pg; - CGI::Wiki::Setup::Pg::setup($dbname, $dbuser, $dbpass, $dbhost); + CGI::Wiki::Setup::Pg::setup($dbname, $dbuser, $dbpass, $dbhost, $table_prefix); Takes three mandatory arguments -- the database name, the username and the password. The username must be able to create and drop tables in the @@ -93,7 +93,7 @@ again with a fresh database, run C 1 } ) or croak DBI::errstr; + $table_prefix = $table_prefix || ''; + # Check whether tables exist, set them up if not. my $sql = "SELECT tablename FROM pg_tables WHERE tablename in (" - . join( ",", map { $dbh->quote($_) } keys %create_sql ) . ")"; + . join( ",", map { $dbh->quote($table_prefix . $_) } keys %create_sql ) . ")"; my $sth = $dbh->prepare($sql) or croak $dbh->errstr; $sth->execute; my %tables; @@ -114,12 +116,16 @@ sub setup { } foreach my $required ( keys %create_sql ) { - if ( $tables{$required} ) { - print "Table $required already exists... skipping...\n"; + if ( $tables{$table_prefix . $required} ) { + print "Table $table_prefix$required already exists... skipping...\n"; } else { - print "Creating table $required... done\n"; + print "Creating Pg table $table_prefix$required... done\n"; foreach my $sql ( @{ $create_sql{$required} } ) { - $dbh->do($sql) or croak $dbh->errstr; + my $_sql = $sql; + $_sql =~ s/TABLE $required/TABLE $table_prefix$required/; + $_sql =~ s/INDEX $required/INDEX $table_prefix$required/; + $_sql =~ s/ON $required/ON $table_prefix$required/; + $dbh->do($_sql) or croak $dbh->errstr; } } } @@ -133,8 +139,8 @@ sub setup { use CGI::Wiki::Setup::Pg; # Clear out the old database completely, then set up tables afresh. - CGI::Wiki::Setup::Pg::cleardb($dbname, $dbuser, $dbpass, $dbhost); - CGI::Wiki::Setup::Pg::setup($dbname, $dbuser, $dbpass, $dbhost); + CGI::Wiki::Setup::Pg::cleardb($dbname, $dbuser, $dbpass, $dbhost, $table_prefix); + CGI::Wiki::Setup::Pg::setup($dbname, $dbuser, $dbpass, $dbhost, $table_prefix); Takes three mandatory arguments -- the database name, the username and the password. The username must be able to drop tables in the database. @@ -152,7 +158,7 @@ which search backend you're using. =cut sub cleardb { - my ($dbname, $dbuser, $dbpass, $dbhost) = _get_args(@_); + my ($dbname, $dbuser, $dbpass, $dbhost, $table_prefix) = _get_args(@_); my $dsn = "dbi:Pg:dbname=$dbname"; $dsn .= ";host=$dbhost" if $dbhost; @@ -161,10 +167,12 @@ sub cleardb { AutoCommit => 1 } ) or croak DBI::errstr; - print "Dropping tables... "; + $table_prefix = $table_prefix || ''; + + print "Dropping Pg tables($table_prefix)... "; my $sql = "SELECT tablename FROM pg_tables WHERE tablename in (" - . join( ",", map { $dbh->quote($_) } keys %create_sql ) . ")"; + . join( ",", map { $dbh->quote($table_prefix . $_) } keys %create_sql ) . ")"; foreach my $tableref (@{$dbh->selectall_arrayref($sql)}) { $dbh->do("DROP TABLE $tableref->[0]") or croak $dbh->errstr; } @@ -177,7 +185,7 @@ sub cleardb { sub _get_args { if ( ref $_[0] ) { my %hash = %{$_[0]}; - return @hash{ qw( dbname dbuser dbpass dbhost ) }; + return @hash{ qw( dbname dbuser dbpass dbhost table_prefix ) }; } else { return @_; } @@ -189,14 +197,15 @@ sub _get_args { As requested by Podmaster. Instead of passing arguments to the methods as - ($dbname, $dbuser, $dbpass, $dbhost) + ($dbname, $dbuser, $dbpass, $dbhost, $table_prefix) you can pass them as ( { dbname => $dbname, dbuser => $dbuser, dbpass => $dbpass, - dbhost => $dbhost + dbhost => $dbhost, + table_prefix => $table_prefix, } ) diff -pubr CGI-Wiki-0.50_01/lib/CGI/Wiki/Setup/SQLite.pm CGI-Wiki-Knew/lib/CGI/Wiki/Setup/SQLite.pm --- CGI-Wiki-0.50_01/lib/CGI/Wiki/Setup/SQLite.pm Thu Nov 20 12:53:15 2003 +++ CGI-Wiki-Knew/lib/CGI/Wiki/Setup/SQLite.pm Mon Nov 24 20:49:15 2003 @@ -52,7 +52,7 @@ CGI::Wiki::Setup::SQLite - Set up tables =head1 SYNOPSIS use CGI::Wiki::Setup::SQLite; - CGI::Wiki::Setup::MySQLite::setup($dbfile); + CGI::Wiki::Setup::MySQLite::setup($dbfile, $table_prefix); =head1 DESCRIPTION @@ -65,10 +65,11 @@ Set up a SQLite database for use as a CG =item B use CGI::Wiki::Setup::SQLite; - CGI::Wiki::Setup::SQLite::setup($dbfile); + CGI::Wiki::Setup::SQLite::setup($dbfile, $table_prefix); + +Takes two arguments - the name of the file that the SQLite database is +stored in (mandatory), and a prefix to add to the table names (optional). -Takes one argument - the name of the file that the SQLite database is -stored in. B If a table that the module wants to create already exists, C will leave it alone. This means that you can safely run this @@ -79,17 +80,19 @@ again with a fresh database, run Cconnect("dbi:SQLite:dbname=$dbfile", "", "", { PrintError => 1, RaiseError => 1, AutoCommit => 1 } ) or croak DBI::errstr; + $table_prefix = $table_prefix || ''; + # Check whether tables exist, set them up if not. my $sql = "SELECT name FROM sqlite_master WHERE type='table' AND name in (" - . join( ",", map { $dbh->quote($_) } keys %create_sql ) . ")"; + . join( ",", map { $dbh->quote($table_prefix . $_) } keys %create_sql ) . ")"; my $sth = $dbh->prepare($sql) or croak $dbh->errstr; $sth->execute; my %tables; @@ -98,11 +101,13 @@ sub setup { } foreach my $required ( keys %create_sql ) { - if ( $tables{$required} ) { - print "Table $required already exists... skipping...\n"; + if ( $tables{$table_prefix . $required} ) { + print "Table $table_prefix$required already exists... skipping...\n"; } else { - print "Creating table $required... done\n"; - $dbh->do($create_sql{$required}) or croak $dbh->errstr; + print "Creating SQLite table $table_prefix$required... done\n"; + my $sql = $create_sql{$required}; + $sql =~ s/TABLE $required/TABLE $table_prefix$required/; + $dbh->do($sql) or croak $dbh->errstr; } } @@ -115,11 +120,11 @@ sub setup { use CGI::Wiki::Setup::SQLite; # Clear out the old database completely, then set up tables afresh. - CGI::Wiki::Setup::SQLite::cleardb($dbfile); - CGI::Wiki::Setup::SQLite::setup($dbfile); + CGI::Wiki::Setup::SQLite::cleardb($dbfile, $table_prefix); + CGI::Wiki::Setup::SQLite::setup($dbfile, $table_prefix); -Takes one argument - the name of the file that the SQLite database is -stored in. +Takes two arguments - the name of the file that the SQLite database is +stored in (mandatory), and a prefix to add to the table names (optional). Clears out all L store tables from the database. B that this will lose all your data; you probably only want to use this @@ -132,17 +137,19 @@ which search backend you're using. =cut sub cleardb { - my $dbfile = _get_args(@_); + my ($dbfile, $table_prefix) = _get_args(@_); my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile", "", "", { PrintError => 1, RaiseError => 1, AutoCommit => 1 } ) or croak DBI::errstr; - print "Dropping tables... "; + $table_prefix = $table_prefix || ''; + + print "Dropping SQLite tables($table_prefix)... "; my $sql = "SELECT name FROM sqlite_master WHERE type='table' AND name in (" - . join( ",", map { $dbh->quote($_) } keys %create_sql ) . ")"; + . join( ",", map { $dbh->quote($table_prefix . $_) } keys %create_sql ) . ")"; foreach my $tableref (@{$dbh->selectall_arrayref($sql)}) { $dbh->do("DROP TABLE $tableref->[0]") or croak $dbh->errstr; } @@ -153,14 +160,12 @@ sub cleardb { } sub _get_args { - my @args; if ( ref $_[0] ) { my %hash = %{$_[0]}; - @args = @hash{ qw( dbname ) }; + return @hash{ qw( dbname table_prefix ) }; } else { - @args = @_; + return @_; } - return $args[0]; } =back @@ -169,11 +174,12 @@ sub _get_args { As requested by Podmaster. Instead of passing arguments to the methods as - ($dbfile) + ($dbfile, $table_prefix) you can pass them as - ( { dbname => $dbfile + ( { dbname => $dbfile, + table_prefix => $table_prefix, } ) diff -pubr CGI-Wiki-0.50_01/lib/CGI/Wiki/Store/Database.pm CGI-Wiki-Knew/lib/CGI/Wiki/Store/Database.pm --- CGI-Wiki-0.50_01/lib/CGI/Wiki/Store/Database.pm Thu Nov 20 11:31:25 2003 +++ CGI-Wiki-Knew/lib/CGI/Wiki/Store/Database.pm Mon Nov 24 20:49:15 2003 @@ -34,11 +34,13 @@ Can't see yet why you'd want to use the my $store = CGI::Wiki::Store::MySQL->new( dbname => "wiki", dbuser => "wiki", dbpass => "wiki", - dbhost => "db.example.com" ); + dbhost => "db.example.com", + table_prefix => "something" ); C is mandatory. C, C and C are optional, but you'll want to supply them unless your database's authentication -method doesn't require it. +method doesn't require it. C is also optional, and is only +needed if you wish to share one database between multiple CGI::Wiki systems. =cut @@ -60,6 +62,7 @@ sub _init { $self->{_dbuser} = $args{dbuser} || ""; $self->{_dbpass} = $args{dbpass} || ""; $self->{_dbhost} = $args{dbhost} || ""; + $self->{_table_prefix} = $args{table_prefix} || ""; # Connect to database and store the database handle. my ($dbname, $dbuser, $dbpass, $dbhost) = @@ -134,11 +137,13 @@ sub _retrieve_node_data { my %data = $self->_retrieve_node_content( %args ); return $data{content} unless wantarray; + my $metadata_table = $self->{_table_prefix} . "metadata"; + # If we want additional data then get it. Note that $data{version} # will already have been set by C<_retrieve_node_content>, if it wasn't # specified in the call. my $dbh = $self->dbh; - my $sql = "SELECT metadata_type, metadata_value FROM metadata WHERE " + my $sql = "SELECT metadata_type, metadata_value FROM $metadata_table WHERE " . "node=" . $dbh->quote($args{name}) . " AND " . "version=" . $dbh->quote($data{version}); my $sth = $dbh->prepare($sql); @@ -163,13 +168,17 @@ sub _retrieve_node_content { my ($self, %args) = @_; croak "No valid node name supplied" unless $args{name}; my $dbh = $self->dbh; + + my $node_table = $self->{_table_prefix} . "node"; + my $content_table = $self->{_table_prefix} . "content"; + my $sql; if ( $args{version} ) { - $sql = "SELECT text, version, modified FROM content" + $sql = "SELECT text, version, modified FROM $content_table" . " WHERE name=" . $dbh->quote($args{name}) . " AND version=" . $dbh->quote($args{version}); } else { - $sql = "SELECT text, version, modified FROM node + $sql = "SELECT text, version, modified FROM $node_table WHERE name=" . $dbh->quote($args{name}); } my @results = $dbh->selectrow_array($sql); @@ -260,7 +269,10 @@ sub list_backlinks { my $node = $args{node}; croak "Must supply a node name" unless $node; my $dbh = $self->dbh; - my $sql = "SELECT link_from FROM internal_links WHERE link_to=" + + my $internal_links_table = $self->{_table_prefix} . "internal_links"; + + my $sql = "SELECT link_from FROM $internal_links_table WHERE link_to=" . $dbh->quote($node); my $sth = $dbh->prepare($sql); $sth->execute or croak $dbh->errstr; @@ -285,10 +297,14 @@ link to it. sub list_dangling_links { my $self = shift; my $dbh = $self->dbh; - my $sql = "SELECT DISTINCT internal_links.link_to - FROM internal_links LEFT JOIN node - ON node.name=internal_links.link_to - WHERE node.version IS NULL"; + + my $node_table = $self->{_table_prefix} . "node"; + my $internal_links_table = $self->{_table_prefix} . "internal_links"; + + my $sql = "SELECT DISTINCT $internal_links_table.link_to + FROM $internal_links_table LEFT JOIN $node_table + ON $node_table.name=$internal_links_table.link_to + WHERE $node_table.version IS NULL"; my $sth = $dbh->prepare($sql); $sth->execute or croak $dbh->errstr; my @links; @@ -353,27 +369,32 @@ sub write_node_post_locking { @args{ qw( node content links_to metadata) }; my $dbh = $self->dbh; + my $metadata_table = $self->{_table_prefix} . "metadata"; + my $node_table = $self->{_table_prefix} . "node"; + my $content_table = $self->{_table_prefix} . "content"; + my $internal_links_table = $self->{_table_prefix} . "internal_links"; + my $timestamp = $self->_get_timestamp(); my @links_to = @{ $links_to_ref || [] }; # default to empty array my $version; # Either inserting a new page or updating an old one. - my $sql = "SELECT count(*) FROM node WHERE name=" . $dbh->quote($node); + my $sql = "SELECT count(*) FROM $node_table WHERE name=" . $dbh->quote($node); my $exists = @{ $dbh->selectcol_arrayref($sql) }[0] || 0; if ($exists) { - $sql = "SELECT max(version) FROM content + $sql = "SELECT max(version) FROM $content_table WHERE name=" . $dbh->quote($node); $version = @{ $dbh->selectcol_arrayref($sql) }[0] || 0; croak "Can't get version number" unless $version; $version++; - $sql = "UPDATE node SET version=" . $dbh->quote($version) + $sql = "UPDATE $node_table SET version=" . $dbh->quote($version) . ", text=" . $dbh->quote($content) . ", modified=" . $dbh->quote($timestamp) . " WHERE name=" . $dbh->quote($node); $dbh->do($sql) or croak "Error updating database: " . DBI->errstr; } else { $version = 1; - $sql = "INSERT INTO node (name, version, text, modified) + $sql = "INSERT INTO $node_table (name, version, text, modified) VALUES (" . join(", ", map { $dbh->quote($_) } ($node, $version, $content, $timestamp) @@ -383,7 +404,7 @@ sub write_node_post_locking { } # In either case we need to add to the history. - $sql = "INSERT INTO content (name, version, text, modified) + $sql = "INSERT INTO $content_table (name, version, text, modified) VALUES (" . join(", ", map { $dbh->quote($_) } ($node, $version, $content, $timestamp) @@ -392,10 +413,10 @@ sub write_node_post_locking { $dbh->do($sql) or croak "Error updating database: " . DBI->errstr; # And to the backlinks. - $dbh->do("DELETE FROM internal_links WHERE link_from=" + $dbh->do("DELETE FROM $internal_links_table WHERE link_from=" . $dbh->quote($node) ) or croak $dbh->errstr; foreach my $links_to ( @links_to ) { - $sql = "INSERT INTO internal_links (link_from, link_to) VALUES (" + $sql = "INSERT INTO $internal_links_table (link_from, link_to) VALUES (" . join(", ", map { $dbh->quote($_) } ( $node, $links_to ) ) . ")"; # Better to drop a backlink or two than to lose the whole update. # Shevek wants a case-sensitive wiki, Jerakeen wants a case-insensitive @@ -427,7 +448,7 @@ sub write_node_post_locking { @values = keys %unique; foreach my $value ( @values ) { - my $sql = "INSERT INTO metadata " + my $sql = "INSERT INTO $metadata_table " . "(node, version, metadata_type, metadata_value) VALUES (" . join(", ", map { $dbh->quote($_) } ( $node, $version, $type, $value ) @@ -439,7 +460,7 @@ sub write_node_post_locking { # Otherwise grab a checksum and store that. my $type_to_store = "__" . $type . "__checksum"; my $value_to_store = $self->_checksum_hashes( @values ); - my $sql = "INSERT INTO metadata " + my $sql = "INSERT INTO $metadata_table " . "(node, version, metadata_type, metadata_value) VALUES (" . join(", ", map { $dbh->quote($_) } ( $node, $version, $type_to_store, $value_to_store ) @@ -488,14 +509,20 @@ sub delete_node { my ($self, $node) = @_; my $dbh = $self->dbh; my $name = $dbh->quote($node); + + my $metadata_table = $self->{_table_prefix} . "metadata"; + my $node_table = $self->{_table_prefix} . "node"; + my $content_table = $self->{_table_prefix} . "content"; + my $internal_links_table = $self->{_table_prefix} . "internal_links"; + # Should start a transaction here. FIXME. - my $sql = "DELETE FROM node WHERE name=$name"; + my $sql = "DELETE FROM $node_table WHERE name=$name"; $dbh->do($sql) or croak "Deletion failed: " . DBI->errstr; - $sql = "DELETE FROM content WHERE name=$name"; + $sql = "DELETE FROM $content_table WHERE name=$name"; $dbh->do($sql) or croak "Deletion failed: " . DBI->errstr; - $sql = "DELETE FROM internal_links WHERE link_from=$name"; + $sql = "DELETE FROM $internal_links_table WHERE link_from=$name"; $dbh->do($sql) or croak $dbh->errstr; - $sql = "DELETE FROM metadata WHERE node=$name"; + $sql = "DELETE FROM $metadata_table WHERE node=$name"; $dbh->do($sql) or croak $dbh->errstr; # And finish it here. return 1; @@ -617,8 +644,13 @@ sub _find_recent_changes_by_criteria { metadata_was metadata_wasnt) }; my $dbh = $self->dbh; + my $metadata_table = $self->{_table_prefix} . "metadata"; + my $node_table = $self->{_table_prefix} . "node"; + my $content_table = $self->{_table_prefix} . "content"; + my $internal_links_table = $self->{_table_prefix} . "internal_links"; + my @where; - my $main_table = "node"; + my $main_table = $node_table; if ( $metadata_is ) { if ( scalar keys %$metadata_is > 1 ) { croak "metadata_is must have one key and one value only"; @@ -627,8 +659,8 @@ sub _find_recent_changes_by_criteria { my $value = $metadata_is->{$type}; croak "metadata_is must have one key and one value only" if ref $value; - push @where, "metadata.metadata_type=" . $dbh->quote($type); - push @where, "metadata.metadata_value=" . $dbh->quote($value); + push @where, "$metadata_table.metadata_type=" . $dbh->quote($type); + push @where, "$metadata_table.metadata_value=" . $dbh->quote($value); } elsif ( $metadata_isnt ) { if ( scalar keys %$metadata_isnt > 1 ) { croak "metadata_isnt must have one key and one value only"; @@ -640,11 +672,11 @@ sub _find_recent_changes_by_criteria { my @omit = $self->list_nodes_by_metadata( metadata_type => $type, metadata_value => $value ); - push @where, "node.name NOT IN (" + push @where, "$node_table.name NOT IN (" . join(",", map { $dbh->quote($_) } @omit ) . ")" if scalar @omit; } elsif ( $metadata_was ) { - $main_table = "content"; + $main_table = $content_table; if ( scalar keys %$metadata_was > 1 ) { croak "metadata_was must have one key and one value only"; } @@ -652,10 +684,10 @@ sub _find_recent_changes_by_criteria { my $value = $metadata_was->{$type}; croak "metadata_was must have one key and one value only" if ref $value; - push @where, "metadata.metadata_type=" . $dbh->quote($type); - push @where, "metadata.metadata_value=" . $dbh->quote($value); + push @where, "$metadata_table.metadata_type=" . $dbh->quote($type); + push @where, "$metadata_table.metadata_value=" . $dbh->quote($value); } elsif ( $metadata_wasnt ) { - $main_table = "content"; + $main_table = $content_table; if ( scalar keys %$metadata_wasnt > 1 ) { croak "metadata_wasnt must have one key and one value only"; } @@ -668,8 +700,8 @@ sub _find_recent_changes_by_criteria { metadata_was => $metadata_wasnt, ); foreach my $omit ( @omits ) { - push @where, "( content.name != " . $dbh->quote($omit->{name}) - . " OR content.version != " . $dbh->quote($omit->{version}) + push @where, "( $content_table.name != " . $dbh->quote($omit->{name}) + . " OR $content_table.version != " . $dbh->quote($omit->{version}) . ")"; } } @@ -684,9 +716,9 @@ sub _find_recent_changes_by_criteria { $main_table.version, $main_table.modified FROM $main_table - LEFT JOIN metadata - ON $main_table.name=metadata.node - AND $main_table.version=metadata.version + LEFT JOIN $metadata_table + ON $main_table.name=$metadata_table.node + AND $main_table.version=$metadata_table.version " . ( scalar @where ? " WHERE " . join(" AND ",@where) : "" ) @@ -704,7 +736,7 @@ sub _find_recent_changes_by_criteria { foreach my $find ( @finds ) { my %metadata; my $sth = $dbh->prepare( "SELECT metadata_type, metadata_value - FROM metadata WHERE node=? AND version=?" ); + FROM $metadata_table WHERE node=? AND version=?" ); $sth->execute( $find->{name}, $find->{version} ); while ( my ($type, $value) = $sth->fetchrow_array ) { if ( defined $metadata{$type} ) { @@ -730,7 +762,10 @@ won't be in any kind of order; do any so sub list_all_nodes { my $self = shift; my $dbh = $self->dbh; - my $sql = "SELECT name FROM node;"; + + my $node_table = $self->{_table_prefix} . "node"; + + my $sql = "SELECT name FROM $node_table;"; my $nodes = $dbh->selectall_arrayref($sql); return ( map { $_->[0] } (@$nodes) ); } @@ -794,12 +829,17 @@ sub list_nodes_by_metadata { } sub _get_list_by_metadata_sql { + my $self = shift; + + my $metadata_table = $self->{_table_prefix} . "metadata"; + my $node_table = $self->{_table_prefix} . "node"; + # can be over-ridden by database-specific subclasses - return "SELECT node.name FROM node, metadata" - . " WHERE node.name=metadata.node" - . " AND node.version=metadata.version" - . " AND metadata.metadata_type = ? " - . " AND metadata.metadata_value = ? "; + return "SELECT $node_table.name FROM $node_table, $metadata_table" + . " WHERE $node_table.name=$metadata_table.node" + . " AND $node_table.version=$metadata_table.version" + . " AND $metadata_table.metadata_type = ? " + . " AND $metadata_table.metadata_value = ? "; } =item B @@ -866,6 +906,19 @@ backend storage. sub dbhost { my $self = shift; return $self->{_dbhost}; +} + +=item B + + my $table_prefix = $store->table_prefix; + +Returns the optional prefix for tables in the database backend. + +=cut + +sub table_prefix { + my $self = shift; + return $self->{_table_prefix}; } # Cleanup. diff -pubr CGI-Wiki-0.50_01/lib/CGI/Wiki/Store/Pg.pm CGI-Wiki-Knew/lib/CGI/Wiki/Store/Pg.pm --- CGI-Wiki-0.50_01/lib/CGI/Wiki/Store/Pg.pm Thu Nov 20 11:31:25 2003 +++ CGI-Wiki-Knew/lib/CGI/Wiki/Store/Pg.pm Mon Nov 24 20:49:15 2003 @@ -79,18 +79,22 @@ sub check_and_write_node { sub _get_list_by_metadata_sql { my ($self, %args) = @_; + + my $metadata_table = $self->{_table_prefix} . "metadata"; + my $node_table = $self->{_table_prefix} . "node"; + if ( $args{ignore_case} ) { - return "SELECT node.name FROM node, metadata" - . " WHERE node.name=metadata.node" - . " AND node.version=metadata.version" - . " AND lower(metadata.metadata_type) = ? " - . " AND lower(metadata.metadata_value) = ? "; + return "SELECT $node_table.name FROM $node_table, $metadata_table" + . " WHERE $node_table.name=$metadata_table.node" + . " AND $node_table.version=$metadata_table.version" + . " AND lower($metadata_table.metadata_type) = ? " + . " AND lower($metadata_table.metadata_value) = ? "; } else { - return "SELECT node.name FROM node, metadata" - . " WHERE node.name=metadata.node" - . " AND node.version=metadata.version" - . " AND metadata.metadata_type = ? " - . " AND metadata.metadata_value = ? "; + return "SELECT $node_table.name FROM $node_table, $metadata_table" + . " WHERE $node_table.name=$metadata_table.node" + . " AND $node_table.version=$metadata_table.version" + . " AND $metadata_table.metadata_type = ? " + . " AND $metadata_table.metadata_value = ? "; } } diff -pubr CGI-Wiki-0.50_01/lib/CGI/Wiki/Store/SQLite.pm CGI-Wiki-Knew/lib/CGI/Wiki/Store/SQLite.pm --- CGI-Wiki-0.50_01/lib/CGI/Wiki/Store/SQLite.pm Thu Nov 20 11:31:25 2003 +++ CGI-Wiki-Knew/lib/CGI/Wiki/Store/SQLite.pm Mon Nov 24 20:49:15 2003 @@ -93,18 +93,22 @@ sub check_and_write_node { sub _get_list_by_metadata_sql { my ($self, %args) = @_; + + my $metadata_table = $self->{_table_prefix} . "metadata"; + my $node_table = $self->{_table_prefix} . "node"; + if ( $args{ignore_case} ) { - return "SELECT node.name FROM node, metadata" - . " WHERE node.name=metadata.node" - . " AND node.version=metadata.version" - . " AND metadata.metadata_type LIKE ? " - . " AND metadata.metadata_value LIKE ? "; + return "SELECT $node_table.name FROM $node_table, $metadata_table" + . " WHERE $node_table.name=$metadata_table.node" + . " AND $node_table.version=$metadata_table.version" + . " AND $metadata_table.metadata_type LIKE ? " + . " AND $metadata_table.metadata_value LIKE ? "; } else { - return "SELECT node.name FROM node, metadata" - . " WHERE node.name=metadata.node" - . " AND node.version=metadata.version" - . " AND metadata.metadata_type = ? " - . " AND metadata.metadata_value = ? "; + return "SELECT $node_table.name FROM $node_table, $metadata_table" + . " WHERE $node_table.name=$metadata_table.node" + . " AND $node_table.version=$metadata_table.version" + . " AND $metadata_table.metadata_type = ? " + . " AND $metadata_table.metadata_value = ? "; } } diff -pubr CGI-Wiki-0.50_01/lib/CGI/Wiki/TestLib.pm CGI-Wiki-Knew/lib/CGI/Wiki/TestLib.pm --- CGI-Wiki-0.50_01/lib/CGI/Wiki/TestLib.pm Thu Nov 20 12:14:05 2003 +++ CGI-Wiki-Knew/lib/CGI/Wiki/TestLib.pm Mon Nov 24 20:49:15 2003 @@ -41,13 +41,16 @@ search and storage backends. my %configured = %CGI::Wiki::TestConfig::config; +my @prefixes = ( undef, '', 'one_' ); + my %datastore_info; foreach my $dbtype (qw( MySQL Pg SQLite )) { + foreach my $tblprefix (0..$#prefixes) { if ( $configured{$dbtype}{dbname} ) { my %config = %{ $configured{$dbtype} }; my $store_class = "CGI::Wiki::Store::$dbtype"; my $setup_class = "CGI::Wiki::Setup::$dbtype"; - $datastore_info{$dbtype} = { + $datastore_info{$dbtype . $tblprefix} = { class => $store_class, setup_class => $setup_class, params => { @@ -55,23 +58,28 @@ foreach my $dbtype (qw( MySQL Pg SQLite dbuser => $config{dbuser}, dbpass => $config{dbpass}, dbhost => $config{dbhost}, + table_prefix => $prefixes[$tblprefix], }, }; } + } } my %dbixfts_info; # DBIxFTS only works with MySQL. if ( $configured{dbixfts} && $configured{MySQL}{dbname} ) { + foreach my $tblprefix (0..$#prefixes) { my %config = %{ $configured{MySQL} }; - $dbixfts_info{MySQL} = { + $dbixfts_info{'MySQL' . $tblprefix} = { db_params => { dbname => $config{dbname}, dbuser => $config{dbuser}, dbpass => $config{dbpass}, dbhost => $config{dbhost}, + table_prefix => $prefixes[$tblprefix], }, }; + } } my %sii_info; @@ -126,23 +134,27 @@ if ( $configured{search_invertedindex} ) # @wiki_info describes which searches work with which stores. # Database-specific searchers. -push @wiki_info, { datastore_info => $datastore_info{MySQL}, - dbixfts_info => $dbixfts_info{MySQL} } - if ( $datastore_info{MySQL} and $dbixfts_info{MySQL} ); -push @wiki_info, { datastore_info => $datastore_info{MySQL}, +foreach my $tblprefix (0..$#prefixes) { + push @wiki_info, { datastore_info => $datastore_info{'MySQL' . $tblprefix}, + dbixfts_info => $dbixfts_info{'MySQL' . $tblprefix} } + if ( $datastore_info{'MySQL' . $tblprefix} and $dbixfts_info{'MySQL'} . $tblprefix ); + push @wiki_info, { datastore_info => $datastore_info{'MySQL' . $tblprefix}, sii_info => $sii_info{MySQL} } - if ( $datastore_info{MySQL} and $sii_info{MySQL} ); -push @wiki_info, { datastore_info => $datastore_info{Pg}, + if ( $datastore_info{'MySQL' . $tblprefix} and $sii_info{MySQL} ); + push @wiki_info, { datastore_info => $datastore_info{'Pg' . $tblprefix}, sii_info => $sii_info{Pg} } - if ( $datastore_info{Pg} and $sii_info{Pg} ); + if ( $datastore_info{'Pg' . $tblprefix} and $sii_info{Pg} ); +} # All stores are compatible with the default S::II search, and with no search. foreach my $dbtype ( qw( MySQL Pg SQLite ) ) { - push @wiki_info, { datastore_info => $datastore_info{$dbtype}, + foreach my $tblprefix (0..$#prefixes) { + push @wiki_info, { datastore_info => $datastore_info{$dbtype . $tblprefix}, sii_info => $sii_info{DB_File} } - if ( $datastore_info{$dbtype} and $sii_info{DB_File} ); - push @wiki_info, { datastore_info => $datastore_info{$dbtype} } - if $datastore_info{$dbtype}; + if ( $datastore_info{$dbtype . $tblprefix} and $sii_info{DB_File} ); + push @wiki_info, { datastore_info => $datastore_info{$dbtype . $tblprefix} } + if $datastore_info{$dbtype . $tblprefix}; + } } =head1 METHODS @@ -170,7 +182,7 @@ sub new_wiki_maker { bless $iterator, $class; return $iterator; } - +use Data::Dumper; sub new_wiki { my $self = shift; return undef if $$self > $#wiki_info; @@ -183,7 +195,13 @@ sub new_wiki { eval "require $setup_class"; { no strict "refs"; - &{"$setup_class\:\:cleardb"}( $datastore_info{params} ); + + my $_params = { %{$datastore_info{params}} }; + foreach my $tblprefix (@prefixes) { + $_params->{table_prefix} = $tblprefix; + &{"$setup_class\:\:cleardb"}( $_params ); + } + #&{"$setup_class\:\:cleardb"}( $datastore_info{params} ); &{"$setup_class\:\:setup"}( $datastore_info{params} ); } my $class = $datastore_info{class}; @@ -202,7 +220,7 @@ sub new_wiki { or croak "Can't connect to $dbconfig{dbname} using $dsn: " . DBI->errstr; require CGI::Wiki::Setup::DBIxFTSMySQL; CGI::Wiki::Setup::DBIxFTSMySQL::setup( - @dbconfig{ qw( dbuser dbname dbpass ) } + @dbconfig{ qw( dbuser dbname dbpass dbhost table_prefix ) } ); require CGI::Wiki::Search::DBIxFTS; $wiki_config{search} = CGI::Wiki::Search::DBIxFTS->new( dbh => $dbh ); diff -pubr CGI-Wiki-0.50_01/t/010_metadata.t CGI-Wiki-Knew/t/010_metadata.t --- CGI-Wiki-0.50_01/t/010_metadata.t Thu Nov 20 13:53:59 2003 +++ CGI-Wiki-Knew/t/010_metadata.t Mon Nov 24 20:49:15 2003 @@ -69,7 +69,8 @@ while ( my $wiki = $iterator->new_wiki ) SKIP: { skip "Test only works on database backends", 1 unless $dbh; # White box testing. - my $sql = "SELECT metadata_type, metadata_value FROM metadata + my $metadata_table = $wiki->store->table_prefix . "metadata"; + my $sql = "SELECT metadata_type, metadata_value FROM $metadata_table WHERE node='Reun Thai'"; my $sth = $dbh->prepare($sql); $sth->execute;