简体   繁体   中英

UPDATE in PostgreSQL 9.1 seems to misuse placeholder types

Given the following schema (as an example)

CREATE TABLE "test" (
  "id" int, 
  "title" varchar
);

in NodeJS, I try to do an UPDATE with the following

client.query(
            'WITH new_vals ("id","title") AS (VALUES($1,$2)) ' +
            'UPDATE "test" "t" SET "id"=nv.id, "title"=nv.title ' +
            'FROM new_vals nv ' +
            'WHERE "t"."id"=nv.id;',
        [1,'test'],
        function(err, res){ ... }
);

And it gives me the following error: 'error: operator does not exist: integer = text'

Ok, let's try to stop using "t"."id"=nv.id and just reuse one the available parameters:

client.query(
            'WITH new_vals ("id","title") AS (VALUES($1,$2)) ' +
            'UPDATE "test" "t" SET "id"=nv.id, "title"=nv.title ' +
            'FROM new_vals nv ' +
            'WHERE "t"."id"=$1;',
        [1,'test'],
        function(err, res){ ... }
);

Still 'error: operator does not exist: integer = text' .

Ok, now let's add another $3 placeholder:

client.query(
            'WITH new_vals ("id","title") AS (VALUES($1,$2)) ' +
            'UPDATE "test" "t" SET "id"=nv.id, "title"=nv.title ' +
            'FROM new_vals nv ' +
            'WHERE "t"."id"=$3;',
        [1,'test',1],
        function(err, res){ ... }
);

Another error: 'error: column "id" is of type integer but expression is of type text'

I'm completely lost. Why doesn't it use the int operator classes in WHERE? What's wrong here?

Strangely, the standard UPDATE form without the WITH clause works fine...

In case you need the code to play with: https://gist.github.com/kolypto/7455957

In this context:

WITH new_vals ("id","title") AS (VALUES($1,$2))

PostgreSQL has no idea what type $1 or $2 are going to be so they will end up being treated as text values. The fine manual notes this :

When VALUES is used in INSERT , the values are all automatically coerced to the data type of the corresponding destination column. When it's used in other contexts, it might be necessary to specify the correct data type.

and in values($1, $2) , the types cannot be inferred so you have to be explicit:

WITH new_vals ("id", "title") AS (VALUES($1::integer, $2::text))

The cast on $2 isn't necessary but I like to be consistent.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM