PHP调用PostgreSQL时强制表名小写致表不存在问题求助
嘿,这个问题我太熟了!PostgreSQL的标识符大小写规则经常坑到不少人,我来给你拆解一下问题出在哪,以及怎么解决。
问题根源:PostgreSQL的标识符大小写规则
PostgreSQL对表名、列名这类标识符的处理逻辑很特殊:
- 如果创建表的时候没有用双引号包裹表名(比如
CREATE TABLE public.MSysQueries1),PostgreSQL会自动把表名转为全小写,实际存储的表名是msysqueries1。 - 但如果创建表的时候用了双引号(比如
CREATE TABLE public."MSysQueries1"),表名会严格保留大小写,此时查询的时候必须也用双引号包裹表名,否则PostgreSQL会再次把表名转为小写,导致找不到你实际存在的那个带大写的表。
你遇到的报错relation "public.msysqueries1" does not exist,就是因为查询时PostgreSQL把你传入的MSysQueries1自动转成了全小写的msysqueries1,但你的数据库里实际是大小写敏感的MSysQueries1表。
解决方案:正确处理标识符(表名)
你需要做的核心操作是:把表名用双引号包裹起来传给PostgreSQL,同时要确保转义表名里的特殊字符(比如双引号),避免SQL注入或者语法错误。
推荐方案:使用pg_escape_identifier()
PHP从5.4版本开始提供了专门用于转义PostgreSQL标识符的函数pg_escape_identifier(),它会自动帮你完成两件事:给标识符加上双引号,以及转义标识符里的特殊字符(比如双引号会被转成两个双引号)。
修改后的代码如下:
$whatever = $_POST['tableID']; $table2string = (string)$whatever; // 用专门的标识符转义函数处理表名 $escapedTable = pg_escape_identifier($table2string); $db = pg_connect("host=localhost port=5432 dbname=name user=user password=password"); // 直接拼接即可,$escapedTable已经被正确包裹双引号 $query = "SELECT * FROM public.$escapedTable;"; $result = pg_query($db, $query);
兼容旧版本PHP的方案
如果你的PHP版本低于5.4,没有pg_escape_identifier()函数,可以手动处理:
$whatever = $_POST['tableID']; $table2string = (string)$whatever; // 手动转义表名中的双引号(PostgreSQL要求用两个双引号表示一个) $escapedTable = str_replace('"', '""', $table2string); // 给表名加上双引号 $quotedTable = "\"$escapedTable\""; $db = pg_connect("host=localhost port=5432 dbname=name user=user password=password"); $query = "SELECT * FROM public.$quotedTable;"; $result = pg_query($db, $query);
验证一下
你可以先输出最终生成的SQL语句看看,比如加一行echo $query;,正确的SQL应该是SELECT * FROM public."MSysQueries1";,这样PostgreSQL就能准确找到你的表了。
内容的提问来源于stack exchange,提问作者J. Sax




