Query Builder giving a parameters bound error - yii

I'm using Yii 1.1.15 and am trying to create a query. but when i do i get a no parameters where bound error This is my code below. From the doc it looks like i'm doing everything right.
$user = Yii::app()->db->createCommand()
->select()
->from('ABC')
->where('id=:id0 AND id=:id1 AND id=:id2', array(':id0'=> '07Q00G', ':id1'=>'07Q01A', ':id2'=>'07Q02A'))
->execute();
CDbCommand failed to execute the SQL statement: SQLSTATE[HY093]: Invalid parameter number: no parameters were bound. The SQL statement executed was: SELECT *
FROM `ABC`
WHERE id=:id0 AND id=:id1 AND id=:id2
also when i used ->query() instead of ->execute() it echo's this. and doesnt replace the variables
CDbDataReader Object ( [_statement:CDbDataReader:private] => PDOStatement Object ( [queryString] => SELECT * FROM `ABC` WHERE id=:id0 AND id=:id1 AND id=:id2 ) [_closed:CDbDataReader:private] => [_row:CDbDataReader:private] => [_index:CDbDataReader:private] => -1 [_e:CComponent:private] => [_m:CComponent:private] => )
Any idea what i'm missing here?

Instead of execute() you should do queryAll()
so It should be
$user = Yii::app()->db->createCommand()
->select()
->from('ABC')
->where('id=:id0 AND id=:id1 AND id=:id2', array(':id0'=> '07Q00G', ':id1'=>'07Q01A', ':id2'=>'07Q02A'))
->queryAll();

Related

How to pass subquery as table name to another query in yii2

I have a query which I am trying to convert into yii2 syntax. Below is the query
SELECT project_id, user_ref_id FROM
(
SELECT `project_id`, `user_ref_id`
FROM `projectsList`
WHERE user_type_ref_id = 1) AS a WHERE user_ref_id = '.yii::$app->user->id;
I am trying to convert it into yii2 format like
$subQuery = (new Query())->select(['p.project_id', 'p.user_ref_id'])->from('projectsList')->where(['user_type_ref_id' => 1]);
$uQuery = (new Query())->select(['p.project_id', 'p.user_ref_id'])->from($subQuery)->where(['user_ref_id ' => yii::$app->user->id])->all();
It is giving an error like
trim() expects parameter 1 to be string, object given
How to I pass subquery as table name to another query
Not tested, but generally this is how it goes. You need to pass the subQuery as a table. So change ->from($subQuery) in the second query to ->from(['subQuery' => $subQuery])
$subQuery = (new Query())->select(['p.project_id', 'p.user_ref_id'])->from('projectsList')->where(['user_type_ref_id' => 1]);
Then
$query = (new Query())->select(['p.project_id', 'p.user_ref_id'])->from(['subQuery' => $subQuery])->where(['subQuery.user_ref_id ' => yii::$app->user->id])->all();

cakephp see the compiled SQL Query before execution

My query gets the timeout error on each run. Its a pagination with joins.
I want to debug the SQL, but since I get a timeout, I can't see it.
How can I see the compiled SQL Query before execution?
Some cake code:
$this -> paginate = array(
'limit' => '16',
'joins' => array( array(
'table' => 'products',
'alias' => 'Product',
'type' => 'LEFT',
'conditions' => array('ProductModel.id = Product.product_model_id')
)),
'fields' => array(
'COUNT(Product.product_model_id) as Counter',
'ProductModel.name'
),
'conditions' => array(
'ProductModel.category_id' => $category_id,
),
'group' => array('ProductModel.id')
);
First off, set the debug variable to 2 in app/config/config.php.
Then add:
<?php echo $this->element('sql_dump');?>
at the end of your layout. This should actually be commented out in your default cake layout.
You will now be able see all SQL queries that go to the database.
Now copy the query and use the SQL EXPLAIN command (link is for MySQL) over the database to see what the query does in the DBMS. For more on CakePHP debugging check here.
Since your script doesn't even render you can try to get the latest log directly from the datasource with:
function getLastQuery()
{
$dbo = $this->getDatasource();
$logs = $dbo->getLog();
$lastLog = end($logs['log']);
return $lastLog['query'];
}
This needs to be in a model since the getDatasource() function is defined in a model.
Inspect the whole $logs variable and see what's in there.
One more thing you can do is ....
Go to Cake/Model/DataSource/DboSource.php and locate function execute() and print $sql variable.
That should print the sql.
This certainly is not be the cleanest way (as you are changing Cake directory) .. but certainly would be quickest just to debug if something is not working with sql.
Try...
function getLastQuery($model) {
$dbo = $model->getDatasource();
$logData = $dbo->getLog();
$getLog = end($logData['log']);
echo $getLog['query'];
}
Simple way to show all executed query of your given model:
$sqllog = $this->ModelName->getDataSource()->getLog(false, false);
debug($sqllog);
class YourController extends AppController {
function testfunc(){
$this->Model->find('all', $options);
echo 'SQL: '.$this->getLastQuery();
}
function getLastQuery()
{
$dbo = ConnectionManager::getDataSource('default');
$logs = $dbo->getLog();
$lastLog = end($logs['log']);
return $lastLog['query'];
}
}
or you can get all the query by adding following line in to the function execute() in lib/Cake/Model/DataSource.php
Debugger::dump($sql);
set the debug variable to 2 in app/config/config.php.
echo $this->Payment->save();
Out put like =>SQL Query: INSERT INTO photoora_photoorange.payments VALUES (*******)
[insert query][2]
set the debug variable to 2 in app/config/config.php.
And

pdo connection error

<?php
$config['db'] = array (
'host' => 'localhost'
'username' => 'root'
'password' => ''
'dbname' => 'phplogin'
);
$db = new PDO("mysql:host={$config['db']['host']};dbname={$config['db']['dbname']}",
$config['db']['username'], $config['db']['password']);
?>
receives error: "Parse error: syntax error, unexpected ''username'' (T_CONSTANT_ENCAPSED_STRING), expecting ')' in C:\webroot\wamp\www\index.php on line 4"
My question is:
Can you highlight or comment on the lines I have to insert my information such as localhost, databasename, table, root, "", etc. Also if you see any changes that need to be made.
When you get errors, you can find the mistake by looking in the error message
The T_CONSTANT_ENCAPSED_STRING parser token error occurs due to an unexpected quote, so all you had to do is look at your code to notice that you don't have commas in the array declaration as stated by Johnny000. You always have to look the error messages and interpret their meaning. That's coding 101 in my opinion.
The error is because you forget to seperate the arrayvalues with ,
Here the right code
<?php
$config['db'] = array (
'host' => 'YOURHOST',
'username' => 'YOURUSERNAME',
'password' => 'YOURPASSWORD',
'dbname' => 'YOURTABLE'
);
$db = new PDO("mysql:host={$config['db']['host']};dbname={$config['db']['dbname']}",
$config['db']['username'], $config['db']['password']);
?>

PDO: Passing extra parameters to a prepared statment than needed

Can you send more parameters than needed to a prepared statement using PDO with no undesired side effects?
That mights seem like a strange question but I ask because I have 4 queries in a row which all use similar and different parameters. The relevant parts of the queries:
1st (select, different table to others):
WHERE threadID = :tid
2nd (select):
WHERE user_ID = :u_ID AND thread_ID = :tid
3rd (update if 2nd was successful):
SET time = :current_time WHERE user_ID = :u_ID AND thread_ID = :tid
4th (insert if 2nd was unsuccessful):
VALUES (:u_ID, :tid, :current_time)
Can I declare one array with the three parameters at the beginning and use it for all 4 queries?
To sort out any confusion, the queries would be executed seperately. It is the parameters variable being reused and so that would mean some queries would receive parameters they don't need. So something like:
$parameters = array(':tid' => $tid, ':u_ID' => $u_ID, ':current_time' => $time);
$1st = $db->prepare($query1);
$1st->execute($parameters);
$2nd = $db->prepare($query2);
$2nd->execute($parameters);
$3rd = $db->prepare($query3);
$3rd->execute($parameters);
$4th = $db->prepare($query4);
$4th->execute($parameters);
If I can, should I? Will this slow down or cause security flaws to my database or scripts?
If I can make this question a bit clearer, please ask.
Thank you!
Perhaps the documentation has been updated since this question was first asked, but now it is quite clearly stated "No"
You cannot bind more values than specified; if more keys exist in input_parameters than in the SQL specified in the PDO::prepare(), then the statement will fail and an error is emitted.
These answers should be useful in filtering out the extra parameters.
I know this is already answered and it's only asking about whether you can send extra params, but I thought people might arrive at this question, and want to know how to get around this limitation. Here's the solution I use:
$parameters = array('tid' => $tid, 'u_ID' => $u_ID, 'current_time' => $time);
$1st = $db->prepare($query1);
$1st->execute(array_intersect_key($parameters, array_flip(array('tid'))));
$2nd = $db->prepare($query2);
$2nd->execute(array_intersect_key($parameters, array_flip(array('u_ID', 'tid'))));
$3rd = $db->prepare($query3);
$3rd->execute(array_intersect_key($parameters, array_flip(array('u_ID', 'tid', 'current_time'))));
$4th = $db->prepare($query4);
$4th->execute(array_intersect_key($parameters, array_flip(array('u_ID', 'tid', 'current_time'))));
That array_interset_key and array_flip maneuver could be extracted to its own function, like:
function filter_fields($params,$field_names) {
return array_intersect_key($params, array_flip($field_names))
}
I just haven't got around to it yet.
The function flips your array of key names, so you have an array with no values, but the right keys. Then intersect filters the first array so you only have the keys that are in both arrays (in this case, only the ones in your array_flipped array). But you get the values for the original array (not the empties). So you make one array of parameters, but specify which params are actually sent to PDO.
So, with the function, you'd do:
$parameters = array('tid' => $tid, 'u_ID' => $u_ID, 'current_time' => $time);
$1st = $db->prepare($query1);
$1st->execute(filter_fields($parameters, array('tid')));
$2nd = $db->prepare($query2);
$2nd->execute(filter_fields($parameters, array('u_ID', 'tid')));
$3rd = $db->prepare($query3);
$3rd->execute(filter_fields($parameters, array('u_ID', 'tid', 'current_time')));
$4th = $db->prepare($query4);
$4th->execute(filter_fields($parameters, array('u_ID', 'tid', 'current_time')));
If you have PHP 5.4, you can use the square bracket array syntax, to make it even cooler:
$parameters = array('tid' => $tid, 'u_ID' => $u_ID, 'current_time' => $time);
$1st = $db->prepare($query1);
$1st->execute(filter_fields($parameters, ['tid']));
$2nd = $db->prepare($query2);
$2nd->execute(filter_fields($parameters, ['u_ID', 'tid']));
$3rd = $db->prepare($query3);
$3rd->execute(filter_fields($parameters, ['u_ID', 'tid', 'current_time']));
$4th = $db->prepare($query4);
$4th->execute(filter_fields($parameters, ['u_ID', 'tid', 'current_time']));
I got a chance to test my question, and the answer is you cannot send more parameters than the query uses. You get the following error:
PDOException Object
(
[message:protected] => SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
[string:Exception:private] =>
[code:protected] => HY093
[file:protected] => C:\Destination\to\file.php
[line:protected] => line number
[trace:Exception:private] => Array
(
[0] => Array
(
[file] => C:\Destination\to\file.php
[line] => line number
[function] => execute
[class] => PDOStatement
[type] => ->
[args] => Array
(
[0] => Array
(
[:u_ID] => 1
[:tid] => 1
[:current_time] => 1353524522
)
)
)
[1] => Array
(
[file] => C:\Destination\to\file.php
[line] => line number
[function] => function name
[class] => class name
[type] => ->
[args] => Array
(
[0] => SELECT
column
FROM
table
WHERE
user_ID = :u_ID AND
thread_ID = :tid
[1] => Array
(
[:u_ID] => 1
[:tid] => 1
[:current_time] => 1353524522
)
)
)
)
[previous:Exception:private] =>
[errorInfo] => Array
(
[0] => HY093
[1] => 0
)
)
I don't know a huge amount about PDO, hence my question, but I think that because :current_time is sent but not used and the error message is "Invalid parameter number: parameter was not defined" you cannot send extra parameters which are not used.
Additionally the error code HY093 is generated. Now I can't seem to find any documentation explaining PDO codes anywhere, however I came across the following two links specifically about HY093:
What is PDO Error HY093
SQLSTATE[HY093]
It seems HY093 is generated when you incorrectly bind parameters. This must be happening here because I am binding too many parameters.
executing different type of multiple queries with one execute leads to problems. you can run multiple selects or multiple updates with one execute. For this case to create different prepared statements objects and pass the the parameters accordingly.
// for WHERE threadID = :tid
$st1 = $db->prepare($sql);
$st1->bindParam(':tid', $tid);
$st1->execute();
or
$st1->execute(array(':tid'=>$tid);
// for WHERE user_ID = :u_ID AND thread_ID = :tid
$st2 = $db->prepare($sql);
$st2->bindParam(':u_ID', $u_ID);
$st2->bindParam(':tid', $tid);
$st2->execute();
or
$st2->execute(array(':tid'=>$tid, ':u_ID' => $u_ID);
// for SET time = :current_time WHERE user_ID = :u_ID AND thread_ID = :tid
$st3 = $db->prepare($sql);
$st3->bindParam(':u_ID', $u_ID);
$st3->bindParam(':tid', $tid);
$st3->bindParam(':current_time', $current_time);
$st3->execute();
or
$st3->execute(array(':tid'=>$tid, ':u_ID' => $u_ID, ':current_time' => $current_time);
// for VALUES (:u_ID, :tid, :current_time)
$st4 = $db->prepare($sql);
$st4->bindParam(':u_ID', $u_ID);
$st4->bindParam(':tid', $tid);
$st4->bindParam(':current_time', $current_time);
$st4->execute();
or
$st4->execute(array(':tid'=>$tid, ':u_ID' => $u_ID, ':current_time' => $current_time);

Yii update with join

I have a code
$command = Yii::app()->db->createCommand()
->update(
'queue q',
array('i.status_id' => $status_id)
)
->join('item i', 'q.item_id = i.item_id')
->where('IN', 'queue_id', $ids);
after I call $command->buildQuery() I get an error:
CDbCommand failed to execute the SQL statement: Invalid parameter number: parameter was not defined. The SQL statement executed was: UPDATE queue q SET i.status_id=:i.status_id
The impression is that it does not see the join and where commands.
What the problem?
Your code is valid with the newest Yii version. This MySQL-specific functionality has been added as of 1.1.14: https://github.com/yiisoft/yii/commit/ed49b77ca059c0895be17df5813ee1e83d4c916d.
The where clause should be in the update() function like this
Yii::app()->db->createCommand()
->update(
'queue q',
array('i.status_id' => $status_id),array('in', 'queue_id', $ids)
);
And regarding the JOIN part there is a open bug at https://github.com/yiisoft/yii/issues/124 (Im not sure. Correct me if Im wrong). Please let me know if there is a workaround.
You have to bind the parameters:
$command = Yii::app()->db->createCommand()
->update(
'queue q',
array('i.status_id' => ':status_id'),
array('in', 'queue_id', $ids),
array(':status_id' => $status_id),
)
->join('item i', 'q.item_id = i.item_id');
Having come across this problem a few times in my projects I have come-up with the following Yii work-around using CDbCriteria which is a little hacky, but gives the security of param count matching.
When applied to your example my code would be (guessing a little bit of your structure):
$ids = array(1,2,3,4,5);
$criteria = new CDbCriteria();
$criteria->addInCondition('i.queue_id',$ids);
$sql = '
UPDATE queue q
JOIN item i
ON q.item_id = i.item_id
SET i.status_id = :status
WHERE '.$criteria->condition;
$command = Yii::app()->db->createCommand($sql);
$command->bindValue('status',$status);
$command->bindValues($criteria->params);
$rows = $command->execute();