How do you use "?" with sqlite statements in an executeQuery method? - iphone

I assume that you can include "?" in your sqlite statement, provided in the "executeQuery" method, you pass additional arguments corresponding to each "?". But when I put this to practice, the results are not consistent.
This statement works:
SELECT * FROM answers WHERE test_id = ? and question_id = ?
with this method
FMResultSet * answer = [[UIApp database] executeQuery:[Queries getTheAnswer], l, n];
The following statement crashes the program when I include a "?"
SELECT * FROM questions where test_id = ? ORDER BY RANDOM() LIMIT ?
FMResultSet * set = [[UIApp database] executeQuery:[Queries randomNumberOfVerses], selectedTests, numRounds];
But works fine when I hardcode a value in.
SELECT * FROM questions where test_id = 5 ORDER BY RANDOM() LIMIT ?
FMResultSet * set = [[UIApp database] executeQuery:[Queries randomNumberOfVerses], numRounds];
Any suggestions since I don't want to hardcode values in? All variable used as arguments are of type NSNumber*

I don't know the iPhone or Objective C, but usually ? arguments are used for prepared statements, rather than "immediate mode" queries.
In the SQLite C API, the functions you're interested in are called sqlite3_prepare*().
If you can figure out what the Objective C mapping is for those, you should be able make some progress.
Edit:
I almost forgot the part that actually answers your question...
Once you have a prepared statement, use the sqlite3_bind*() functions to give values to the query parameters.

While WHERE clauses can include bind-parameters, the LIMIT argument cannot. It has to be an integer literal. See the SQLite Syntax Diagram.
Given that, I'm not sure why your last one is working. It should be fine if you hardcode the LIMIT argument, leaving the test_id = ?, but it shouldn't work when you use ? for the LIMIT.

Related

EF Core raw query with Like clause

I want to create queries using EF FromSqlInterpolated or FromSqlRaw that allows me to use Like clauses, but I don't know what is the right way to do it without opening the application to SqlInjection attacks.
One first approach has took me to the following code
var results = _context.Categories.FromSqlInterpolated(
$"Select * from Category where name like {"%" + partialName + "%"}");
First test worked fine, it returns results when providing expected strings, and returns nothing when i provide something like ';select * from Category Where name='Notes'--%';
Still I don't know much about SqlInjection, at least not enough to feel safe with the query shown before.
Does someone know if the query is safe, or if there is a right way to do it?
Thanks
From this document
The FromSqlInterpolated and ExecuteSqlInterpolated methods allow using
string interpolation syntax in a way that protects against SQL injection attacks.
var results = _context.Categories.FromSqlInterpolated(
$"Select * from Category where name like {"%" + partialName + "%"}");
Or you can also change your query to Linq-to-Entity like this way
var results = _context.Categories.Where(p => p.name.Contains(partialName ));

Avoiding SQL injections with prepare and execute

A line of code like
my $sql_query = "SELECT * FROM Users WHERE user='$user';";
might introduce an SQL injection vulnerability into your program. To avoid this one could use something like
my $sth = $dbh->prepare("SELECT * FROM Users WHERE user='?';");
$dbh->execute($user);
However, in the code I am currently working on the following is used
$sql_query = "SELECT * FROM Users WHERE user='" . $user . "';";
$dbh->prepare($sql_query);
$dbh->execute();
Does this actually work? If yes, are there any differences to what I would have done? What are the advantages and disadvantages?
my $sth = $dbh->prepare("SELECT * FROM Users WHERE user='?'");
This won't work because it's searching for a literal '?' character — not a parameter. If you try to send a value for the parameter, MySQL will be like, "what do you want me to do with this?" because the query has no parameter placeholder.
If you want to use a parameter, you must NOT put the parameter placeholder inside string delimiters in the SQL query, even if the parameter will take string or datetime value:
my $sth = $dbh->prepare("SELECT * FROM Users WHERE user=?");
The next example:
$sql_query = "SELECT * FROM Users WHERE user='" . $user . "'";
$dbh->prepare($sql_query);
$dbh->execute();
That will run the query, but it's NOT safe. You can prepare any query even if it has no parameters.
Using prepare() is not what makes queries safe from SQL injection. What makes it safer is using parameters to combine dynamic values instead of doing string-concatenation like you're doing in this example.
But using parameters does require the use of prepare().
PS: You don't need to put ; at the end of your SQL queries when you run them one at a time programmatically. The separator is only needed if you run multiple queries, like in an SQL script, or in a stored procedure. In your examples, the ; is harmless but MySQL doesn't require it, and it will just ignore it.

How to insert similar value into multiple locations of a psycopg2 query statement using dict? [duplicate]

I have a Python script that runs a pgSQL file through SQLAlchemy's connection.execute function. Here's the block of code in Python:
results = pg_conn.execute(sql_cmd, beg_date = datetime.date(2015,4,1), end_date = datetime.date(2015,4,30))
And here's one of the areas where the variable gets inputted in my SQL:
WHERE
( dv.date >= %(beg_date)s AND
dv.date <= %(end_date)s)
When I run this, I get a cryptic python error:
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) argument formats can't be mixed
…followed by a huge dump of the offending SQL query. I've run this exact code with the same variable convention before. Why isn't it working this time?
I encountered a similar issue as Nikhil. I have a query with LIKE clauses which worked until I modified it to include a bind variable, at which point I received the following error:
DatabaseError: Execution failed on sql '...': argument formats can't be mixed
The solution is not to give up on the LIKE clause. That would be pretty crazy if psycopg2 simply didn't permit LIKE clauses. Rather, we can escape the literal % with %%. For example, the following query:
SELECT *
FROM people
WHERE start_date > %(beg_date)s
AND name LIKE 'John%';
would need to be modified to:
SELECT *
FROM people
WHERE start_date > %(beg_date)s
AND name LIKE 'John%%';
More details in the pscopg2 docs: http://initd.org/psycopg/docs/usage.html#passing-parameters-to-sql-queries
As it turned out, I had used a SQL LIKE operator in the new SQL query, and the % operand was messing with Python's escaping capability. For instance:
dv.device LIKE 'iPhone%' or
dv.device LIKE '%Phone'
Another answer offered a way to un-escape and re-escape, which I felt would add unnecessary complexity to otherwise simple code. Instead, I used pgSQL's ability to handle regex to modify the SQL query itself. This changed the above portion of the query to:
dv.device ~ E'iPhone.*' or
dv.device ~ E'.*Phone$'
So for others: you may need to change your LIKE operators to regex '~' to get it to work. Just remember that it'll be WAY slower for large queries. (More info here.)
For me it's turn out I have % in sql comment
/* Any future change in the testing size will not require
a change here... even if we do a 100% test
*/
This works fine:
/* Any future change in the testing size will not require
a change here... even if we do a 100pct test
*/

Assigning a whole DataStructure its nullind array

Some context before the question.
Imagine file FileA having around 50 fields of different types. Instead of all programs using the file, I tried having a service program, so the file could only be accessed by that service program. The programs calling the service would then receive a DataStructure based on the file structure, as an ExtName. I use SQL to recover the information, so, basically, the procedure would go like this :
Datastructure shared by service program :
D FileADS E DS ExtName(FileA) Qualified
Procedure called by programs :
P getFileADS B Export
D PI N
D PI_IDKey 9B 0 Const
D PO_DS LikeDS(FileADS)
D LocalDS E DS ExtName(FileA) Qualified
D NullInd S 5i 0 Array(50) <-- Since 50 fields in fileA
//Code
Clear LocalDS;
Clear PO_DS;
exec sql
SELECT *
INTO :LocalDS :nullind
FROM FileA
WHERE FileA.ID = :PI_IDKey;
If SqlCod <> 0;
Return *Off;
EndIf;
PO_DS = LocalDS;
Return *On;
P getFileADS E
So, that procedure will return a datastructure filled with a record from FileA if it finds it.
Now my question : Is there any way I can assign the %nullind(field) = *On without specifying EACH 50 fields of my file?
Something like a loop
i = 1;
DoW (i <= 50);
if nullind(i) = -1;
%nullind(datastructure.field) = *On;
endif;
i++;
EndDo;
Cause let's face it, it'd be a pain to look each fields of each file every time.
I know a simple chain(n) could do the trick
chain(n) PI_IDKey FileA FileADS;
but I really was looking to do it with SQL.
Thank you for your advices!
OS Version : 7.1
First, you'll be better off in the long run by eliminating SELECT * and supplying a SELECT list of the 50 field names.
Next, consider these two web pages -- Meaningful Names for Null Indicators and Embedded SQL and null indicators. The first shows an example of assigning names to each null indicator to match the associated field names. It's just a matter of declaring a based DS with names, based on the address of your null indicator array. The second points out how a null indicator array can be larger than needed, so future database changes won't affect results. (Bear in mind that the page shows a null array of 1000 elements, and the memory is actually relatively tiny even at that size. You can declare it smaller if you think it's necessary for some reason.)
You're creating a proc that you'll only write once. It's not worth saving the effort of listing the 50 fields. Maybe if you had many programs using this proc and you had to create the list each time it'd be a slight help to use SELECT *, but even then it's not a great idea.
A matching template DS for the 50 data fields can be defined in the /COPY member that will hold the proc prototype. The template DS will be available in any program that brings the proc prototype in. Any program that needs to call the proc can simply specify LIKEDS referencing the template to define its version in memory. The template DS should probably include the QUALIFIED keyword, and programs would then use their own DS names as the qualifying prefix. The null indicator array can be handled similarly.
However, it's not completely clear what your actual question is. You show an example loop and ask if it'll work, but you don't say if you had a problem with it. It's an array, so a loop can be used much like you show. But it depends on what you're actually trying to accomplish with it.
for old school rpg just include the nulls in the data structure populated with the select statement.
select col1, ifnull(col1), col2, ifnull(col2), etc. into :dsfilewithnull where f.id = :id;
for old school rpg that can't handle nulls remove them with the select statement.
select coalesce(col1,0), coalesce(col2,' '), coalesce(col3, :lowdate) into :dsfile where f.id = :id;
The second method would be easier to use in a legacy environment.
pass the key by value to the procedure so you can use it like a built in function.
One answer to your question would be to make the array part of a data structure, and assign *all'0' to the data structure.
dcl-ds nullIndDs;
nullInd Ind Dim(50);
end-ds;
nullIndDs = *all'0';
The answer by jmarkmurphy is an example of assigning all zeros to an array of indicators. For the example that you show in your question, you can do it this way:
D NullInd S 5i 0 dim(50)
/free
NullInd(*) = 1 ;
Nullind(*) = 0 ;
*inlr = *on ;
return ;
/end-free
That's a complete program that you can compile and test. Run it in debug and stop at the first statement. Display NullInd to see the initial value of its elements. Step through the first statement and display it again to see how the elements changed. Step through the next statement to see how things changed again.
As for "how to do it in SQL", that part doesn't make sense. SQL sets the values automatically when you FETCH a row. Other than that, the array is used by the host language (RPG in this case) to communicate values back to SQL. When a SQL statement runs, it again automatically uses whatever values were set. So, it either is used automatically by SQL for input or output, or is set by your host language statements. There is nothing useful that you can do 'in SQL' with that array.

Reusing ?'s on a DBI prepare

Is there a way to reuse the ?'s used on a DBI prepare statement. Consider the following code:
$sth=$dbh->prepare("INSERT INTO mytable(a,b,c) SELECT ?,B(?),C(?)");
$sth->execute($a,$a,$a);
It would be very nice to instead use something like this:
#I'm making this up as something I hope exists
$sth=$dbh->prepare("INSERT INTO mytable(a,b,c) SELECT ?,B(?:1),C(?:1)");
$sth->execute($a);
Notice that only one $a is passed to the execute instead of three. Is there a way to do this in real life?
It depends on your DBD. For example, using DBD::Pg with the $1 style of placeholders, or DBD::Oracle with named placeholders and bind_param, you can do exactly what you like. But using the general purpose ? style of placeholders that works DBI-wide, it's not possible.
If you use a library to generate your SQL statements for you, e.g. SQL::Abstract or a full-on ORM like DBIx::Class, you won't have to worry about things like that.
Alternatively you can do something similar with just a few lines of code:
my $sql = 'INSERT INTO ...blah blah... VALUES (' . (join(', ', ('?') x scalar(#insert_elements))) . ')';
#hobbs' answer is right -- default DBI placeholders can't do it. #Ether's answer is right -- a SQL abstraction can make this a non-issue.
However, typically one need only bind each distinct parameterized value once. In your example, using a scalar derived table makes the user-supplied value available by name to the rest of the query:
my $sth = $dbh->prepare(<<'__eosql');
INSERT INTO mytable(a,b,c)
SELECT x, B(x), C(x) FROM (SELECT ? AS x) subq
-- Subquery may vary from DB to DB:
-- "FROM (SELECT ? AS x FROM DUAL) subq"
-- "FROM (SELECT ? FROM rdb$database) subq(x)"
-- "FROM (VALUES (?)) subq(x)"
-- etc.
__eosql
for $v (#values) {
$sth->execute($v);
}
Usually this is incrementally more "wire efficient" than the alternative, since the user-supplied parameter is typically transmitted just once instead of N times.
You can set SQL variables in one SQL statement and then use that variable multiple times in the next query.
$dbh->do('set #reusable = ?', undef, $perl_var);
$dbh->select_arrayref('select * from table where cola = #reusable or colb = #reusable');
No duplicated variables and you still get the safety of parameterized queries.