How to put a literal "?" in a Mysql query with bind variables - mysql

I have the following query:
select subclasses.id,participants_subclasses.participant_id
from subclasses
left outer join participants_subclasses on
participants_subclasses.participant_id = ?
and subclasses.id = participants_subclasses.subclass_id
where
subclasses.classification_id = ?
and subclasses.showhover
order by subclasses.seq,
IF(LEFT(subclasses.code, 1) = '<',
Extractvalue(subclasses.code, "//texts/text/content"),
subclasses.code)
The above query is processing a table where the code column sometimes has text and sometimes has XML with text inside a tag. The above query works. The side-effect is that a code value cannot start with a "<" which should be acceptable, but the order by would mistake it for XML content. The query below would be more specific and accurate:
select subclasses.id,participants_subclasses.participant_id
from subclasses
left outer join participants_subclasses on
participants_subclasses.participant_id = ?
and subclasses.id = participants_subclasses.subclass_id
where
subclasses.classification_id = ?
and subclasses.showhover
order by subclasses.seq,
IF(LEFT(subclasses.code, 5) = '<?xml',
Extractvalue(subclasses.code, "//texts/text/content"),
subclasses.code)
However this variation checking the XML header in the content fails with a "NameInput Array does not match ?" error in MySQL. It appears that the ? inside <?xml literal is being mistaken for a bind target. And I am passing 2 values to be bound - which again is correct.
So my question is - how do I get the <?xml literal to not be mistaken for a bind value target???

SOLVED
This turns out to be a bug in ADODB interface from phpLens, and NOT in MySQL itself. It exists in current version which is 5.17 for PHP5.

Related

How to remove extra apostrophe

I wrote a SQL query to find the desired output for my project. I was working fine with the correct output. But suddenly it started to give error and in the SQL query, there is some additional apoatrophe in. How to resolve it?
I tried to add the query to $this->db->query(); but still no use.
public function getStudentConut($id) {
$this->db->select('students.id')
->from('students')
->join('bp','students.pbp = bp.id','left')
->where(condition 1)
->where(condition 2);
$query1 = $this->db->get_compiled_select();
$this->db->select('students.id')
->from('students')
->join('bp','students.dbp = bp.id','left')
->where(condition 1)
->where(condition 2);
$query2 = $this->db->get_compiled_select();
$this->db->select('COUNT(id) as stud_count')
->from('('.$query1." UNION ALL ".$query2.') X')
->group_by('X.id');
$results = $this->db->get();
return $results->num_rows();
}
It was giving correct count earlier. But without any new changes, it started to give the error.
Now I get error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.id`` WHERE ``bp.some_value`` IS NULL AND ``students.`schoo' at line 2
SELECT COUNT(id) as stud_count FROM (SELECT students.id`` FROM ``students`` LEFT JOIN ``bp`` ON ``students.pbp`` = ``bp.id`` WHERE ``bp..Some other condition.. UNION ALL SELECT students.idFROMstudentsLEFT JOINbpONstudents.dbp=bp.id..some other condition....) X GROUP BYX.id`
I think the issue (at least with the double `) is that CodeIgniter isn't very good with subqueries and such. Basically every time you get the compiled select statement it already has the escape identifiers and then you are putting it in the from statement at the end which will add additional escape identifiers on top of that.
`->from('('.$query1." UNION ALL ".$query2.') X')`
Unfortunately, unlike other methods like set, from doesn't have a 2nd parameter that allows you to set escaping to false (which is what I think you need).
I suggest trying this:
$this->db->_protect_identifiers = FALSE;
$this->db->select('COUNT(id) as stud_count')
->from('('.$query1." UNION ALL ".$query2.') X')
->group_by('X.id');
$results = $this->db->get();
$this->db->_protect_identifiers = TRUE;
and also look in to this: ->where(condition 2); which I'm pretty sure shouldn't compile due to lack of quotes. You probably don't want this escaped so you can do ->where('condition 2', '', false); as per: https://www.codeigniter.com/user_guide/database/query_builder.html#CI_DB_query_builder::where
When all else fails, just know that CodeIgniter has some limitations with "advanced" queries and that maybe you should write it out manually as a string utilizing $this->db->escape_str(...) for escaping user input vars, and $this->db->query(...) to run the SQL.

ssrs ORA_01008:NOT ALL VALIABLE BOUNDED [duplicate]

I have come across an Oracle problem for which I have so far been unable to find the cause.
The query below works in Oracle SQL developer, but when running in .NET it throws:
ORA-01008: not all variables bound
I've tried:
Changing the Oracle data type for lot_priority (Varchar2 or int32).
Changing the .NET data type for lot_priority (string or int).
One bind variable name is used twice in the query. This is not a problem in my
other queries that use the same bound variable in more than one
location, but just to be sure I tried making the second instance its
own variable with a different :name and binding it separately.
Several different ways of binding the variables (see commented code;
also others).
Moving the bindByName() call around.
Replacing each bound variable with a literal. I've had two separate variables cause the problem (:lot_pri and :lot_priprc). There were some minor changes I can't remember between the two. Changing to literals made the query work, but they do need to work with binding.
Query and code follow. Variable names have been changed to protect the innocent:
SELECT rf.myrow floworder, rf.stage, rf.prss,
rf.pin instnum, rf.prid, r_history.rt, r_history.wt
FROM
(
SELECT sub2.myrow, sub2.stage, sub2.prss, sub2.pin, sub2.prid
FROM (
SELECT sub.myrow, sub.stage, sub.prss, sub.pin,
sub.prid, MAX(sub.target_rn) OVER (ORDER BY sub.myrow) target_row
,sub.hflag
FROM (
WITH floc AS
(
SELECT flow.prss, flow.seq_num
FROM rpf#mydblink flow
WHERE flow.parent_p = :lapp
AND flow.prss IN (
SELECT r_priprc.prss
FROM r_priprc#mydblink r_priprc
WHERE priprc = :lot_priprc
)
AND rownum = 1
)
SELECT row_number() OVER (ORDER BY pp.seq_num, rpf.seq_num) myrow,
rpf.stage, rpf.prss, rpf.pin,
rpf.itype, hflag,
CASE WHEN rpf.itype = 'SpecialValue'
THEN rpf.instruction
ELSE rpf.parent_p
END prid,
CASE WHEN rpf.prss = floc.prss
AND rpf.seq_num = floc.seq_num
THEN row_number() OVER (ORDER BY pp.seq_num, rpf.seq_num)
END target_rn
FROM floc, rpf#mydblink rpf
LEFT OUTER JOIN r_priprc#mydblink pp
ON (pp.prss = rpf.prss)
WHERE pp.priprc = :lot_priprc
ORDER BY pp.seq_num, rpf.seq_num
) sub
) sub2
WHERE sub2.myrow >= sub2.target_row
AND sub2.hflag = 'true'
) rf
LEFT OUTER JOIN r_history#mydblink r_history
ON (r_history.lt = :lt
AND r_history.pri = :lot_pri
AND r_history.stage = rf.stage
AND r_history.curp = rf.prid
)
ORDER BY myrow
public void runMyQuery(string lot_priprc, string lapp, string lt, int lot_pri) {
Dictionary<int, foo> bar = new Dictionary<int, foo>();
using(var con = new OracleConnection(connStr)) {
con.Open();
using(var cmd = new OracleCommand(sql.rtd_get_flow_for_lot, con)) { // Query stored in sql.resx
try {
cmd.BindByName = true;
cmd.Prepare();
cmd.Parameters.Add(new OracleParameter("lapp", OracleDbType.Varchar2)).Value = lapp;
cmd.Parameters.Add(new OracleParameter("lot_priprc", OracleDbType.Varchar2)).Value = lot_priprc;
cmd.Parameters.Add(new OracleParameter("lt", OracleDbType.Varchar2)).Value = lt;
// Also tried OracleDbType.Varchar2 below, and tried passing lot_pri as an integer
cmd.Parameters.Add(new OracleParameter("lot_pri", OracleDbType.Int32)).Value = lot_pri.ToString();
/*********** Also tried the following, more explicit code rather than the 4 lines above: **
OracleParameter param_lapp
= cmd.Parameters.Add(new OracleParameter("lapp", OracleDbType.Varchar2));
OracleParameter param_priprc
= cmd.Parameters.Add(new OracleParameter("lot_priprc", OracleDbType.Varchar2));
OracleParameter param_lt
= cmd.Parameters.Add(new OracleParameter("lt", OracleDbType.Varchar2));
OracleParameter param_lot_pri
= cmd.Parameters.Add(new OracleParameter("lot_pri", OracleDbType.Varchar2));
param_lapp.Value = lastProcedureStackProcedureId;
param_priprc.Value = lotPrimaryProcedure;
param_lt.Value = lotType;
param_lot_pri.Value = lotPriority.ToString();
//***************************************************************/
var reader = cmd.ExecuteReader();
while(reader.Read()) {
// Get values from table (Never reached)
}
}
catch(OracleException e) {
// ORA-01008: not all variables bound
}
}
}
Why is Oracle claiming that not all variables are bound?
I know this is an old question, but it hasn't been correctly addressed, so I'm answering it for others who may run into this problem.
By default Oracle's ODP.net binds variables by position, and treats each position as a new variable.
Treating each copy as a different variable and setting it's value multiple times is a workaround and a pain, as furman87 mentioned, and could lead to bugs, if you are trying to rewrite the query and move things around.
The correct way is to set the BindByName property of OracleCommand to true as below:
var cmd = new OracleCommand(cmdtxt, conn);
cmd.BindByName = true;
You could also create a new class to encapsulate OracleCommand setting the BindByName to true on instantiation, so you don't have to set the value each time. This is discussed in this post
I found how to run the query without error, but I hesitate to call it a "solution" without really understanding the underlying cause.
This more closely resembles the beginning of my actual query:
-- Comment
-- More comment
SELECT rf.flowrow, rf.stage, rf.process,
rf.instr instnum, rf.procedure_id, rtd_history.runtime, rtd_history.waittime
FROM
(
-- Comment at beginning of subquery
-- These two comment lines are the problem
SELECT sub2.flowrow, sub2.stage, sub2.process, sub2.instr, sub2.pid
FROM ( ...
The second set of comments above, at the beginning of the subquery, were the problem. When removed, the query executes. Other comments are fine.
This is not a matter of some rogue or missing newline causing the following line to be commented, because the following line is a SELECT. A missing select would yield a different error than "not all variables bound."
I asked around and found one co-worker who has run into this -- comments causing query failures -- several times.
Does anyone know how this can be the cause? It is my understanding that the very first thing a DBMS would do with comments is see if they contain hints, and if not, remove them during parsing. How can an ordinary comment containing no unusual characters (just letters and a period) cause an error? Bizarre.
You have two references to the :lot_priprc binding variable -- while it should require you to only set the variable's value once and bind it in both places, I've had problems where this didn't work and had to treat each copy as a different variable. A pain, but it worked.
On Charles' comment problem: to make things worse, let
:p1 = 'TRIALDEV'
via a Command Parameter, then execute
select T.table_name as NAME, COALESCE(C.comments, '===') as DESCRIPTION
from all_all_tables T
Inner Join all_tab_comments C on T.owner = C.owner and T.table_name = C.table_name
where Upper(T.owner)=:p1
order by T.table_name
558 line(s) affected. Processing time: 00:00:00.6535711
and when changing the literal string from === to ---
select T.table_name as NAME, COALESCE(C.comments, '---') as DESCRIPTION
[...from...same-as-above...]
ORA-01008: not all variables bound
Both statements execute fine in SQL Developer. The shortened code:
Using con = New OracleConnection(cs)
con.Open()
Using cmd = con.CreateCommand()
cmd.CommandText = cmdText
cmd.Parameters.Add(pn, OracleDbType.NVarchar2, 250).Value = p
Dim tbl = New DataTable
Dim da = New OracleDataAdapter(cmd)
da.Fill(tbl)
Return tbl
End Using
End Using
using Oracle.ManagedDataAccess.dll Version 4.121.2.0 with the default settings in VS2015 on the .Net 4.61 platform.
So somewhere in the call chain, there might be a parser that is a bit too aggressively looking for one-line-comments started by -- in the commandText. But even if this would be true, the error message "not all variables bound" is at least misleading.
The solution in my situation was similar answer to Charles Burns; and the problem was related to SQL code comments.
I was building (or updating, rather) an already-functioning SSRS report with Oracle datasource. I added some more parameters to the report, tested it in Visual Studio, it works great, so I deployed it to the report server, and then when the report is executed the report on the server I got the error message:
"ORA-01008: not all variables bound"
I tried quite a few different things (TNSNames.ora file installed on the server, Removed single line comments, Validate dataset query mapping). What it came down to was I had to remove a comment block directly after the WHERE keyword. The error message was resolved after moving the comment block after the WHERE CLAUSE conditions. I have other comments in the code also. It was just the one after the WHERE keyword causing the error.
SQL with error: "ORA-01008: not all variables bound"...
WHERE
/*
OHH.SHIP_DATE BETWEEN TO_DATE('10/1/2018', 'MM/DD/YYYY') AND TO_DATE('10/31/2018', 'MM/DD/YYYY')
AND OHH.STATUS_CODE<>'DL'
AND OHH.BILL_COMP_CODE=100
AND OHH.MASTER_ORDER_NBR IS NULL
*/
OHH.SHIP_DATE BETWEEN :paramStartDate AND :paramEndDate
AND OHH.STATUS_CODE<>'DL'
AND OHH.BILL_COMP_CODE IN (:paramCompany)
AND LOAD.DEPART_FROM_WHSE_CODE IN (:paramWarehouse)
AND OHH.MASTER_ORDER_NBR IS NULL
AND LOAD.CLASS_CODE IN (:paramClassCode)
AND CUST.CUST_CODE || '-' || CUST.CUST_SHIPTO_CODE IN (:paramShipto)
SQL executes successfully on the report server...
WHERE
OHH.SHIP_DATE BETWEEN :paramStartDate AND :paramEndDate
AND OHH.STATUS_CODE<>'DL'
AND OHH.BILL_COMP_CODE IN (:paramCompany)
AND LOAD.DEPART_FROM_WHSE_CODE IN (:paramWarehouse)
AND OHH.MASTER_ORDER_NBR IS NULL
AND LOAD.CLASS_CODE IN (:paramClassCode)
AND CUST.CUST_CODE || '-' || CUST.CUST_SHIPTO_CODE IN (:paramShipto)
/*
OHH.SHIP_DATE BETWEEN TO_DATE('10/1/2018', 'MM/DD/YYYY') AND TO_DATE('10/31/2018', 'MM/DD/YYYY')
AND OHH.STATUS_CODE<>'DL'
AND OHH.BILL_COMP_CODE=100
AND OHH.MASTER_ORDER_NBR IS NULL
*/
Here is what the dataset parameter mapping screen looks like.
It's a bug in Managed ODP.net - 'Bug 21113901 : MANAGED ODP.NET RAISE ORA-1008 USING SINGLE QUOTED CONST + BIND VAR IN SELECT' fixed in patch 23530387 superseded by patch 24591642
Came here looking for help as got same error running a statement listed below while going through a Udemy course:
INSERT INTO departments (department_id, department_name)
values( &dpet_id, '&dname');
I'd been able to run statements with substitution variables before. Comment by Charles Burns about possibility of server reaching some threshold while recreating the variables prompted me to log out and restart the SQL Developer. The statement ran fine after logging back in.
Thought I'd share for anyone else venturing here with a limited scope issue as mine.
I'd a similar problem in a legacy application, but de "--" was string parameter.
Ex.:
Dim cmd As New OracleCommand("INSERT INTO USER (name, address, photo) VALUES ('User1', '--', :photo)", oracleConnection)
Dim fs As IO.FileStream = New IO.FileStream("c:\img.jpg", IO.FileMode.Open)
Dim br As New IO.BinaryReader(fs)
cmd.Parameters.Add(New OracleParameter("photo", OracleDbType.Blob)).Value = br.ReadBytes(fs.Length)
cmd.ExecuteNonQuery() 'here throws ORA-01008
Changing address parameter value '--' to '00' or other thing, works.

Codeigniter sql binding

How do I use Codeigniter SQL Binding if there are two target dates?
Is how I did it below correct?
public function getInvestmentForBorrowing($id, $Interest, $Currency, $Loantime, $target_date, $Risk_category)
{
$query = '
select CASE WHEN (a.amount_financed - a.amount_invested - a.amount_withdrawn) < a.amount_per_borrower
THEN round((a.amount_financed - a.amount_invested - a.amount_withdrawn), 2)
ELSE round((a.amount_per_borrower) , 2)
END AS investable_amount, a.*,
c.IBAN as Return_IBAN, c.BIC as Return_BIC,
i.average_rate
from investment a
inner join userinfo c
on a.Owner = c.Owner and
c.UPDATE_DT is null
inner join exchange_rates i
on a.Currency = i.currency_id and
? between i.effective_dt and i.expiration_dt
where a.ORIG_ID = ? and
a.Interest <= ? and
a.Currency = ? and
a.status = 2 and
a.Loantime >= ? and
a.Available >= ? and
a.Risk <= ? and
a.UPDATE_DT is null
having investable_amount > 0';
$query = $this->db->query($query, array($target_date, $id ,$Interest, $Currency, $Loantime ,$target_date ,$Risk_category));
$result = $query->result();
return $result;
}
Write now the question marks just represent the array so I added two $target_date to the array but not sure if thats the right way to do it.
It appears to be ok according to the codeigniter documentation but i say that without regard to your original SQL being correct or not.
Just make sure that the number of ? match the number of values you are providing and they are in the right order.
One way to sanity check it, apart from just running it, is to place the following command right after you perform the query:
echo $this->db->last_query();
And providing it known data, you can cheat and just hard code some dummy values for testing, take the generated SQL and throw that into something like phpmyadmin and run it the generated SQL against the Database and see if it works with the expected results.
Just a side note regarding your variable naming style. I see you are mixing cases i.e. things like $target_date (all lower case) and $Risk_category (First letter uppercase). Just be aware that on a linux based system case does matter and mixing like that can cause errors. It's a good idea to decide on one and stick with it.

Flask - Convert request.args to dict

I've been trying to figure out how to pass the request.args to sqlalchemy filter.
I thought this should work:
model.query.filter(**request.args).all()
But it's throwing the error:
TypeError: <lambda>() got an unexpected keyword argument 'userid'
When userid or any other get arg is present.
According to this post - https://stackoverflow.com/questions/19506105/flask-sqlalchemy-query-with-keyword-as-variable - you can pass a dict to the filter function.
Any ideas what I'm doing wrong?
Many thanks :)
UPDATE: Many thanks to the poster below, however now it's throwing the following error:
ProgrammingError: (ProgrammingError) (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') ORDER BY tblclients.clientname' at line 3") 'SELECT favourites.id AS favourites_id, favourites.userid AS favourites_userid, favourites.clientid AS favourites_clientid, favourites.last_visit AS favourites_last_visit \nFROM favourites INNER JOIN tblclients ON tblclients.clientid = favourites.clientid \nWHERE favourites.userid = %s ORDER BY tblclients.clientname' ([u'41'],)
Any ideas?
First, you have to use filter_by, not filter.
Second, Flask request.args uses a MultiDict, a dict with the values inside a list, allowing more than one value for the same key, because the same field can appear more than once in a querystring. You got the error because the SQL query got the [u'41'] when it expected only '41'. You can use request.args.to_dict() to fix that:
model.query.filter_by(**request.args.to_dict()).all()
Use filter_by:
model.query.filter_by(**request.args).all()
filter is used like this: query.filter(Class.property == value) while filter_by is used like this: query.filter_by(property=value) (the first one being an expression and the latter one being a keyword argument).
filter_by(**request.args) doesn't work well if you have non-model query parameters, like page for pagination, otherwise you get errors like these:
InvalidRequestError: Entity '<class 'flask_sqlalchemy.JobSerializable'>' has no property 'page'
I use something like this which ignores query parameters not in the model:
builder = MyModel.query
for key in request.args:
if hasattr(MyModel, key):
vals = request.args.getlist(key) # one or many
builder = builder.filter(getattr(MyModel, key).in_(vals))
if not 'page' in request.args:
resources = builder.all()
else:
resources = builder.paginate(
int(request.args['page'])).items
Considering a model with a column called valid, something like this will work:
curl -XGET "http://0.0.0.0/mymodel_endpoint?page=1&valid=2&invalid=whatever&valid=1"
invalid will be ignored, and page is available for pagination and best of all, the following SQL will be generated: WHERE mymodel.valid in (1,2)
(get the above snippet for free if you use this boilerplate-saving module)
You can:
http://localhost:5000/filter-test?var=test
query_dict = request.args.to_dict()
print(query_dict)
{'var': 'test'}
print(query_dict['var'])
var

ActiveRecord + SQLite 3 behaves strangely

Using activerecord I made this query
AdImage.select("ad_images.id, ad_images.locale_id, ad_campaigns.click_url,
ad_campaigns.default_ad_image_id").joins("left outer join ad_campaigns on
ad_campaigns.id = ad_images.ad_campaign_id").where("ad_images.ad_campaign_id" => 1)
which generates the following sql query:
SELECT ad_images.id, ad_images.locale_id, ad_campaigns.click_url,
ad_campaigns.default_ad_image_id FROM "ad_images" left outer join ad_campaigns on
ad_campaigns.id = ad_images.ad_campaign_id WHERE "ad_images"."ad_campaign_id" = 1
and the result is the following:
=> [#<AdImage id: 22, click_url: "market://details?id=com.mobiata.flighttrack",
locale_id: 2>]
which is wrong.
So I used ActiveRecord::Base.connection.execute method to directly run the sql query:
ActiveRecord::Base.connection.execute("SELECT ad_campaigns.click_url, ad_images.id,
ad_images.locale_id, ad_campaigns.default_ad_image_id FROM ad_campaigns inner join
ad_images on ad_campaigns.id = ad_images.ad_campaign_id WHERE ad_images.ad_campaign_id = 1")
which returns the following:
[{"click_url"=>"market://details?id=com.mobiata.flighttrack", "id"=>22, "locale_id"=>2,
"default_ad_image_id"=>22, 0=>"market://details?id=com.mobiata.flighttrack", 1=>22,
2=>2, 3=>22}]
which has the strange repetition in it.
The only difference between the first and the second is "ad_images" vs ad_images in the table names.
My questions are:
1) I don't understand what makes this difference.
2) Why does the second query returns the garbage in SQLite3 while it doesn't happen in MySQL server?
I ended up with using "ActiveRecord::Base.connection.execute" instead of using Rails' ActiveRecord helpers. There doesn't seem to be other solutions to it.
It turns out that you should use the index values instead of double quoted column names when you call values. Otherwise you will bump into Type errors when used in production with MySQL.