Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql 禁用将带引号的值隐式转换为整数_Postgresql - Fatal编程技术网

Postgresql 禁用将带引号的值隐式转换为整数

Postgresql 禁用将带引号的值隐式转换为整数,postgresql,Postgresql,在这里,插入时和选择时postgres都会隐式地将带引号的字符串转换为整数类型,而不是引发类型错误,除非带引号的值被非常明确地类型化为varchar: # CREATE TABLE foo ( id serial, val integer ); CREATE TABLE # INSERT INTO foo (val) VALUES ('1'), (2); INSERT 0 2 # SELECT * FROM foo WHERE id='1'; id | val ----+----- 1

在这里,插入时和选择时postgres都会隐式地将带引号的字符串转换为整数类型,而不是引发类型错误,除非带引号的值被非常明确地类型化为varchar:

# CREATE TABLE foo ( id serial, val integer );
CREATE TABLE
# INSERT INTO foo (val) VALUES ('1'), (2);
INSERT 0 2
# SELECT * FROM foo WHERE id='1';
 id | val 
----+-----
  1 |   1
(1 row)
这里的问题是没有隐式转换的动态类型语言(例如Ruby或Python)

  • 带引号的值映射到字符串
  • 整数映射为整数
  • 这些不兼容,因此根据连接应用程序的体系结构,此行为可能导致不一致的缓存等
有没有办法禁用它并强制引用值始终为varchars(除非显式转换)

编辑:因为人们显然关注不相关的内容,这些查询来自参数化语句,psycopg2将字符串转换为带引号的值,并将带引号的值转换回字符串,因此,无论访问方法如何,都会存在不匹配,这是一种误导。以下是参数化语句的完全相同的情况:

# INSERT INTO foo (val) VALUES (varchar '1');
ERROR:  column "val" is of type integer 
        but expression is of type character varying
LINE 1: INSERT INTO foo (val) VALUES (varchar '1');
                                              ^
HINT:  You will need to rewrite or cast the expression.
哪些产出:

import psycopg2.extensions

with psycopg2.connect(dbname='postgres') as cn:
    cn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
    with cn.cursor() as cx:
        cx.execute("DROP DATABASE IF EXISTS test")
        cx.execute("CREATE DATABASE test")

with psycopg2.connect(dbname='test') as cn:
    with cn.cursor() as cx:
        cx.execute("CREATE TABLE foo ( id serial, val integer )")
        cx.execute("INSERT INTO foo (val) VALUES (%s), (%s)",
                   (1, '2'))
        cx.execute("SELECT * FROM foo WHERE id=%s",
                   ('1',))
        print cx.fetchall()

否,不能禁用将带引号的文字隐式转换为任何目标类型。PostgreSQL将此类文本视为
unknown
类型,除非由强制转换或文本类型说明符重写,并将从
unknown
转换为任何类型。没有从
unknown
转换到
pg_cast
中的类型的转换;这是含蓄的。所以你不能放弃它

据我所知,PostgreSQL遵循SQL规范,接受带引号的文本作为整数

对于PostgreSQL的类型引擎,
1
是一个
整数
'1'
是一个
未知
,如果传递给
整数
函数、运算符或字段,则该类型将被推断为
整数
。您不能禁用来自
unknown
的类型推断,或强制
unknown
被视为
text
,而不直接对解析器/查询计划器进行黑客攻击

您应该做的是使用参数化语句,而不是将文本替换为SQL。如果这样做,则不会出现此问题,因为客户端类型已知或可以指定。这当然适用于Python(psycopg2),而Ruby(Pg gem)不适用于我对psycopg2的想法,见下文


澄清问题后更新:在这里描述的狭义案例中,psycopg2的客户端参数化声明虽然正确,但不会产生原始海报所期望的结果。在更新中运行演示表明,psycopg2没有使用PostgreSQL的v3绑定/执行协议,而是使用简单查询协议并在本地进行参数替换。因此,虽然在Python中使用参数化语句,但在PostgreSQL中没有使用参数化语句。我在上面错误地说psycopg2中的参数化状态可以解决这个问题

演示程序从PostgreSQL日志中运行以下SQL:

[(1, 1)]
因此,您需要绕过类型适配器注册来调用
str
的原始底层适配器。这将,尽管它很丑陋:

def adapt_str_strict(thestr):
    return psycopg2.extensions.AsIs('TEXT ' + psycopg2.extensions.adapt(thestr))

psycopg2.extensions.register_adapter(str, adapt_str_strict)
用它运行您的演示,您将获得:

def adapt_str_strict(thestr):
    return psycopg2.extensions.AsIs('TEXT ' + str(psycopg2.extensions.QuotedString(thestr)))

psycopg2.extensions.register_adapter(str, adapt_str_strict)


(顺便说一句,使用服务器端的
PREPARE
EXECUTE
是行不通的,因为当通过
psycopg2
将值传递给
EXECUTE
时,您只会遇到同样的键入问题。)

否,您不能禁用引用的文本到任何目标类型的隐式转换。PostgreSQL将此类文本视为
unknown
类型,除非由强制转换或文本类型说明符重写,并将从
unknown
转换为任何类型。没有从
unknown
转换到
pg_cast
中的类型的转换;这是含蓄的。所以你不能放弃它

据我所知,PostgreSQL遵循SQL规范,接受带引号的文本作为整数

对于PostgreSQL的类型引擎,
1
是一个
整数
'1'
是一个
未知
,如果传递给
整数
函数、运算符或字段,则该类型将被推断为
整数
。您不能禁用来自
unknown
的类型推断,或强制
unknown
被视为
text
,而不直接对解析器/查询计划器进行黑客攻击

您应该做的是使用参数化语句,而不是将文本替换为SQL。如果这样做,则不会出现此问题,因为客户端类型已知或可以指定。这当然适用于Python(psycopg2),而Ruby(Pg gem)不适用于我对psycopg2的想法,见下文


澄清问题后更新:在这里描述的狭义案例中,psycopg2的客户端参数化声明虽然正确,但不会产生原始海报所期望的结果。在更新中运行演示表明,psycopg2没有使用PostgreSQL的v3绑定/执行协议,而是使用简单查询协议并在本地进行参数替换。因此,虽然在Python中使用参数化语句,但在PostgreSQL中没有使用参数化语句。我在上面错误地说psycopg2中的参数化状态可以解决这个问题

演示程序从PostgreSQL日志中运行以下SQL:

[(1, 1)]
因此,您需要绕过类型适配器注册来调用
str
的原始底层适配器。这将,尽管它很丑陋:

def adapt_str_strict(thestr):
    return psycopg2.extensions.AsIs('TEXT ' + psycopg2.extensions.adapt(thestr))

psycopg2.extensions.register_adapter(str, adapt_str_strict)
用它运行您的演示,您将获得:

def adapt_str_strict(thestr):
    return psycopg2.extensions.AsIs('TEXT ' + str(psycopg2.extensions.QuotedString(thestr)))

psycopg2.extensions.register_adapter(str, adapt_str_strict)


(顺便说一句,使用服务器端的
PREPARE
EXECUTE
是行不通的,因为在通过
psycopg2
将值传递给
EXECUTE
时,你会遇到同样的键入问题。)

那么,为什么你要在SQL中使用字符文字作为数字呢?@a_horse_,一个猜测,SQL构建风格,使用
INSERT-INTO-foo(val)值(%s)
和客户端替换…你们都错了,这里的查询只是一些示例,但使用参数化语句(正在使用