porsager / porsager/postgres

SELECT FROM VALUES incorrectly throws an error about undefined values

Open
#1,073 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
8.7k
Forks
374
Avg merge
11d 16h
Merged PRs (30d)
1

Description

Bug Repro

There seems to be a bug in the way the SQL is composed via template strings. Consider the following code:

async function repro() {
    const design = 'd203e218-ea68-46c4-a7c5-a99986062931';
    rows = [{ pos: 0, stone: 'fcc6fdb8-8b7d-47ee-9c7e-891e68718d43', color: 1 }];
    await sql`
      WITH ${makeCheckpointCte(design)}
      INSERT INTO palette (design, checkpoint, pos, stone, color)
      SELECT 
        ${design},
        (SELECT checkpoint FROM next_checkpoint),
        input.pos,
        input.stone,
        input.color
      FROM (VALUES ${sql(rows, 'pos', 'stone', 'color')})
        AS input (pos, stone, color)`;
}
function makeCheckpointCte(design: string) {
  return sql`
    current_checkpoint AS (
      SELECT COALESCE(MAX(checkpoint), -1) AS checkpoint
        FROM design_checkpoints
        WHERE design = (${design})
    ), next_checkpoint AS (
      INSERT INTO design_checkpoints (design, checkpoint)
      SELECT (${design}), 1 + current.checkpoint
        FROM current_checkpoint current
      RETURNING checkpoint
    )`;
}

The line that does FROM (VALUES (...)) causes the following crash.

Error: UNDEFINED_VALUE: Undefined values are not allowed
    at handleValue (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:83:20)
    at stringifyValue (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:113:5)
    at /workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:125:7
    at Array.map (<anonymous>)
    at /workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:124:19
    at Array.map (<anonymous>)
    at valuesBuilder (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:123:16)
    at Object.values [as fn] (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:133:10)
    at Builder.build (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:71:17)
    at stringifyValue (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:109:38)
    at cachedError (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/query.js:170:23)
    at new Query (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/query.js:36:24)
    at sql (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/index.js:112:11)
    at Object.updatePalette (/workspaces/ddt-project-manager/target/src/server/database.js:94:19) {
  code: 'UNDEFINED_VALUE'
}

The SQL I used is close to what the SQL would be without this library. However, I had a suspicion that VALUES should perhaps be dropped. However, doing that only causes a different error.

With the line

      FROM (${sql(rows, 'pos', 'stone', 'color')})

the error becomes

TypeError: str.replace is not a function
    at escape (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:217:20)
    at /workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:213:22
    at Array.map (<anonymous>)
    at escapeIdentifiers (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:213:13)
    at Object.select [as fn] (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:139:12)
    at Builder.build (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:71:17)
    at stringifyValue (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:109:38)
    at stringify (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/types.js:100:16)
    at build (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/connection.js:223:20)
    at Object.execute (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/connection.js:167:7)
    at cachedError (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/query.js:170:23)
    at new Query (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/query.js:36:24)
    at sql (/workspaces/ddt-project-manager/node_modules/.pnpm/postgres@3.4.7/node_modules/postgres/cjs/src/index.js:112:11)
    at Object.updatePalette (/workspaces/ddt-project-manager/target/src/server/database.js:94:19)

so apparently this is not even caught as bad library usage.

Dropping the parenthesis around the interpolated values changes nothing.

Version Info

$ cat package.json | jq .dependencies.postgres
"3.4.7"
$ pnpm -v
10.11.0
$ node -v
v22.16.0

Related Issues

I have only found #1042 to be potentially related.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the reproducer at target/src/server/database.js:94 and the postgres 3.4.7 handling shown in node_modules/.../src/types.js, then run the supplied VALUES query with the reported Node and pnpm versions. Done means the interpolated rows work in the INSERT without UNDEFINED_VALUE or str.replace errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, nodejs, postgres
Domain
backend, databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
50/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.