Help With Zend_Db_Stmt - zend-framework

I have a little problem with the Zend_Db_Stmt. This works:
$sql = " SELECT * FROM bugs";
$stmt = $this->_getDb()->query($sql);
return $stmt->fetchAll();
But I am trying to make sure the PDO gets used to query the database so I tried this:
$sql = "SELECT * FROM bugs";
$stmt = new Zend_Db_Statement_Pdo($this->_getDb(), $sql);
return $stmt->fetchAll();
And this doesn't work (it returns an empty array). Could you please help me figure this out? The above code works if I use execute() method for UPDATE or INSERT queries but fetchAll() doesn't work.

You need to execute!
$stmt->execute();
return $stmt->fetchAll();
See more examples in the PHP manual.

Related

Aggregate Functions in extbase typo3

I am using extbase-query-method ( like , in ,contains ).
$query = $this->createQuery();
$query->matching(
$query->logicalAnd(
$query->equals("deleted", "0"),
$query->equals("hidden", "0"),
$query->equals("status", $status)
)
);
return $query->execute();
but how can i used Aggregate Functions in extbase query statement.
As far as I know, Extbase doesn't support the use of aggregate functions in the ORM. See more here: https://docs.typo3.org/typo3cms/ExtbaseFluidBook/6-Persistence/3-implement-individual-database-queries.html
You will have to build the SQL query yourself (in the statement) and to tell the query to return raw result (that is stored in an array) instead of returning an object based query.
Exemple:
$query = $this->createQuery();
$query->statement("SELECT AVG(clicks) as 'avg' FROM tablename ...");
$query->getQuerySettings()->setReturnRawQueryResult(TRUE);
$result = $query->execute()[0][avg];
Cheers,
Olivier
I think the only solution for Extbase Query is
$query->statement('SELECT AVG(clicks) FROM tablename ...')
Or not?
If you use Plain SQL Statements, you have can get problems with sql injection!
A better way should be using the new doctrine querybuilder which is since 8.7 available:
// SELECT COUNT(`uid`) FROM `tt_content` WHERE (`bodytext` = 'klaus')
// AND ((`tt_content`.`deleted` = 0) AND (`tt_content`.`hidden` = 0)
// AND (`tt_content`.`starttime` <= 1475580240)
// AND ((`tt_content`.`endtime` = 0) OR (`tt_content`.`endtime` > 1475580240)))
$count = $queryBuilder
->count('uid')
->from('tt_content')
->where(
$queryBuilder->expr()->eq('bodytext', $queryBuilder->createNamedParameter('klaus'))
)
->execute()
->fetchColumn(0);
https://docs.typo3.org/typo3cms/CoreApiReference/latest/ApiOverview/Database/QueryBuilder/Index.html
As others have pointed out, you cannot use these functions on the Query object itself. However, you could use the ExpressionBuilder class for something like this:
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Database\ConnectionPool;
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('my_awesome_table');
$statement = $queryBuilder
->select('uid')
->addSelectLiteral(
$queryBuilder->expr()->max('interesting_field', 'awesome_alias')
)
->from('my_awesome_table')
->groupBy('interesting_field')
->execute();
Note that this returns a QueryResult object.
The only function you can use is COUNT() with
return $query->execute()->count();
For all other functions you have to do a native query, like described in other answers

zf2 When I do addFeature(new Feature\SequenceFeature,...) for Postgres PDO, insert fails because columns and values are nulled out

I'm in Zend Framework 2, trying to get the last inserted id after inserting using postgresql PDO. The insert works fine unless I add a SequenceFeature, like this:
class LogTable extends AbstractTableGateway
{
protected $table = 'log';
public function __construct(Adapter $adapter)
{
$this->adapter = $adapter;
$this->featureSet = new Feature\FeatureSet();
$this->featureSet->addFeature(new Feature\SequenceFeature('id','log_id_seq'));
$this->resultSetPrototype = new ResultSet();
$this->resultSetPrototype->setArrayObjectPrototype(new Log());
print_r($this->getFeatureSet());
$this->initialize();
}
When I later do an insert like this:
$this->insert($data);
It fails, because INSERT INTO "log" () VALUES (), so for some reason zf2 is nulling out the columns and values to insert, but only if I add that SequenceFeature.
If I don't add that feature, the insert works fine, but I can't get the last sequence value. Debugging the Zend/Db/Sql/Insert.php, I found that the values function is accessed twice with the SequenceFeature in there, but only once when it's not in there. For some reason when the SequenceFeature is there, all the insert columns and values are nulled out, possibly because of this double call? I haven't investigated further yet, but maybe it's updating the sequence and then losing the data when making the insert?
Is this a bug, or is there just something I'm missing?
Screw it! We'll do it live!
Definitely not the best solution, but this works. I just cut and pasted the appropriate code from Zend/Db/TableGateway/Feature/SequenceFeature.php and added it as a function to my LogTable class:
public function nextSequenceId()
{
$sql = "SELECT NEXTVAL('log_id_seq')";
$statement = $this->adapter->createStatement();
$statement->prepare($sql);
$result = $statement->execute();
$sequence = $result->getResource()->fetch(\PDO::FETCH_ASSOC);
return $sequence['nextval'];
}
Then I called it before my insert in my LogController class:
$data['id'] = $this->nextSequenceId();
$id = $this->insert($data);
Et voila! Hopefully someone else will explain to me how I'm really supposed to do it, but this will work just fine in the interim.

It is possible to execute MySQLi prepared statement before the other one is closed?

Lets say I have a prepared statement. The query that it prepares doesn't matter. I fetch the result like above (I can't show actual code, as it is something I don't want to show off. Please concentrate on the problem, not the examples meaningless) and I get
Fatal error: Call to a member function bind_param() on a non-object in... error. The error caused in the called object.
<?php
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
class table2Info{
private $mysqli;
public function __construct($_mysqli){
$this->mysqli = $_mysqli;
}
public function getInfo($id)
{
$db = $this->mysqli->prepare('SELECT info FROM table2 WHERE id = ? LIMIT 1');
$db->bind_param('i',$db_id);
$db_id = $id;
$db->bind_result($info);
$db->execute();
$db->fetch();
$db->close();
return $info;
}
}
$t2I = new table2Info($mysqli);
$stmt->prepare('SELECT id FROM table1 WHERE name = ?');
$stmt->bind_param('s',$name);
$name = $_GET['name'];
$stmt->bind_result($id);
$stmt->execute();
while($stmt->fetch())
{
//This will cause the fatal-error
echo $t2I->getInfo($id);
}
$stmt->close();
?>
The question is: is there a way to do another prepared statement while another one is still open? It would simplify the code for me. I can't solve this with SQL JOIN or something like that, it must be this way. Now I collect the fetched data in an array and loop through it after $stmt->close(); but that just isn't good solution. Why should I do two loops when one is better?
From the error you're getting it appears that your statement preparation failed. mysqli::prepare returns a MySQLi_STMT object or false on failure.
Check for the return value from your statement preparation that is causing the error. If it is false you can see more details by looking at mysqli::error.

zend framework 1.11.5 is choking on search function - mysql db

ZF 1.11.5 is puking all over this search function. i've tried creating the query several different ways, sent the sql statement to my view, copied and pasted the sql statement into phpMyAdmin and successfully retrieved records using the sql that ZF is choking on. i have been getting a coupld of different errors: 1) an odd SQL error about 'ordinality' (from my Googling ... it seems this is a ZF hang up .. maybe?) and 2) Fatal error: Call to undefined method Application_Model_DbTable_Blah::query() in /blah/blah/blah.php on line blah
public function searchAction($page=1)
{
$searchForm = new Application_Model_FormIndexSearch();
$this->view->searchForm = $searchForm;
$this->view->postValid = '<p>Enter keywords to search the course listings</p>';
$searchTerm = trim( $this->_request->getPost('keywords') );
$searchDb = new Application_Model_DbTable_Ceres();
$selectSql = "SELECT * FROM listings WHERE `s_coursedesc` LIKE '%".$searchTerm."%' || `s_title` LIKE '%".$searchTerm."%'";
$selectQuery = $searchDb->query($selectSql);
$searchResults = $selectQuery->fetchAll();
}
here's my model ....
class Application_Model_DbTable_Ceres extends Zend_Db_Table_Abstract
{
protected $_name = 'listings';
function getCourse( $courseId )
{
$courseid = (int)$courseId;
$row = $this->fetchRow('id=?',$courseId);
if (!$row)
throw new Exception('That course id was not found');
return $row->toArray();
}
}
never mind the view file ... that never throws an error. on a side note: i'm seriously considering kicking ZF to the curb and using CodeIgniter instead.
looking forward to reading your thoughts. thanks ( in advance ) for your responses
You're trying to all a method called query() on Zend_Db_Table but no such method exists. Since you have built the SQL already you might find it easier to call the query on the DB adapter directly, so:
$selectSql = "SELECT * FROM listings WHERE `s_coursedesc` LIKE '%".$searchTerm."%' || `s_title` LIKE '%".$searchTerm."%'";
$searchResults = $selectQuery->getAdapter()->fetchAll($selectSql);
but note that this will give you arrays of data in the result instead of objects which you might be expecting. You also need to escape $searchTerm here since you are getting that value directly from POST data.
Alternatively, you could form the query programatically, something like:
$searchTerm = '%'.$searchTerm.'%';
$select = $selectQuery->select();
$select->where('s_coursedesc LIKE ?', $searchTerm)
->orWhere('s_title LIKE ?', $searchTerm);
$searchResults = $searchQuery->fetchAll($select);

Can I tell if an ado.net DbCommand is a query or not (before executing it)

I am trying to write a Powershell script to run a general SQL command against a database. The idea is that Run-SQL "select ..." will run the SQL text against the currently open database. If the SQL statement is a query, it should return a DataTable. If it is a non-query (DDL or DML) it should return nothing ($null).
In order to do this, I need to know which method (ExecuteReader or ExecuteNonQuery) to execute against the command. Is there a way to determine this? (I'm happy to prepare the command if that helps).
As an alternative, I can add a -query argument to be supplied by the user, which distinguishes the two cases, but as a potential user, I'd find this annoying (as, in my view, I have already said whether it's a query by the SQL I used, why say again?)
My key use is for Oracle databases, so an Oracle-specific answer is OK with me, although I'd prefer something generic.
I think you could just use ExecuteReader whether it's a query or not. It may be overkill but in some quick experiments with doing an UPDATE ($reader returns nothing) and a COUNT ($reader[0] outputs scalar result) - it just seems to work.
$connstr = "server=.\SQLEXPRESS;Database=AdventureWorks;" +
"Integrated Security=true;Persist Security Info=False"
$conn = new-object System.Data.SqlClient.SqlConnection $connstr
#$query = "UPDATE Production.Product SET Name = 'ACME' WHERE Name = 'Blade'"
$query = "SELECT Count(*) FROM Production.Product"
$cmd = new-object System.Data.SqlClient.SqlCommand $query,$conn
$conn.Open()
try
{
$reader = $cmd.ExecuteReader()
while ($reader.Read())
{
$reader[0]
}
}
finally
{
$conn.Dispose()
}
As an alternative to what Keith said you could try
$sql = 'Select count(1) From SomeTable;'
$sql = $sql.TrimStart(' ')
if ($sql -match "^select") { Write-Host 'ExecuteReader' }
else { Write-Host 'ExecuteNonQuery'}
The trim is there in case the SQL command has a leading space since $sql = ' select ' won't match "^select"