Skip to content

Conversation

Tishj
Copy link
Contributor

@Tishj Tishj commented Dec 3, 2022

This PR implements named parameters (mentioned in #5388)

Basically what happens is we now detect if the passed object to params is a dict, and if it is we assume these contain named parameters, so we replace $param_name with $1 in the query string and populate the param list with the corresponding values of the dict.

Test todos:
ExecuteMany tests
queries containing the named parameter in strings

Also need to check if there is no existing functionality for dictionary as param that gets broken by this change

param_name);
}
// Replace all occurences of $name with $<index>
query = StringUtil::Replace(query, param_name, StringUtil::Format("$%d", param_idx));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very much an edge case, but what if $variable appears inside a string in the query?

Copy link
Contributor Author

@Tishj Tishj Dec 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I thought about this but only in relation to column names, which I reasoned cant contain $, but you raise a valid point, string literals can contain this..

Definitely needs a test for this and probably requires changing the implementation 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My main concern is for people using regex's, where '$hello' is perfectly valid regex

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, definitely, already said you're right 👍
Need to change the implementation

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep just giving a realish query example that could break

@Tishj Tishj marked this pull request as draft December 3, 2022 12:58
@Tishj
Copy link
Contributor Author

Tishj commented Dec 4, 2022

Hmm it seems this does come at the cost of existing functionality, since

import duckdb

con = duckdb.connect()
con.execute("create table tbl (i integer)")
con.execute("insert into tbl VALUES (?), (?), (?)", {2:5,3:6,5:4})
res = con.execute("select * from tbl").fetchall()
print(res)
# [(2,), (3,), (5,)]

currently works on master
So in this case, we take the key part of the dictionary as the prepared parameter
But this doesn't look like great behavior in my opinion, though it is understandable (for key in dict: is default behavior)

@Mause
Copy link
Member

Mause commented Dec 5, 2022

Hmm it seems this does come at the cost of existing functionality, since

import duckdb

con = duckdb.connect()
con.execute("create table tbl (i integer)")
con.execute("insert into tbl VALUES (?), (?), (?)", {2:5,3:6,5:4})
res = con.execute("select * from tbl").fetchall()
print(res)
# [(2,), (3,), (5,)]

currently works on master So in this case, we take the key part of the dictionary as the prepared parameter But this doesn't look like great behavior in my opinion, though it is understandable (for key in dict: is default behavior)

It seems unlikely that people are using it like this, and the fix is pretty straightforward - list(dict_variable)

@Alex-Monahan
Copy link
Contributor

I would agree that few folks are likely to be using a dict's keys to pass in params!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants