在PostgreSQL中使用模式作为前缀

本页讨论了使用PostgreSQL的模式(Schema)作为前缀的用法。“普通”前缀可以和MySQL一样的用法,所以这里不再讨论。

PostgreSQL有种叫“模式”的机制(http://www.postgresql.org/docs/current/static/ddl-schemas.html)。有时非常方便,但如果你不知道那是什么,你可能实际上不需要它们并可以不用读下去了。

模式在Drupal中可以被用作前缀,也就是说,在多站点安装中,每个站点可以存在于自己的模式中,并且共享的表可以存在于一个“共享”模式中(或者甚至可以是公共模式)。

这儿有个问题:Drupal的升级会失败。很不幸,但是没办法,因为“普通”前缀和模式前缀是不兼容的。如果你对详细情况感兴趣,请访问http://drupal.org/node/40034。

不过也不用担心,可以通过小小的修改更新脚本(update.php和updates.inc)来简单的修正这个问题。问题来自CREATE [UNIQUE] INDEXALTER TABLE .... DROP/ADD CONSTRAINT语句,当使用模式作前缀时,会执行下面的查询:

CREATE INDEX prefix.search_total_word_idx ON prefix.search_total(word)
ALTER TABLE prefix.boxes DROP CONSTRAINT prefix.boxes_title_key
ALTER TABLE test.contact ADD CONSTRAINT test.contact_category_key UNIQUE (category)

必须从索引名和约束名前面移除前缀,也就是它们必须改为:

CREATE INDEX search_total_word_idx ON prefix.search_total(word)
ALTER TABLE prefix.boxes DROP CONSTRAINT boxes_title_key
ALTER TABLE test.contact ADD CONSTRAINT contact_category_key UNIQUE (category)

你只需要搜索CREATE  INDEX,CREATE UNIQUE  INDEXADD/DROP CONSTRAINT语句并移除索引/约束名外面的{}就可以了。

最好的方式是运行升级测试,你可以看到错误查询的列表,然后你就可以很简单的修改它们了。

其它注释:你不能使用prefix.sh来为表加上前缀,这会产生错误的CREATE [UNIQUE] INDEX 查询。这点同样可以简单的被修正,只需要修改:

s/^CREATE INDEX \(.*\) ON /CREATE INDEX $PREFIX\\1 ON $PREFIX/;
s/^CREATE UNIQUE INDEX \(.*\) ON /CREATE UNIQUE INDEX $PREFIX\\1 ON
$PREFIX/;

为:
s/^CREATE INDEX \(.*\) ON /CREATE INDEX \\1 ON $PREFIX/;
s/^CREATE UNIQUE INDEX \(.*\) ON /CREATE UNIQUE INDEX \\1 ON $PREFIX/;

一种可选方法
如果你打算用这种方法来解决,下面是你需要做的:

1.添加下面的语句到database.pgsql文件的顶部:

CREATE SCHEMA schemaname;
SET search_path TO schemaname;

2.编辑drupal/includes/database.pgsql.inc,替换函数db_connect()为:
<?php
function db_connect($url) {
 
$url = parse_url($url);
 
$db_and_schema = explode(".",substr($url['path'], 1));
 
$conn_string = ' user='. $url['user'] .' dbname='.
$db_and_schema['0']  .'  password='$url['pass']  .  '  host='  .
strtr($url['host'],'+','/');
 
$conn_string .= isset($url['port']) ? ' port=' . $url['port'] : '';
 
$connection = pg_connect($conn_string) or die(pg_last_error());
  if(!empty(
$db_and_schema['1'])) pg_query('SET search_path TO
'
.$db_and_schema['1']);
  return
$connection;
}
?>

3.最后,在你的seeting.php文件里使用类似的db_url:
$db_url = 'pgsql://user:password@+tmp/dbname.schemaname';

  • 没有进行彻底的测试,但是我的可以工作(在4.6.3上)。
  • 这也解决了无法指定一个Unix socket作为主机的问题——在pg_connect()里/tmp被替换成了+tmp

。[=red]
[/]