honeysql

Discussion of https://github.com/seancorfield/honeysql :slightly_smiling_face:
wombawomba 2020-07-17T14:47:01.220700Z

How can I reproduce a PostgreSQL hex->int cast (`x'beef'::int`) in HoneySQL?

seancorfield 2020-07-17T15:12:10.222800Z

@wombawomba I was going to suggest the PostgreSQL extensions to HoneySQL https://github.com/nilenso/honeysql-postgres but that doesn't seem to have anything so you're either going to need to use #raw (or honeysql.core/raw) or perhaps use a regular cast via #call etc?

wombawomba 2020-07-17T15:12:35.223300Z

yeah I’m already using that, but I couldn’t find anything for this

wombawomba 2020-07-17T15:15:51.224600Z

cast works, but I’m not sure how to create the hex literal (`cast(x'aa' AS int)` works but cast('aa' AS int) doesn’t)

seancorfield 2020-07-17T15:16:31.225400Z

If it's just a literal, use #raw

seancorfield 2020-07-17T15:16:54.225800Z

#raw "x'aa'::int"

wombawomba 2020-07-17T15:17:10.226400Z

ah, okay

wombawomba 2020-07-17T15:17:18.226800Z

any way to make that non-sql-injectable?

seancorfield 2020-07-17T15:17:33.227100Z

If it's a literal it can't be injected.

wombawomba 2020-07-17T15:17:42.227500Z

oh, sorry

seancorfield 2020-07-17T15:17:46.227800Z

and the reader tags only work on literals

wombawomba 2020-07-17T15:18:26.228600Z

I meant literal as in x'...' is the syntax for a “hex literal” in Postgres

wombawomba 2020-07-17T15:18:46.229100Z

I want the string itself (i.e. '...') to be parametrized

seancorfield 2020-07-17T15:19:03.229500Z

That doesn't make sense.

wombawomba 2020-07-17T15:19:22.229700Z

why not?

seancorfield 2020-07-17T15:19:58.230500Z

Okay, take a step back -- what actual problem are you trying to solve here? You asked about hex literals in each case.

seancorfield 2020-07-17T15:20:42.231600Z

x'..' has to be a literal. It's not a parameterizable thing.

wombawomba 2020-07-17T15:21:39.232600Z

oh okay, I think I see what you’re saying

seancorfield 2020-07-17T15:22:16.233900Z

So what I think you're asking is: "I have a hex string in Clojure but I want to pass it as an int to SQL..."?

wombawomba 2020-07-17T15:22:24.234200Z

my problem is that I have a bunch of queries like INSERT INTO foo (col, ...) VALUES (x'a123'::int8, ...) that I want to call from Clojure, with the ‘hex string’ parametrized

seancorfield 2020-07-17T15:22:45.234900Z

They are LITERALS.

wombawomba 2020-07-17T15:22:53.235300Z

well almost; I want to pass it as hex to postgres and then I want postgres to handle the conversion

wombawomba 2020-07-17T15:23:20.235700Z

but what you’re saying is that there’s no way to parametrize literals

seancorfield 2020-07-17T15:23:30.236200Z

Of course there isn't. They are literals.

seancorfield 2020-07-17T15:24:20.237100Z

If it is a literal value in your code, it cannot be an injection vector. Only values coming in from "outside" can be a vector for injection attacks.

wombawomba 2020-07-17T15:24:59.237400Z

right

seancorfield 2020-07-17T15:26:02.238400Z

If you have Clojure strings that are in hex, coming from "outside", those strings could be an injection vector -- but they are, by definition not literals, and you cannot use SQL's literal syntax on them.

wombawomba 2020-07-17T15:26:38.239200Z

yeah sorry, I didn’t realize there was no way to map a string to a (non-string) literal in SQL

seancorfield 2020-07-17T15:27:42.240700Z

If you have hex data from "outside", you need to convert that to numbers yourself.

wombawomba 2020-07-17T15:27:54.241100Z

I want the conversion to happen in the db though

wombawomba 2020-07-17T15:28:29.241900Z

but it sounds like this is more of a Postgres concern than a HoneySQL concern, so I guess I’ll take my question elsewhere

seancorfield 2020-07-17T15:30:58.243700Z

It's not specific to PostgreSQL. Parameters are entire values. ?::int8 would be legal, where you're passing in a number.

wombawomba 2020-07-17T15:31:48.244400Z

yeah, unfortunately however Postgres doesn’t do the hex conversion for that one

seancorfield 2020-07-17T15:31:59.244600Z

Of course it doesn't.

seancorfield 2020-07-17T15:33:21.245800Z

If you can find a PG function that accepts a hex string -- just the string portion, not with an x prefix -- and produces a number, that's going to be the way to go.

wombawomba 2020-07-17T15:33:57.246200Z

yeah, that’s what I was trying to say with “it’s a Postgres concern”

seancorfield 2020-07-17T15:37:40.248Z

Based on my Bing results, this seems to be a fairly common question about PG and there really are no entirely good answers (several people on SO suggest bashing strings together to get a hex literal and passing that to PG but that's dangerous and open to attack vectors).

wombawomba 2020-07-17T15:37:49.248300Z

for the record, apparently the solution is basically to build a string and eval (EXECUTE) it (https://stackoverflow.com/a/8316731/2571391)

wombawomba 2020-07-17T15:38:12.248800Z

okay yeah, sounds like we came to the same conclusion 🙂

wombawomba 2020-07-17T15:38:34.249500Z

guess I’ll just have to convert the string in Clojure-land

seancorfield 2020-07-17T15:39:12.250100Z

This https://stackoverflow.com/questions/8316164/convert-hex-in-text-representation-to-decimal-number?noredirect=1 mentions a bn_in_hex() function but the comments suggest it is not available in all PG distributions.

seancorfield 2020-07-17T15:39:26.250900Z

(scroll past the various string-bashing "wrong" answers)

wombawomba 2020-07-17T15:39:32.251100Z

right yeah, seems like you’d need an extension for it

seancorfield 2020-07-17T15:40:09.251900Z

I really think the better approach is to do the hex to int conversion in Clojure and handle input validation there, and then pass the int to the SQL.

wombawomba 2020-07-17T15:40:20.252200Z

yeah, that’s what I’m thinking

wombawomba 2020-07-17T15:41:14.253300Z

it’ll make grepping my logs a bit trickier, but I guess I’ll have to cope

wombawomba 2020-07-17T15:44:59.255700Z

BTW, you wouldn’t happen to have any material on why parametrizing these ‘custom’ literals is impossible but parametrizing a regular string literal is fine? I got the impression you thought it was a dumb question but it doesn’t seem at all obvious to me why it’d be the case.

seancorfield 2020-07-17T15:45:16.255900Z

At what point in your code are you logging this? Couldn't you log before the hex->int conversion?

seancorfield 2020-07-17T15:45:45.256800Z

I'm not sure what to point you at re: parameterization -- this is just a matter of SQL syntax.

wombawomba 2020-07-17T15:46:13.257600Z

yeah, I do that too; but when there are (unexpected) SQL exceptions or when I’m doing debug logging I log the query data

wombawomba 2020-07-17T15:48:31.259600Z

Well, my thought was that since I can replace all literals I’ve encountered thus far (like 'foo', true, 123) with a parameter in a parametrized query, I should be able to do the same thing with this other type of literal x'fff'.

wombawomba 2020-07-17T15:50:57.261700Z

What I don’t see is what makes this distinction obvious; but I presume that’s because I’m not really familiar with the SQL standard or JDBC or wherever the distinction between these different types of literals is made.

seancorfield 2020-07-17T15:52:16.262100Z

Sorry, I just don't know how to explain it other than "syntax".

wombawomba 2020-07-17T15:52:39.262300Z

Alright :)

wombawomba 2020-07-17T16:06:38.263700Z

okay, after a bit of googling it seems like x'aa' is a literal for the “bit string” SQL type, and the problem here is actually that JDBC doesn’t have a way of sending bit strings (just for the record)