How to delete multiple rows (using named parameters) in Adobe AIR - actionscript-3

I am trying to delete multiple rows in the sqlite table in my Adobe AIR app (runtime 2.5).
Here is the statement, using the "IN" operator:
"DELETE FROM mylist WHERE tdId IN (tdId1, tdId2, tdId3, ...)";
Where tdId1, tdId2, etc. will be determined at runtime based on which row(s) the user chooses to delete. The user can delete arbitrary number of rows.
I've tried something like:
//delete statement text
"DELETE FROM mylist WHERE tdId IN :tdId";
//delete statement parameters: take 1.
//Got "argument error: near ':tdId': syntax error"
deleteStmt.parameters[":tdId"] = "(26, 32)";
//delete statement parameters: take 2.
//Also got "argument error: near ':tdId': syntax error"
var arr:Array = [26, 32];
deleteStmt.parameters[":tdId"] = arr;
How I go about deleting multiple rows?
[Edit] So it looks like the aforementioned cached statement with parameter [":tdId"] doesn't work when deleting multiple rows. When attempting to execute the delete statement multiple times in asynchronous mode, after the very first row in the queue is deleted, Flash throws the following error:
"Error #3110: Operation cannot be
performed while SQLStatement.executing
is true."
It would seem too much of trouble to chain these deletes with a callback. So I guess I am using my last resort: building the sql at runtime. Conclusion: Cached statements can't be used in these kind of situations...

The problem occurs when you insert the parameter "(26,32)". As the parameter is not purely a substitution of value, it represents a variable to SQL, NOT A STRING. Hence you statement effectively became (or roughly) in your first take...
"DELETE FROM mylist WHERE tdId IN '(26,32)'"
Hence your error, due to the syntax... In your second take it gets worse...
"DELETE FROM mylist WHERE tdId IN *Array(26,32)*"
As the variable does not convert to a string value, this does not actually happen. But what happens is that when the interprater (SQL) tries to understand the code after the 'IN' text, it gets an ARRAY object, which it has completely no idea on what to do... Its not even a valid SQL type....
Solution? [I yet to fully test it, so please do]
var toDel:Array = [26,32]
//delete statement text
var baseStr:String = "DELETE FROM mylist WHERE tdId IN (";
var midStr:String = '';
//delete statement parameters: Processing parameter
for( var i = 0; i < toDel.length; i++ ) {
deleteStmt.parameters[i] = toDel[i];
if(midStr.length > 0) { midStr += ' , '; }
midStr += '?';
}
deleteStmt.text = baseStr + midStr + ' )';
//Then execute
So what happens in this case is that u effectively execute...
"DELETE FROM mylist WHERE tdId IN ( :val1 , :val2 )"
In this way you still maintain the safe (good practice) use of parameters, without converting everything to a string.
EDIT: if you dun understand the use of parameter / '?' refer to :
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/data/SQLStatement.html#parameters

If the IN clause does not allow parameters, you can try old-school SQL style: append multiple
" OR (tdId = :param" + paramCounter.toString() + ")"
to the SQL string

Related

mysql query using python 3.6 (string variable is in single quotes)

I am new in python as well as mysql. I am having trouble in populating proper query statement for mysql.
sql = "SELECT * FROM Persons WHERE %s"
cur = db.cursor()
cur.execute(sql,(where,))
where is a string variable which creates a string for WHERE clause; this is the point of question. When I print this variable it give the following result:
Gender = True And IsLate = False
(without any quotes) but when I add this variable to the query to execute it, it adds single quotes around the string.
I used the command
print(cur.statement)
and it prints:
SELECT * FROM Persons WHERE 'Gender = True And IsLate = False'
After supplying parameter, it puts it within single quotes and query returns 0 rows.
I have worked around by concatenating the query statement and variable together and execute the string as query, that worked,
sql = sql + where
cur.execute(sql)
But I know that is not the professional way, as I have searched and found the professional way is to use parameterized query and use variable to store the condition(s) and supplying it at the execution of query.
Looking for advice, am I thinking the right way or otherwise?
The whole point of using parameter substitution in cursor.execute() is that it protects you from SQL injection. Each parameter is treated as a literal value, not substituted into the query and re-interpreted.
If you really want it to be interprted, you need to use string formatting or concatenation, as you discovered. But then you will have to be very careful in validating the input, because the user can supply extra SQL code that you may not have expected, and cause the query to malfunction.
What you should do is build the where string and parameter list dynamically.
where = []
params = []
if gender_supplied:
where.append('gender = %s')
params.append(gender)
if islate_supplied:
where.append*('islate = %s')
params.append(islate)
sql = 'select * from persons'
if where:
query = sql + ' where ' + ' and '.join(where)
else:
query = sql
cur.execute(query, params)

How to use Oracle's JSON_VALUE function with a PreparedStatement

I am trying to run a SQL query using Oracle's json_value() function using a PreparedStatement.
Assume the following table setup:
drop table foo cascade constraints purge;
create table foo
(
id integer primary key,
payload clob,
constraint ensure_json check (payload IS JSON STRICT)
);
insert into foo values (1, '{"data": {"k1": 1, "k2": "foo"}}');
The following SQL query works fine:
select *
from foo
where json_value(payload, '$.data.k1') = '1'
and returns the expected row.
However, when I try to run this query using a PreparedStatement like in the the following piece of code:
String sql =
"select *\n" +
"from foo\n" +
"where json_value(payload, ?) = ?";
PreparedStatement pstmt = conection.prepareStatement(sql);
pstmt.setString(1, "$.data.k1");
pstmt.setString(2, "1");
ResultSet rs = pstmt.executeQuery();
(I removed all error checking from the example to keep it simple)
This results in:
java.sql.SQLException: ORA-40454: path expression not a literal
The culprit is passing the json path value (parameter index 1), the second parameter is no problem.
When I replace (only) the first parameter with a String constant json_value(payload, '$.data.k1') = ? the prepared statement works fine.
In a desperate attempt, I also tried including the single quotes in the parameter: pstmt.setString(1, "'$.data.k1'") but not surprisingly, Oracle wouldn't accept it either (same error message).
I also tried using json_value(payload, concat('$.', ?) ) and only passing "data.k1" as the parameter - same result.
So, the question is:
How can I pass a JSON path expression to Oracle's json_value function using a PreparedStatement parameter?
Any ideas? Is this a bug in the driver or in Oracle? (I couldn't find anything on My Oracle Support)
Or is this simply a case of "not implemented"?
Environment:
I am using Oracle 18.0
I tried the 18.3 and 19.3 version of the ojdbc10.jar driver together with OpenJDK 11.
It isn't the driver - you get the same thing with dynamic SQL:
declare
result foo%rowtype;
begin
execute immediate 'select *
from foo
where json_value(payload, :1) = :2'
into result using '$.data.k1', '1';
dbms_output.put_line(result.payload);
end;
/
ORA-40454: path expression not a literal
ORA-06512: at line 4
And it isn't really a bug, it's documented (emphasis added):
JSON_basic_path_expression
Use this clause to specify a SQL/JSON path expression. The function uses the path expression to evaluate expr and find a scalar JSON value that matches, or satisfies, the path expression. The path expression must be a text literal. See Oracle Database JSON Developer's Guide for the full semantics of JSON_basic_path_expression.
So you would have to embed the path literal, rather than bind it, unfortunately:
declare
result foo%rowtype;
begin
execute immediate 'select *
from foo
where json_value(payload, ''' || '$.data.k1' || ''') = :1'
into result using '1';
dbms_output.put_line(result.payload);
end;
/
1 rows affected
dbms_output:
{"data": {"k1": 1, "k2": "foo"}}
or for your JDBC example (keeping the path as a separate string as you presumably want that to be a variable really):
String sql =
"select *\n" +
"from foo\n" +
"where json_value(payload, '" + "$.data.k1" + "') = ?";
PreparedStatement pstmt = conection.prepareStatement(sql);
pstmt.setString(1, "1");
ResultSet rs = pstmt.executeQuery();
Which obviously isn't what you want to do*, but there doesn't seem to be an alternative. Other than turning your query into a function and passing the path variable in to that, but then the function would have to use dynamic SQL, so the effect is much the same - maybe easier to handle SQL injection concerns that way though.
* and I'm aware you know how to do this the embedded way, and know you want to use bind variables because that's the correct thing to do; I've spelled it out more than you need for other visitors *8-)

Insert query failing when using a parameter in the associated select statement in SQL Server CE

INSERT INTO voucher (voucher_no, account, party_name, rece_amt, particulars, voucher_date, voucher_type, cuid, cdt)
SELECT voucher_rec_no, #account, #party_name, #rece_amt, #particulars, #voucher_date, #voucher_type, #cuid, #cdt
FROM auto_number
WHERE (auto_no = 1)
Error:
A parameter is not allowed in this location. Ensure that the '#' sign is in a valid location or that parameters are valid at all in this SQL statement.
I've just stumbled upon this whilst trying to fix the same issue. I know it's late but, assuming that you're getting this error when attempting to execute the query via .net, ensure that you are setting the SqlCeParameter.DbType - if this is not specified, you get the exception you listed above.
Example (assume cmd is a SqlCeCommand - all the stuff is in the System.Data.SqlServerCe namespace):
SqlCeParameter param = new SqlCeParameter();
param.ParameterName = "#SomeParameterName";
param.Direction = ParameterDirection.Input;
param.DbType = DbType.String; // this is the important bit to avoid the exception
param.Value = kvp.Value;
cmd.Parameters.Add(param);
Obviously, you'd want to set the DB type to match the type of your parameter.

in iOS sqlite getting insertion error for html strings

I am in the requirement of saving the html strings in SQLite Database. While running the insert query, I am getting a syntax error near the style tag of the HTML file.
Here is the code:
-(BOOL)insertAttendees{
sqlite3_stmt *statement;
NSString *insertSQL;
BOOL var=NO;
if (sqlite3_open(dbpath, &db) == SQLITE_OK)
{
//work only for the 1st event
for (int i=0; i<[attendeeCount[0]integerValue];i++)
{
insertSQL = [NSString stringWithFormat:#"INSERT INTO ATTENDEE (A_NAME,A_IMAGE,A_EMAIL,A_PHONE,A_BIO) VALUES (\"%#\",\"%#\", \"%#\",\"%#\",\"%#\")",arrayOf_AName[0][i],arrayOf_AImage[0][i],arrayOf_AEmail[0][i],arrayOf_APhone[0][i],arrayOf_ABio[0][i]];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(db, insert_stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
var=YES;
}
else
{
NSLog(#"sqlite insertion error %s", sqlite3_errmsg(db));
var=NO;
}
sqlite3_finalize(statement);
}
sqlite3_close(db);
return var;
}
return var;
}
There are a whole bunch of issues here:
The root of the problem is that you're building your SQL using stringWithFormat, which you should not do. If your values contained a quotation mark in them (such as might be near your style tag in your HTML), your SQLite code would fail. Instead, you should:
Your SQL should use ? placeholders (note, no quotation marks in the SQL, either):
const char *insert_stmt = "INSERT INTO ATTENDEE (A_NAME,A_IMAGE,A_EMAIL,A_PHONE,A_BIO) VALUES (?,?,?,?,?)";
Then you should then bind values with something like:
if (sqlite3_bind_text(statement, 1, [string UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
NSLog(#"%s: bind column 1 failed: %s", __FUNCTION__, sqlite3_errmsg(db));
}
where string is the NSString value you want to insert, and that second parameter (1, in the above example) is the index of the ? placeholder that you're binding to the text value (where the leftmost placeholder has an index of one).
Only after you've called sqlite3_bind_xxxx() for each of the five ? placeholders, then you can proceed by calling sqlite3_step(), etc.
A second problem is that you are not checking to see if sqlite3_prepare_v2 succeeded or not. This is significant because the meaningful error messages you would have seen if you called sqlite3_errmsg immediately after the prepare statement failed is now lost. You're ignoring any potential prepare error, proceeding with sqlite3_step regardless, and so the meaningful error message will be replaced with one that effectively (but cryptically) says that you called sqlite3_step without first successfully calling sqlite3_prepare_v2.
So, check to make sure if sqlite3_prepare_v2 succeeded, and if it failed, check sqlite3_errmsg immediately before doing any other SQLite calls.
Once you solve the above two issues, you might consider optimizing your code a little. Notably, if you perform a BEGIN TRANSACTION before all of your INSERT statements, and COMMIT TRANSACTION when you're done with all of your inserts, it will be much faster. If you're only inserting a couple of records it might not be observable, but if inserting a lot of records, the performance gain can be staggering.
As yet a further optimization, let's imagine that you addressed my above points (notably, eliminated stringWithFormat for the SQL and used ? placeholders instead) and you had something like the following pseudo code (but obviously checking all of the sqlite3 function return values and handling errors properly):
sqlite3_exec("begin transaction");
for (i = 0; i < whatever; i++) {
sqlite3_prepare(...);
sqlite3_bind(...);
sqlite3_bind(...);
sqlite3_bind(...);
sqlite3_bind(...);
sqlite3_bind(...);
sqlite3_step();
sqlite3_finalize();
}
sqlite3_exec("commit transaction");
Rather than preparing the same SQL many times, you can prepare it once, bind the values, perform the step, and then reset the bindings so you can do it again:
sqlite3_exec("begin transaction");
sqlite3_prepare(...);
for (i = 0; i < whatever; i++) {
sqlite3_bind(...);
sqlite3_bind(...);
sqlite3_bind(...);
sqlite3_bind(...);
sqlite3_bind(...);
sqlite3_step();
sqlite3_reset();
}
sqlite3_finalize();
sqlite3_exec("commit transaction");
Personally, I'd suggest you focus on points 1 and 2 above, and only once you fix the fundamental problem should you contemplate the optimizations of points 3 and 4. Make sure you've got it working before you bother to optimize it.
Finally, I'd be remiss if I didn't point out that you really should contemplate the wonderful third-party FMDB Objective-C wrapper around the SQLite C interface. When you write proper SQLite code, that is binding each value, checking each return code, etc., it gets unwieldy quickly. FMDB greatly simplifies your code.
If you really want to insert HTML in sqlite database then replace all " with \" before executing the query.
(You have't mentioned that whether you are replacing special characters or not).
Suppose, you are doing this..
"SELECT * FROM table WHERE someColume = <div style="width:25px"></div>"
It will fail right after style=" because sqlite will try to execute "SELECT * FROM table WHERE someColume = <div style=",
But if you replace " with \", then your final query will look like this -
"SELECT * FROM table WHERE someColume = <div style=\"width:25px\"></div>"
Good luck.

Prepared statement fetches all the results in db, but not one I ask for

Trying to make my blog secure and learning prepared statements.
Although I set the variable, I still get all the entries from database. $escapedGet is real variable when I print it out. It's obviously a rookie mistake, but I cant seem to find an answer.
I need to get the data where postlink is $escapedGet not all the data.
$escapedGet = mysql_real_escape_string($_GET['article']);
// Create statement object
$stmt = $con->stmt_init();
// Create a prepared statement
if($stmt->prepare("SELECT `title`, `description`, `keywords` FROM `post` WHERE `postlink` = ?")) {
// Bind your variable to replace the ?
$stmt->bind_param('i', $postlink);
// Set your variable
$postlink = $escapedGet;
// Execute query
$stmt->execute();
$stmt->bind_result($articleTitle, $articleDescription, $articleKeywords);
while($stmt->fetch()) {
echo $articleTitle, $articleDescription, $articleKeywords;
}
// Close statement object
$stmt->close();
}
just tryed this: echo $escapedGet;
echo $_Get['artcile']
and got - some_other
thats the same entry that I have saved in database as postlink
tried to shande postlink to id, and then it worked. but why not with postlink tab?
When you are binding your data using 'i' modifier, it gets bound as integer.
Means string will be cast to 0 in the final statement.
But as mysql does type casting, your strings become zeroes in this query:
SELECT title FROM post WHERE postlink = 0;
try it and see - for the textual postlinks you will have all your records returned (as well as a bunch of warnings).
So, bind strings using s modifier, not i