Skip to content

Commit b4dc6c3

Browse files
committed
fix: handle postgres string literal quotation
1 parent 7cedf08 commit b4dc6c3

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

src/QueryBuilder.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,4 +351,41 @@ describe('from', () => {
351351
expect(results.length).toBeGreaterThan(0)
352352
expect(results.length).toBeLessThanOrEqual(maxResults)
353353
})
354+
355+
test('behavior: hex string parameters are properly quoted', async () => {
356+
// This test verifies that hex strings like 0x... are properly quoted in SQL.
357+
// Without proper quoting, PostgreSQL interprets 0x... as a bit string literal,
358+
// causing "operator does not exist: bytea = bit" errors when comparing to bytea columns.
359+
const hexAddress = '0x4200000000000000000000000000000000000006'
360+
const chainId = 8453
361+
362+
// Capture the request to verify the SQL query
363+
const requests: Request[] = []
364+
is.on('request', (request) => {
365+
requests.push(request)
366+
})
367+
368+
const qb = QueryBuilder.from(is)
369+
370+
await qb
371+
.selectFrom('txs')
372+
.select(['hash'])
373+
.where('chain', '=', chainId)
374+
.where('to', '=', hexAddress)
375+
.limit(1)
376+
.execute()
377+
378+
expect(requests.length).toBeGreaterThan(0)
379+
const request = requests[requests.length - 1]
380+
if (!request) throw new Error('Request not found')
381+
const body = await request.text()
382+
const parsedBody = JSON.parse(body)
383+
const query = parsedBody[0].query as string
384+
385+
// Verify the hex string is properly quoted in the SQL
386+
// Without the fix: WHERE "to" = 0x4200... (bit literal - causes error)
387+
// With the fix: WHERE "to" = '0x4200...' (properly quoted string)
388+
expect(query).toContain(`'${hexAddress}'`)
389+
expect(query).not.toMatch(new RegExp(`= ${hexAddress}(?!')`, 'i'))
390+
})
354391
})

src/QueryBuilder.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,12 @@ class Connection implements DatabaseConnection {
370370

371371
compiledQuery.parameters.forEach((param, i) => {
372372
const placeholder = `$${i + 1}`
373-
query = query.replaceAll(placeholder, String(param))
373+
// Quote string parameters to avoid PostgreSQL interpreting hex as bit literals
374+
const formatted =
375+
typeof param === 'string'
376+
? `'${param.replace(/'/g, "''")}'` // Escape single quotes
377+
: String(param)
378+
query = query.replaceAll(placeholder, formatted)
374379
})
375380

376381
const signatures: string[] = []

0 commit comments

Comments
 (0)