{"thread":{"id":"12736","subject":"[PATCH] Allow git-cvsserver database table name prefix to be specified.","startedAt":"2008-03-18T01:51:49Z","lastAt":"2008-03-18T08:09:13Z","messageCount":2,"participants":["Josh Elsasser","Frank Lichtenheld"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"72338","messageId":"12058051092735-git-send-email-josh@elsasser.org","threadId":"12736","inReplyTo":null,"subject":"[PATCH] Allow git-cvsserver database table name prefix to be specified.","fromName":"Josh Elsasser","fromEmail":"josh@elsasser.org","sentAt":"2008-03-18T01:51:49Z","receivedAt":"2008-03-18T01:51:49Z","isPatch":true,"sender":{"key":"josh@elsasser.org","avatar":"https://gravatar.com/avatar/59e823292b7a3b7960ac53d992f493f2044a29708ffa430fbea37572bd739951?d=mp&s=160"},"body":"Adds a gitcvs.dbprefix config variable, the contents of which are\nprepended to any database tables used by git-cvsserver. The same\nsubstutions as gitcvs.dbname and gitcvs.dbuser are supported, and any\nnon-alphabetic characters are replaced with underscores.\n---\nThe purpose of this patch is to easily allow a single database (think\nPostgreSQL or MySQL) to be shared by multiple repositories.\n\n Documentation/config.txt               |    7 +++\n Documentation/git-cvsserver.txt        |    5 ++\n contrib/completion/git-completion.bash |    2 +-\n git-cvsserver.perl                     |   77 ++++++++++++++++++-------------\n 4 files changed, 58 insertions(+), 33 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 0865f4e..ca232cf 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -661,6 +661,13 @@ gitcvs.dbuser, gitcvs.dbpass::\n \t'gitcvs.dbuser' supports variable substitution (see\n \tlinkgit:git-cvsserver[1] for details).\n \n+gitcvs.dbprefix::\n+\tDatabase table name prefix. This will be prepended to any\n+\ttables used, allowing a single database to be used for deveral\n+\trepositories. Supports variable substitution (see\n+\tlinkgit:git-cvsserver[1] for details). Any non-alphabetic\n+\tcharacters will be replaces with underscores.\n+\n All gitcvs variables except for 'gitcvs.allbinary' can also be\n specified as 'gitcvs.<access_method>.<varname>' (where 'access_method'\n is one of \"ext\" and \"pserver\") to make them apply only for the given\ndiff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt\nindex d3e9993..abd0ebe 100644\n--- a/Documentation/git-cvsserver.txt\n+++ b/Documentation/git-cvsserver.txt\n@@ -227,6 +227,11 @@ gitcvs.dbpass::\n \tDatabase password.  Only useful if setting `dbdriver`, since\n \tSQLite has no concept of database passwords.\n \n+gitcvs.dbprefix::\n+\tDatabase table name prefix. Supports variable substitution\n+\t(see below). Any non-alphabetic characters will be replaces\n+\twith underscores.\n+\n All variables can also be set per access method, see <<configaccessmethod,above>>.\n \n Variable substitution\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 5046f69..7d77374 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -999,7 +999,7 @@ _git_config ()\n \t\tgitcvs.enabled\n \t\tgitcvs.logfile\n \t\tgitcvs.allbinary\n-\t\tgitcvs.dbname gitcvs.dbdriver gitcvs.dbuser gitcvs.dvpass\n+\t\tgitcvs.dbname gitcvs.dbdriver gitcvs.dbuser gitcvs.dbpass gitcvs.dbprefix\n \t\tgc.packrefs\n \t\tgc.reflogexpire\n \t\tgc.reflogexpireunreachable\ndiff --git a/git-cvsserver.perl b/git-cvsserver.perl\nindex 7f632af..7098b35 100755\n--- a/git-cvsserver.perl\n+++ b/git-cvsserver.perl\n@@ -2326,6 +2326,8 @@ sub new\n         $cfg->{gitcvs}{dbuser} || \"\";\n     $self->{dbpass} = $cfg->{gitcvs}{$state->{method}}{dbpass} ||\n         $cfg->{gitcvs}{dbpass} || \"\";\n+    $self->{dbprefix} = $cfg->{gitcvs}{$state->{method}}{dbprefix} ||\n+        $cfg->{gitcvs}{dbprefix} || \"\";\n     my %mapping = ( m => $module,\n                     a => $state->{method},\n                     u => getlogin || getpwuid($<) || $<,\n@@ -2334,6 +2336,8 @@ sub new\n                     );\n     $self->{dbname} =~ s/%([mauGg])/$mapping{$1}/eg;\n     $self->{dbuser} =~ s/%([mauGg])/$mapping{$1}/eg;\n+    $self->{dbprefix} =~ s/%([mauGg])/$mapping{$1}/eg;\n+    $self->{dbprefix} = mangle_tablename($self->{dbprefix});\n \n     die \"Invalid char ':' in dbdriver\" if $self->{dbdriver} =~ /:/;\n     die \"Invalid char ';' in dbname\" if $self->{dbname} =~ /;/;\n@@ -2349,10 +2353,10 @@ sub new\n     }\n \n     # Construct the revision table if required\n-    unless ( $self->{tables}{revision} )\n+    unless ( $self->{tables}{\"$self->{dbprefix}revision\"} )\n     {\n         $self->{dbh}->do(\"\n-            CREATE TABLE revision (\n+            CREATE TABLE $self->{dbprefix}revision (\n                 name       TEXT NOT NULL,\n                 revision   INTEGER NOT NULL,\n                 filehash   TEXT NOT NULL,\n@@ -2363,20 +2367,20 @@ sub new\n             )\n         \");\n         $self->{dbh}->do(\"\n-            CREATE INDEX revision_ix1\n-            ON revision (name,revision)\n+            CREATE INDEX $self->{dbprefix}revision_ix1\n+            ON $self->{dbprefix}revision (name,revision)\n         \");\n         $self->{dbh}->do(\"\n-            CREATE INDEX revision_ix2\n-            ON revision (name,commithash)\n+            CREATE INDEX $self->{dbprefix}revision_ix2\n+            ON $self->{dbprefix}revision (name,commithash)\n         \");\n     }\n \n     # Construct the head table if required\n-    unless ( $self->{tables}{head} )\n+    unless ( $self->{tables}{\"$self->{dbprefix}head\"} )\n     {\n         $self->{dbh}->do(\"\n-            CREATE TABLE head (\n+            CREATE TABLE $self->{dbprefix}head (\n                 name       TEXT NOT NULL,\n                 revision   INTEGER NOT NULL,\n                 filehash   TEXT NOT NULL,\n@@ -2387,16 +2391,16 @@ sub new\n             )\n         \");\n         $self->{dbh}->do(\"\n-            CREATE INDEX head_ix1\n-            ON head (name)\n+            CREATE INDEX $self->{dbprefix}head_ix1\n+            ON $self->{dbprefix}head (name)\n         \");\n     }\n \n     # Construct the properties table if required\n-    unless ( $self->{tables}{properties} )\n+    unless ( $self->{tables}{\"$self->{dbprefix}properties\"} )\n     {\n         $self->{dbh}->do(\"\n-            CREATE TABLE properties (\n+            CREATE TABLE $self->{dbprefix}properties (\n                 key        TEXT NOT NULL PRIMARY KEY,\n                 value      TEXT\n             )\n@@ -2404,10 +2408,10 @@ sub new\n     }\n \n     # Construct the commitmsgs table if required\n-    unless ( $self->{tables}{commitmsgs} )\n+    unless ( $self->{tables}{\"$self->{dbprefix}commitmsgs\"} )\n     {\n         $self->{dbh}->do(\"\n-            CREATE TABLE commitmsgs (\n+            CREATE TABLE $self->{dbprefix}commitmsgs (\n                 key        TEXT NOT NULL PRIMARY KEY,\n                 value      TEXT\n             )\n@@ -2427,10 +2431,10 @@ sub update\n     # first lets get the commit list\n     $ENV{GIT_DIR} = $self->{git_path};\n \n-    my $commitsha1 = `git rev-parse $self->{module}`;\n+    my $commitsha1 = `git-rev-parse $self->{module}`;\n     chomp $commitsha1;\n \n-    my $commitinfo = `git cat-file commit $self->{module} 2>&1`;\n+    my $commitinfo = `git-cat-file commit $self->{module} 2>&1`;\n     unless ( $commitinfo =~ /tree\\s+[a-zA-Z0-9]{40}/ )\n     {\n         die(\"Invalid module '$self->{module}'\");\n@@ -2783,7 +2787,7 @@ sub insert_rev\n     my $author = shift;\n     my $mode = shift;\n \n-    my $insert_rev = $self->{dbh}->prepare_cached(\"INSERT INTO revision (name, revision, filehash, commithash, modified, author, mode) VALUES (?,?,?,?,?,?,?)\",{},1);\n+    my $insert_rev = $self->{dbh}->prepare_cached(\"INSERT INTO $self->{dbprefix}revision (name, revision, filehash, commithash, modified, author, mode) VALUES (?,?,?,?,?,?,?)\",{},1);\n     $insert_rev->execute($name, $revision, $filehash, $commithash, $modified, $author, $mode);\n }\n \n@@ -2793,7 +2797,7 @@ sub insert_mergelog\n     my $key = shift;\n     my $value = shift;\n \n-    my $insert_mergelog = $self->{dbh}->prepare_cached(\"INSERT INTO commitmsgs (key, value) VALUES (?,?)\",{},1);\n+    my $insert_mergelog = $self->{dbh}->prepare_cached(\"INSERT INTO $self->{dbprefix}commitmsgs (key, value) VALUES (?,?)\",{},1);\n     $insert_mergelog->execute($key, $value);\n }\n \n@@ -2801,7 +2805,7 @@ sub delete_head\n {\n     my $self = shift;\n \n-    my $delete_head = $self->{dbh}->prepare_cached(\"DELETE FROM head\",{},1);\n+    my $delete_head = $self->{dbh}->prepare_cached(\"DELETE FROM $self->{dbprefix}head\",{},1);\n     $delete_head->execute();\n }\n \n@@ -2816,7 +2820,7 @@ sub insert_head\n     my $author = shift;\n     my $mode = shift;\n \n-    my $insert_head = $self->{dbh}->prepare_cached(\"INSERT INTO head (name, revision, filehash, commithash, modified, author, mode) VALUES (?,?,?,?,?,?,?)\",{},1);\n+    my $insert_head = $self->{dbh}->prepare_cached(\"INSERT INTO $self->{dbprefix}head (name, revision, filehash, commithash, modified, author, mode) VALUES (?,?,?,?,?,?,?)\",{},1);\n     $insert_head->execute($name, $revision, $filehash, $commithash, $modified, $author, $mode);\n }\n \n@@ -2825,7 +2829,7 @@ sub _headrev\n     my $self = shift;\n     my $filename = shift;\n \n-    my $db_query = $self->{dbh}->prepare_cached(\"SELECT filehash, revision, mode FROM head WHERE name=?\",{},1);\n+    my $db_query = $self->{dbh}->prepare_cached(\"SELECT filehash, revision, mode FROM $self->{dbprefix}head WHERE name=?\",{},1);\n     $db_query->execute($filename);\n     my ( $hash, $revision, $mode ) = $db_query->fetchrow_array;\n \n@@ -2837,7 +2841,7 @@ sub _get_prop\n     my $self = shift;\n     my $key = shift;\n \n-    my $db_query = $self->{dbh}->prepare_cached(\"SELECT value FROM properties WHERE key=?\",{},1);\n+    my $db_query = $self->{dbh}->prepare_cached(\"SELECT value FROM $self->{dbprefix}properties WHERE key=?\",{},1);\n     $db_query->execute($key);\n     my ( $value ) = $db_query->fetchrow_array;\n \n@@ -2850,12 +2854,12 @@ sub _set_prop\n     my $key = shift;\n     my $value = shift;\n \n-    my $db_query = $self->{dbh}->prepare_cached(\"UPDATE properties SET value=? WHERE key=?\",{},1);\n+    my $db_query = $self->{dbh}->prepare_cached(\"UPDATE $self->{dbprefix}properties SET value=? WHERE key=?\",{},1);\n     $db_query->execute($value, $key);\n \n     unless ( $db_query->rows )\n     {\n-        $db_query = $self->{dbh}->prepare_cached(\"INSERT INTO properties (key, value) VALUES (?,?)\",{},1);\n+        $db_query = $self->{dbh}->prepare_cached(\"INSERT INTO $self->{dbprefix}properties (key, value) VALUES (?,?)\",{},1);\n         $db_query->execute($key, $value);\n     }\n \n@@ -2872,7 +2876,7 @@ sub gethead\n \n     return $self->{gethead_cache} if ( defined ( $self->{gethead_cache} ) );\n \n-    my $db_query = $self->{dbh}->prepare_cached(\"SELECT name, filehash, mode, revision, modified, commithash, author FROM head ORDER BY name ASC\",{},1);\n+    my $db_query = $self->{dbh}->prepare_cached(\"SELECT name, filehash, mode, revision, modified, commithash, author FROM $self->{dbprefix}head ORDER BY name ASC\",{},1);\n     $db_query->execute();\n \n     my $tree = [];\n@@ -2895,7 +2899,7 @@ sub getlog\n     my $self = shift;\n     my $filename = shift;\n \n-    my $db_query = $self->{dbh}->prepare_cached(\"SELECT name, filehash, author, mode, revision, modified, commithash FROM revision WHERE name=? ORDER BY revision DESC\",{},1);\n+    my $db_query = $self->{dbh}->prepare_cached(\"SELECT name, filehash, author, mode, revision, modified, commithash FROM $self->{dbprefix}revision WHERE name=? ORDER BY revision DESC\",{},1);\n     $db_query->execute($filename);\n \n     my $tree = [];\n@@ -2923,15 +2927,15 @@ sub getmeta\n     my $db_query;\n     if ( defined($revision) and $revision =~ /^\\d+$/ )\n     {\n-        $db_query = $self->{dbh}->prepare_cached(\"SELECT * FROM revision WHERE name=? AND revision=?\",{},1);\n+        $db_query = $self->{dbh}->prepare_cached(\"SELECT * FROM $self->{dbprefix}revision WHERE name=? AND revision=?\",{},1);\n         $db_query->execute($filename, $revision);\n     }\n     elsif ( defined($revision) and $revision =~ /^[a-zA-Z0-9]{40}$/ )\n     {\n-        $db_query = $self->{dbh}->prepare_cached(\"SELECT * FROM revision WHERE name=? AND commithash=?\",{},1);\n+        $db_query = $self->{dbh}->prepare_cached(\"SELECT * FROM $self->{dbprefix}revision WHERE name=? AND commithash=?\",{},1);\n         $db_query->execute($filename, $revision);\n     } else {\n-        $db_query = $self->{dbh}->prepare_cached(\"SELECT * FROM head WHERE name=?\",{},1);\n+        $db_query = $self->{dbh}->prepare_cached(\"SELECT * FROM $self->{dbprefix}head WHERE name=?\",{},1);\n         $db_query->execute($filename);\n     }\n \n@@ -2951,7 +2955,7 @@ sub commitmessage\n     die(\"Need commithash\") unless ( defined($commithash) and $commithash =~ /^[a-zA-Z0-9]{40}$/ );\n \n     my $db_query;\n-    $db_query = $self->{dbh}->prepare_cached(\"SELECT value FROM commitmsgs WHERE key=?\",{},1);\n+    $db_query = $self->{dbh}->prepare_cached(\"SELECT value FROM $self->{dbprefix}commitmsgs WHERE key=?\",{},1);\n     $db_query->execute($commithash);\n \n     my ( $message ) = $db_query->fetchrow_array;\n@@ -2981,7 +2985,7 @@ sub gethistory\n     my $filename = shift;\n \n     my $db_query;\n-    $db_query = $self->{dbh}->prepare_cached(\"SELECT revision, filehash, commithash FROM revision WHERE name=? ORDER BY revision DESC\",{},1);\n+    $db_query = $self->{dbh}->prepare_cached(\"SELECT revision, filehash, commithash FROM $self->{dbprefix}revision WHERE name=? ORDER BY revision DESC\",{},1);\n     $db_query->execute($filename);\n \n     return $db_query->fetchall_arrayref;\n@@ -3003,7 +3007,7 @@ sub gethistorydense\n     my $filename = shift;\n \n     my $db_query;\n-    $db_query = $self->{dbh}->prepare_cached(\"SELECT revision, filehash, commithash FROM revision WHERE name=? AND filehash!='deleted' ORDER BY revision DESC\",{},1);\n+    $db_query = $self->{dbh}->prepare_cached(\"SELECT revision, filehash, commithash FROM $self->{dbprefix}revision WHERE name=? AND filehash!='deleted' ORDER BY revision DESC\",{},1);\n     $db_query->execute($filename);\n \n     return $db_query->fetchall_arrayref;\n@@ -3061,4 +3065,13 @@ sub mangle_dirname {\n     return $dirname;\n }\n \n+sub mangle_tablename {\n+    my $tablename = shift;\n+    return unless defined $tablename;\n+\n+    $tablename =~ s/[^\\w_]/_/g;\n+\n+    return $tablename;\n+}\n+\n 1;\n-- \n1.5.4.2\n"},{"id":"72347","messageId":"20080318080913.GF18624@mail-vs.djpig.de","threadId":"12736","inReplyTo":"12058051092735-git-send-email-josh@elsasser.org","subject":"Re: [PATCH] Allow git-cvsserver database table name prefix to be specified.","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2008-03-18T08:09:13Z","receivedAt":"2008-03-18T08:09:13Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"On Mon, Mar 17, 2008 at 06:51:49PM -0700, Josh Elsasser wrote:\n> Adds a gitcvs.dbprefix config variable, the contents of which are\n> prepended to any database tables used by git-cvsserver. The same\n> substutions as gitcvs.dbname and gitcvs.dbuser are supported, and any\n> non-alphabetic characters are replaced with underscores.\n> ---\n> The purpose of this patch is to easily allow a single database (think\n> PostgreSQL or MySQL) to be shared by multiple repositories.\n\nFor the record, I think that this is a good idea, but have no time\nto really test it.\n\n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> index 0865f4e..ca232cf 100644\n> --- a/Documentation/config.txt\n> +++ b/Documentation/config.txt\n> @@ -661,6 +661,13 @@ gitcvs.dbuser, gitcvs.dbpass::\n>  \t'gitcvs.dbuser' supports variable substitution (see\n>  \tlinkgit:git-cvsserver[1] for details).\n>  \n> +gitcvs.dbprefix::\n> +\tDatabase table name prefix. This will be prepended to any\n> +\ttables used, allowing a single database to be used for deveral\n\nTypo s/deveral/several/\n\n> +gitcvs.dbprefix::\n> +\tDatabase table name prefix. Supports variable substitution\n> +\t(see below). Any non-alphabetic characters will be replaces\n\nTypo s/replaces/replaced/\n\n> +\twith underscores.\n> +\n>  All variables can also be set per access method, see <<configaccessmethod,above>>.\n>  \n>  Variable substitution\n[...]\n> @@ -2427,10 +2431,10 @@ sub update\n>      # first lets get the commit list\n>      $ENV{GIT_DIR} = $self->{git_path};\n>  \n> -    my $commitsha1 = `git rev-parse $self->{module}`;\n> +    my $commitsha1 = `git-rev-parse $self->{module}`;\n>      chomp $commitsha1;\n>  \n> -    my $commitinfo = `git cat-file commit $self->{module} 2>&1`;\n> +    my $commitinfo = `git-cat-file commit $self->{module} 2>&1`;\n>      unless ( $commitinfo =~ /tree\\s+[a-zA-Z0-9]{40}/ )\n\nUnrelated whitespace changes?\n\nGruesse,\n-- \nFrank Lichtenheld <frank@lichtenheld.de>\nwww: http://www.djpig.de/\n"}]}