PostgreSQL模式下CodeIgniter is_unique验证规则失效求助
解决CodeIgniter is_unique规则在PostgreSQL Schema表中的验证问题
我碰到过完全一样的问题!CodeIgniter 3的默认is_unique规则确实没考虑PostgreSQL的schema场景,它会错误地把products.catalog.name解析成表products的列catalog.name,而不是products schema下的catalog表的name列,再加上转义符处理出错,就出现了你看到的relation "products" does not exist错误。
CodeIgniter官方推荐用以下两种方式解决,不需要修改核心文件:
方案1:使用自定义回调函数(简单直接)
这是官方最推荐的快速解决方案,你可以在控制器里写一个回调方法来手动校验唯一性:
// 设置表单验证规则,用回调函数替代is_unique $this->form_validation->set_rules("name", "Name", 'required|callback__check_unique_catalog_name'); // 回调方法(注意方法名前的下划线,避免被直接访问) public function _check_unique_catalog_name($input_name) { // 用Query Builder自动处理schema和表名的转义,避免SQL注入 $this->db->where('name', $input_name); $this->db->from('products.catalog'); $query = $this->db->get(); if ($query->num_rows() > 0) { // 设置错误提示信息 $this->form_validation->set_message('_check_unique_catalog_name', 'The {field} already exists in our catalog.'); return FALSE; } return TRUE; }
Query Builder会自动识别products.catalog是schema+表的组合,生成正确的PostgreSQL语法,不用你手动处理标识符转义。
方案2:扩展Form_validation类(通用解决方案)
如果你需要在多个地方使用带schema的唯一性验证,可以扩展系统的Form_validation类,重写is_unique方法,让它支持schema:
- 在
application/libraries/目录下创建MY_Form_validation.php(文件名前缀要和config/config.php里的$config['subclass_prefix']一致,默认是MY_):
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class MY_Form_validation extends CI_Form_validation { public function is_unique($str, $field) { // 先判断是否带schema(包含两个点:schema.table.column) if (substr_count($field, '.') < 2) { // 不带schema的情况,沿用父类的逻辑 return parent::is_unique($str, $field); } // 拆分schema、表、列 list($schema_table, $column) = explode('.', $field, 2); list($schema, $table) = explode('.', $schema_table, 2); // 用数据库类的方法正确转义标识符 $schema_escaped = $this->CI->db->escape_identifiers($schema); $table_escaped = $this->CI->db->escape_identifiers($table); $column_escaped = $this->CI->db->escape_identifiers($column); // 执行查询 $query = $this->CI->db->query( "SELECT 1 FROM $schema_escaped.$table_escaped WHERE $column_escaped = ? LIMIT 1", [$str] ); if ($query->num_rows() > 0) { $this->set_message('is_unique', $this->CI->lang->line('form_validation_is_unique')); return FALSE; } return TRUE; } }
- 之后你就可以像原来一样使用
is_unique规则了:
$this->form_validation->set_rules("name", "Name", 'required|is_unique[products.catalog.name]');
这个扩展类会自动处理带schema的表名,同时兼容原来的简单表名场景。
内容的提问来源于stack exchange,提问作者Nafiu Lawal
相关产品推荐
相关产品推荐

