hi, any idea how I can pass identifiers (table names) via parameters in honeysql ? I tried this (with [:param ..] as well) but the table name gets quoted (wrongly) for PostgreSQL .
(honey.sql/format {:select [:id] :from :?articles}
{:params {:articles "articles_2604"} :inline true})
;;=> ["SELECT id FROM 'articles_2604'"]is this the idiomatic way?
(honey.sql/format {:select [:id] :from [(keyword "articles_2604")]}
{:inline true})
;;=> ["SELECT id FROM articles_2604"]
Not sure what you're trying to achieve. What do you mean by "via parameters"? Your second code block is exactly the same as this,:
(honey.sql/format {:select :id :from :articles_2604})
=> ["SELECT id FROM articles_2604"]Do you mean that you have a string and want to use it as a table name?
If so then yeah, (keyword ...) is the way to go. But no need for :inline.
hi, I want to query a table for which the name is supplied via a form
not baked into code
From the perspective of SQL, that's not via parameters - meaning, it doesn't become a parameter in a prepared SQL statement. It has to be baked into the SQL statement itself. And that's exactly what happens when you use (keyword ...) like above.
I tried this, but it capitalizez the table name and that might now always work (for example some people use CamleCase table names for postgres and those require quoting: public."CamelCase"
(honey.sql/format {:select [:id] :from [:?articles]}
{:params {:articles (keyword "articles_2604")}
:inline true})
;;=> ["SELECT id FROM ARTICLES_2604"]Because that's not the intended usage of :params. Just don't use it for table names. And definitely don't use :inline here - it's a recipe for SQL injections:
(honey.sql/format {:select [:id] :from [:?articles]}
{:params {:articles (keyword "foo; drop table foo;")}
:inline true})
=> ["SELECT id FROM FOO; DROP TABLE FOO;"]> From the perspective of SQL, that's not via parameters - meaning, it doesn't become a parameter in a prepared SQL statement. It has to be baked into the SQL statement itself. And that's exactly what happens when you use (keyword ...) like above.
HugSQL has a way to pass identifiers and I thought honeyssql has something similar:
https://www.hugsql.org/hugsql-in-detail/parameter-types/sql-identifier-parameters
That's "Identifier Parameters", a term that can be scoped only to HugSQL itself. It's not a thing in general.
> And definitely don't use :inline here - it's a recipe for SQL injections:
thanks, inline is for easy exploration
Without :inline, your :?articles won't work at all. :)
> That's "Identifier Parameters", a term that can be scoped only to HugSQL itself. It's not a thing in general. I know, I was looking for the equivalent in HoneySQL
(keyword ...) is the equivalent. HoneySQL is fully programmatic so it doesn't call it "parameters". Anything can be parameterized there, you can construct the whole map in any way you like. You can "parameterize" the SELECT keyword.
seems a bit convoluted that I have to convert to keyword so it's converted back to string
do you know if it does some (SQL injection) checks during translation?
That's what DSLs require in general when they depend on specific types.
A map -> a statement, a vector -> depends on the nesting level, a keyword -> an identifier or a keyword, a scalar value -> an SQL parameter.
> do you know if it does some (SQL injection) checks during translation?
To a degree, but do not rely on it. Instead, never use :inline with user-provided data without your own checks, never put user-provided non-scalars and non-keywords inside sqlmaps. And set up proper quoting compatible with your DB, just in case.
(honey.sql/format {:select :id :from (keyword "foo; drop table foo;")})
Execution error (ExceptionInfo) at honey.sql/suspicious-entity-check (sql.cljc:170).
suspicious character found in entity: "foo; drop table foo;"thanks, I think the above info, regarding sql identifiers and solution to use keywords should be added to docs. wdyt? cc @seancorfield . Also, would it make sense to expose these table names in the HoneySQL DSL ? Something like {:from [:identifier "table-name"]} - and do specific checks for identifier ?
HoneySQL accepts symbols or keywords in the DSL:
(honey.sql/format (assoc '{select id ...} 'from (symbol my-table)))
Not sure what you think specifically needs adding to the docs? The DSL is "just" Clojure data.
Feel free to open an issue with specific suggestions -- or even a draft PR for discussion.for a beginer like me, these are not obvious
in my mind, "The DSL is "just" Clojure data." does not translate to, hei if I need to pass a table name as a parameter I can just use (keyword) or symbol my-table
I'll try a more specific question then: what part of the docs made you think you could pass a table name in as a parameter? From the docs: "SQL Parameters As indicated in the preceding sections, values found in the DSL data structure that are not keywords or symbols are lifted out as positional parameters." What parts of the docs do you think you would read to get more information on dynamic table names?
Maybe this would work for your use case (but table really should be a keyword or symbol for the DSL):
user=> (let [table "foo"] (honey.sql/format {:select :id :from [[[:entity table]]]} {:dialect :mysql}))
["SELECT `id` FROM `foo`"]
user=> (let [table "foo"] (honey.sql/format {:select :id :from [[[:entity table]]]} {:quoted true}))
["SELECT \"id\" FROM \"foo\""]there was no part in the docs that indicated that. I had some experience with HugSQL and saw they have identifier parameters for table names and such (see link above). I tried to find the equivalent in HoneySQL for that since I needed to pass a table name as a parameter.