Ruby PG.exec_params执行PostgreSQL报参数数据类型无法确定排查
报错核心原因
报错的本质是参数占位符$1被写在了SQL单引号包裹的字符串字面量内部,PostgreSQL的参数绑定机制只会识别未被单引号包裹的$N格式占位符,被单引号包裹的内容会被解析为普通字符串文本,不会触发参数替换逻辑。
你写的'%$1::text%'在SQL解析器看来就是一个固定字符串,内容就是百分号加$1::text加百分号,和你传入的query参数没有任何关联。数据库在整个SQL语句里找不到合法的、需要绑定$1参数的位置,自然无法推断参数类型,直接抛出类型不确定错误。
你之前尝试的所有类型转换写法都存在同样问题:不管是text($1)还是cast($1 as text),全被写在单引号内部,属于字符串内容的一部分,根本不会被SQL解析器当成类型转换语法执行,完全不生效。
常见写法误区说明
- 禁止把占位符、类型转换逻辑写在单引号包裹的字符串常量内,这类写法会让参数绑定完全失效。
- 不要为了加模糊匹配的通配符
%就把占位符包在引号里,通配符是参数值的一部分,不是SQL语法的一部分。
exec_params 传参能力说明 PG::Connection#exec_params支持显式指定参数类型,调用时可在参数数组后传入对应参数的类型OID或类型名数组,但常规场景下不需要手动指定:只要占位符写法正确,pg gem会自动把Ruby的String、Integer等原生类型映射为PostgreSQL对应的text、integer等数据类型。- 所有通过
PG.connect创建的连接实例,安全传参的核心规则只有一条:绝对不要用Ruby字符串插值把用户输入直接拼接到SQL语句中,所有用户可控的值必须通过$1、$2...形式的占位符传入,由数据库驱动完成参数转义,从根源上避免SQL注入风险。
正确实现代码
两种合法的模糊查询写法,都可以正常运行且无注入风险:
- SQL层拼接通配符(推荐,无需Ruby侧额外处理参数)
def search_recipes(query) p "Query parameter is:" p query p query.class sql = <<~SQL SELECT * FROM recipes WHERE labels ILIKE '%' || $1 || '%' SQL results = query(sql, query) # ... 后续业务逻辑 end
如果需要显式加类型转换,把转换逻辑写在字符串字面量外部即可,写法如下:
WHERE labels ILIKE '%' || $1::text || '%'
- Ruby侧拼接通配符后作为参数传入
def search_recipes(query) p "Query parameter is:" p query p query.class search_term = "%#{query}%" sql = <<~SQL SELECT * FROM recipes WHERE labels ILIKE $1 SQL results = query(sql, search_term) # ... 后续业务逻辑 end
注意:这种写法是在参数值层面拼接通配符,不是拼接SQL语句本身,最终还是通过占位符传入参数,不存在SQL注入风险。
内容的提问来源于stack exchange,提问作者Sarah Bunker
相关产品推荐
相关产品推荐

