Can I use named parameters with jOOQ SQL executor? - sql

I am using jOOQ to execute arbitrary SQL queries. I am doing this as following:
String result = create.fetchSingle("SELECT ...").getValue(0, String.class);
This query always returns one row and one column, hence the usage of fetchSingle and getValue(0, T). I could not find a method which combines the two.
I now want to pass a named parameter to that query. The parameter is used at several places, so I thought using a named parameter was a good usage here. The type of this parameter is an array of strings.
How can I do this? How do I refer to that parameter in the query? In JDBC, I would write :name_of_parameter::text[].

The API you're looking for is DSLContext.fetchSingle(String, Object...), which accepts a SQL string with parameter placeholders, as well as the actual bindings.
However, it does not support named parameters, only indexed parameters, so you'll have to repeat the value several times, e.g.
create.fetchSingle("SELECT 'a' WHERE ?::text[] = ?::text[]", value, value)
.getValue(0, String.class);

Related

PostgreSQL is it possible to parameterize the table name used in a query?

In PostgreSQL, is it possible to parameterize the table name used in a query?
Think of parameters as a replacement for scalar values only. Use one parameter in the place where you could use one string literal or numeric literal.
You cannot use parameters for other parts of an SQL query:
Identifiers like table names, column names, etc.
SQL keywords
Expressions
Lists of values, such as in an IN (...) predicate. Each value in the list would need an individual parameter.
All those parts of the SQL query must be fixed by the time the query is parsed during prepare(). If a client library supports "parameters" for identifiers, it's really doing string-interpolation into the SQL query before the query is parsed.

Is it possible to use a generic identifier in a SELECT query in SQLite?

I'm creating a function for querying a SQLite database that should be generic in the sense of reading from multiple pre-defined tables. As part of the function's paremeters, it is necessary to tel which column of the table should be read, an info that is supposed to be passed by an enumerator value. So the call would be something like this:
callMyFunction(enumTableA,enumColumnB);
Since enumColumnB is an enumerator value, the argument is an integer and I would like to identify the column by that integer value without having to use a switch-case for that. Something like this:
SELECT column(enumColumnB) from ...
So instead of passing the name of the column or reading all columns with * and then selecting the desired one when reading, it would use the number of the column as passed by the enumerator value to identify what should be read.
Is it possible to do this for SQLite? I couldn't find any tutorial mentioning such possibility, so I'm almost concluding there is no such possibility (and I'll have to pass the name of the column as argument or use a switch-case at the end), but I'ld like to be sure I don't have this option available.
SQLite has no mechanism for indirect columns.
(SQLite is designed as an embedded database, i.e., to be used together with a 'real' programming language.)
You have to replace the column name in whatever programming language you're using.

Why should "ordinary string formatting" be used for table/field names in psycopg queries?

From the documentation on properly passing SQL parameters to psycopg2:
"Only variable values should be bound via this method: it shouldn’t be used to set table or field names. For these elements, ordinary string formatting should be used before running execute()."
http://initd.org/psycopg/docs/usage.html#passing-parameters-to-sql-queries
Why is this? Why would setting a field name not have the same SQL injection problems as setting values?
Because you don't usually receive names of your tables or fields from users, you specify them in your code yourself. If you generate your request based on values got from user input, than yes, you should do some kind of escaping to avoid SQL injections.

Infinite optional parameters

In essence, I'd like the ability to create a scalar function which accepts a variable number of parameters and concatenates them together to return a single VARCHAR. In other words, I want the ability to create a fold over an uncertain number of variables and return the result of the fold as a VARCHAR, similar to .Aggregate in C# or Concatenate in Common Lisp.
My (procedural) pseudo code for such a function is as follows:
define a VARCHAR variable
foreach non-null parameter convert it to a VARCHAR and add it to the VARCHAR variable
return the VARCHAR variable as the result of the function
Is there an idiomatic way to do something like this in MS-SQL? Does MS-SQL Server have anything similar to the C# params/Common Lisp &rest keyword?
-- EDIT --
Is it possible to do something similar to this without using table-valued parameters, so that a call to the function could look like:
MY_SCALAR_FUNC('A', NULL, 'C', 1)
instead of having to go through the rigmarole of setting up and inserting into a new temporary table each time the function is called?
For a set of items, you could consider passing a table of values to your function?
Pass table as parameter into sql server UDF
See also http://technet.microsoft.com/en-us/library/ms191165(v=sql.105).aspx
To answer your question directly, no, there is no equivalent to the params keyword. The approach I'd use is the one above - Create a user-defined table type, populate that one row per value, and pass that to your scalar function to operate on.
EDIT: If you want to avoid table parameters, and are on SQL 2012, look at the CONCAT function:
http://technet.microsoft.com/en-us/library/hh231515.aspx
CONCAT ( string_value1, string_value2 [, string_valueN ] )
This is only for the built-in CONCAT function, you couldn't roll-your-own function with "params" style declaration.

Preg_replace solution for prepared statements

I have a command class that abstracts almost all specific database functions (We have the exactly same application running on Mssql 2005 (using ODBC and the native mssql library), MySQL and Oracle. But sometimes we had some problems with our prepare method that, when executed, replaces all placeholders with their respective values. But the problem is that I am using the following:
if(is_array($Parameter['Value']))
{
$Statement = str_ireplace(':'.$Name, implode(', ', $this->Adapter->QuoteValue($Parameter['Value'])), $Statement);
}
else
{
$Statement = str_ireplace(':'.$Name, $this->Adapter->QuoteValue($Parameter['Value']), $Statement);
}
The problem arises when we have two or mer similar parameters names, for example, session_browser and session_browse_version... The first one will partially replace the last one.
Course we learned to go around specifying the parameters within a specific order, but now that I have some "free" time I want to make it better, so I am thinking on switching to preg_replace... and I am not good in regular expression, can anyone give any help with a regex to replace a string like ':parameter_name`?
Best Regards,
Bruno B B Magalhaes
You should use the \b metacharacter to match the word boundary, so you don't accidentally match a short parameter name within a longer parameter name.
Also, you don't need to special-case arrays if you coerce a scalar Value to an array of one entry:
preg_replace("/:$Name\b/",
implode(",", $this->Adapter->QuoteValue( (array) $Parameter['Value'] )),
$Statement);
Note, however, that this can make false positive matches when an identifier or a string literal contains a pattern that looks like a parameter placeholder:
SELECT * FROM ":Name";
SELECT * FROM Table WHERE column = ':Name';
This gets even more complicated when quoted identifiers and string literals can contain escaped quotes.
SELECT * FROM Table WHERE column = 'word\':Name';
You might want to reconsider interpolating variables into SQL strings during prepare, because you're defeating any benefits of prepared statements with respect to security or performance.
I understand why you're doing what you're doing, because not all RDBMS back-end supports named parameters, and also SQL parameters can't be used for lists of values in an IN() predicate. But you're creating an awfully leaky abstraction.