Extending Zend_Db - zend-framework

I apologize if my title is a bit misleading and it turns out that it's some other class under Zend_Db.
I use the following method of extracting data from a MSSQL:
// $_config contains information about how to connect to my MSSQL server
$config = new Zend_Config($_config);
$db = Zend_Db::factory($config->database);
$sql = "SELECT * FROM table1";
print_r($db->fetchAll($sql));
So far no problem and everything runs smooth :).
Now I need to run some more complex queries with multiple rowsets:
$sql2 = <<<EOD
DECLARE #test INT
SET #test = 42
SELECT * FROM table1 WHERE col1 = #test
SELECT col2 FROM table2 UNION
SELECT col3 FROM table2
SELECT * FROM table3
EOD;
print_r($db->fetchAll($sql2));
I hope you get the idea.
Using $db->fetchAll($sql2); will result in
Fatal error: Uncaught exception
'Zend_Db_Statement_Exception' with
message 'SQLSTATE[HY000]: General
error: 10038 Attempt to initiate a new
SQL Server operation with results
pending. [10038] (severity 7)
[(null)]' in
\Sacp026a\sebamweb$\prod\includes\Zend\Db\Statement\Pdo.php:234
The following function will return all the correct rowsets:
function sqlquery_multiple($zdb, $sql) {
$stmt = $zdb->query($sql);
$rowsets = array();
do {
if ($stmt->columnCount() > 0) {
$rowsets[] = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
} while ($stmt->nextRowset());
return $rowsets;
}
print_r(sqlquery_multiple($db, $sql2));
Now my big question is:
How do I extend Zend_Db, so I can implement and use the function above as $db->fetchMulti($sql2); instead of sqlquery_multiple($db, $sql2)?
Thanks in advance :)
NB: It's worth mentioning that I'm using the ODBC-patch in order to be able to fetch multiple rowsets in the first place.

Related

Force Entity Framework to read each line with all details

I am having trouble with en EF method returning duplicate rows of data. When I am running this, in my example, it returns four rows from a database view. The fourth row includes details from the third row.
The same query in SSMS returns four individual rows with the correct details. I have read somewhere about EK and problems with optimization when there are no identity column. But - is there anyway to alter the below code to force EK to read all records with all details?
public List<vs_transactions> GetTransactionList(int cID)
{
using (StagingDataEntities db = new StagingDataEntities())
{
var res = from trans in db.vs_transactions
where trans.CreditID == cID
orderby trans.ActionDate descending
select trans;
return res.ToList();
}
}
Found the solution :) MergeOption.NoTracking
public List<vs_transactions> GetTransactionList(int cID)
{
db.vs_transactions.MergeOption = MergeOption.NoTracking;
using (StagingDataEntities db = new StagingDataEntities())
{
var res = from trans in db.vs_transactions
where trans.CreditID == cID
orderby trans.ActionDate descending
select trans;
return res.ToList();
}
}

Orientdb NoSQL conditionally execute a query

I'm using the OrientDB REST API and am trying to find a way to check for an edge and create it if it does not exist using only one POST request. Multiple queries and commands are fine, just want to minimize the overhead created by back and forth with the server.
I have written a query to check for the edge in OrientDB's built in Tolkien-Arda dataset:
SELECT IF(COUNT(*) FROM
(SELECT FROM Begets
WHERE OUT IN (SELECT FROM Creature WHERE uniquename='rosaBaggins')
AND IN IN (SELECT FROM Creature WHERE uniquename='adalgrimTook')) > 0, "True", "False")
This ugly monstrosity of a query just counts how many edges are going from rosaBaggins to adalgrimTook and returns "true" if it returns more than 0 and false otherwise.
However I'm not sure how to go the next step and execute the CREATE EDGE query if true. Help appreciated with this or with writing my insane query more efficiently, I get the feeling that I've done it the hard way.
If you want you can do that through Java API, this code check if an outgoing edge from rosaBaggins to adalgrimTook exist:
String DB = "<db name>";
String path = "remote:localhost/" + DB;
OServerAdmin serverAdmin;
try
{
serverAdmin = new OServerAdmin(path).connect("<username>", "<password>");
if(serverAdmin.existsDatabase())
{
OrientGraphFactory factory = new OrientGraphFactory(path);
OrientGraph g = factory.getTx();
Iterable<Vertex> result = g.command(new OCommandSQL("SELECT FROM #18:0 WHERE out().uniquename contains 'adalgrimTook'")).execute();
List<Vertex> list = new ArrayList<Vertex>();
CollectionUtils.addAll(list, result.iterator());
if(list.size() == 0)
{
System.out.println("Edge doesn't exist, I'm creating it ...");
g.command(new OCommandSQL("CREATE EDGE connection FROM (SELECT FROM Creature WHERE uniquename = 'rosaBaggins') TO (SELECT FROM Creature WHERE uniquename = 'adalgrimTook')")).execute();
}
else
{
System.out.println("Edge already exist");
}
serverAdmin.close();
}
}
catch(Exception e)
{
e.printStackTrace();
}
Hope it helps
Regards
Since it was not mentioned to be in Java I'll just provide you the pure SQL implementation of this edge Upsert
let $1 = select from user where _id = 'x5mxEBwhMfiLSQHaK';
let $2 = select expand(both('user_story')) from story where _id = '5ab4ddea1908792c6aa06a93';
let $3 = select intersect($1, $2);
if($3.size() > 0) {
return 'already inserted';
}
create edge user_story from (select from user where _id = 'x5mxEBwhMfiLSQHaK') to (select from story where _id = '5ab4ddea1908792c6aa06a93')
return 'just inserted';
I did not use the original code from the tolkien-Arda, but feel free to fill that code in.
The structure consists of a user and a story written by him. If they aren't linked yet an edge (user_story) is created.
Using part of #mitchken 's answer, I've figured it out.
LET $1 = SELECT expand(bothE('Begets')) from Creature where uniquename='asdfasdf';\
LET $2 = SELECT expand(bothE('Begets')) FROM Creature WHERE uniquename='adalgrimTook';\
LET $3 = SELECT INTERSECT($1, $2);\
LET $4 = CREATE EDGE Begets FROM (SELECT FROM Creature WHERE uniquename='asdfasdf') TO (SELECT FROM Creature WHERE uniquename='adalgrimTook');\
SELECT IF($3.INTERSECT.size() > 0, 'Already exists', $4)
Sending this script to the server the first time creates a new edge between 'asdfasdf' (a vertex I just created) and 'adalgrimTook', and returns the #rid of the new edge. The second time I send the script to the server, it returns 'Already exists'.
Also important to note (took me a lot of frustration to figure this out) is that the LET statements will not work in the CLI or Browse tab on the web GUI, but work just fine as a POST script.

Eclipselink ScrollableCursor fails on second next() call

I am trying to use ScrollableCursor for loading all users of the system to memory.
I have a code like this:
Query findUsersQuery
= entityManager.createNamedQuery(UserEntity.QUERY_ALL_USERS, UserEntity.class);
findUsersQuery.setHint(QueryHints.SCROLLABLE_CURSOR, Boolean.TRUE);
findUsersQuery.setHint(QueryHints.CURSOR_PAGE_SIZE, bulkSize);
findUsersQuery.setMaxResults(maxInitialCacheSize);
ScrollableCursor scrollableCursor = (ScrollableCursor) findUsersQuery.getSingleResult();
int leftSize = scrollableCursor.size();
while (scrollableCursor.hasNext()) {
int nextSize = leftSize > bulkSize ? bulkSize : leftSize;
List subscriberPrefs = scrollableCursor.next(nextSize);
leftSize -= nextSize;
//... Result list processing
}
The query is: SELECT s FROM UserEntity u order by u.userId
Size of result table is 100, when scrollableCursor.next(nextSize); called, i get following exception:
org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLRecoverableException: Closed Resultset
Error Code: 17010
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:324)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.cursorRetrieveNextRow(DatabaseAccessor.java:447)[215:org.eclipse.persistence.core:2.4.1.v20121003-ad44345]
at org.eclipse.persistence.queries.ScrollableCursor.retrieveNextObject(ScrollableCursor.java:563)[215:org.eclipse.persistence.core:2.4.1.v20121003-ad44345]
at org.eclipse.persistence.queries.ScrollableCursor.loadNext(ScrollableCursor.java:411)[215:org.eclipse.persistence.core:2.4.1.v20121003-ad44345]
at org.eclipse.persistence.queries.ScrollableCursor.next(ScrollableCursor.java:437)[215:org.eclipse.persistence.core:2.4.1.v20121003-ad44345]
at org.eclipse.persistence.queries.ScrollableCursor.next(ScrollableCursor.java:459)[215:org.eclipse.persistence.core:2.4.1.v20121003-ad44345]
While calling next(10) the first row loaded normally and the exceptions occurs on second row. I don't have an idea why. Can anybody say how i can avoid this error?

Column must appear in the GROUP BY clause or be used in an aggregate function

I'm updating a Qt software, to make it compatible with both SQLite and PostgreSQL.
I have a C++ method that is used to count elements of a given table with given clauses.
In SQLite, the following worked and gave me a number N (the count).
SELECT COUNT(*) FROM table_a
INNER JOIN table_b AS
ON table_b.fk_table_a = table_a.id
WHERE table_a.start_date_time <> 0
ORDER BY table_a.creation_date_time DESC
With PostgreSQL (I'm using 9.3), I have the following error :
ERROR: column "table_a.creation_date_time" must appear in the
GROUP BY clause or be used in an aggregate function
LINE 5: ORDER BY
table_a.creation_date_time DESC
If I add, GROUP BY table_a.creation_date_time, it gives me a table with N rows.
I've read a lot of stuff about how different DBMS allow you to omit columns in the GROUP BY clause. Now, I'm just confused.
For those who are curious, the C++ method is:
static int count(const QString &table, const QString &clauses = QString(""))
{
int success = -1;
if (!table.isEmpty())
{
QString statement = QString("SELECT COUNT(*) FROM ");
statement.append(table);
if (!clauses.isEmpty())
{
statement.append(" ").append(clauses) ;
}
QSqlQuery query;
if(!query.exec(statement))
{
qWarning() << query.lastError();
qWarning() << statement;
}
else
{
if (query.isActive() && query.isSelect() && query.first())
{
bool ok = false;
success = query.value(0).toInt(&ok);
if (ok == false)
{
success = -1;
return success;
}
}
}
}
return success;
}
If you're just doing a count(*) on the table in order to get a single scalar-value result, then surely having the order by present is obsolete ?
solution
Remove the obsolete order by to get "standard" query behavior across multiple dbms

Zend Framework Table Relationships - select from multiple tables within app

I hope I'm asking this question in an understandable way. I've been working on an app that has been dealing with 1 table ( jobschedule ). So, I have models/Jobschedule.php, models/JobscheduleMapper.php, controllers/JobscheduleController.php, view/scripts/jobschedule/*.phtml files
So in my controller I'll do something like this:
$jobnumber = $jobschedule->getJobnum();
$jobtype = $jobschedule->getJobtype();
$table = $this->getDbTable();
public function listAction()
{
$this->_helper->layout->disableLayout();
$this->view->jobnum = $this->getRequest()->getParam( 'jobnum', false );
$this->view->items = array();
$jobschedule = new Application_Model_Jobschedule();
$jobschedule->setJobnum( $this->view->jobnum );
$mapper = new Application_Model_JobscheduleMapper();
$this->view->entries = $mapper->fetchAll ( $jobschedule );
}
and then in my mapper I I do something like:
$resultSet = $table->fetchAll($table->select()->where('jobnum = ?', $jobnumber)->where('jobtype = ?', $jobtype) );
$entries = array();
foreach ($resultSet as $row) {
$entry = new Application_Model_Jobschedule();
$entry->setJobnum($row->jobnum)
->setJobtype($row->jobtype)
->setJobdesc($row->jobdesc)
->setJobstart($row->jobstart)
->setJobend($row->jobend)
->setJobfinished($row->jobfinished)
->setJobnotes($row->jobnotes)
->setJobid($row->jobid);
$entries[] = $entry;
}
return $entries;
}
Then in my view I can manipulate $entries. Well, the problem I'm coming across now is that there is also another table called 'jobindex' that has a column in it called 'jobno'. That 'jobno' column holds the same record as the 'jobnum' column in the 'jobschedule' table. I need to find the value of the 'store_type' column in the 'jobindex' table where jobindex.jobno = joschedule.jobnum ( where 1234 is the jobno/jobnum for example ). Can someone please help me here? Do I need to create a jobindex mapper and controller? If so, that's done ... I just don't know how to manipulate both tables at once and get the record I need. And where to put that code...in my controller?
If I understand you correctly this is the SQL query you need to extract the data from database:
SELECT `jobschedule`.* FROM `jobschedule` INNER JOIN `jobindex` ON jobindex.jobno = jobschedule.jobnum WHERE (jobindex.jobtype = 'WM')
Assembling this SQL query in Zend would look something like this:
$select->from('jobschedule', array('*'))
->joinInner(
'jobindex',
'jobindex.jobno = jobschedule.jobnum',
array())
->where('jobindex.jobtype = ?', $jobtype);
Let us know if that's what you are looking for.
If I'm understanding you correctly, you'll want to join the 'jobindex' table to the 'jobschedule' table.
...
$resultSet = $table->fetchAll(
$table->select()->setIntegrityCheck(false)
->from($table, array('*'))
->joinLeft(
'jobindex',
'jobindex.jobno = jobschedule.jobnumber',
array('store_type'))
->where('jobnum = ?', $jobnumber)
->where('jobtype = ?', $jobtype)
->where('jobindex.store_type = ?', $_POST['store_num'])
);
....
Depending on how 'jobschedule' is related to 'jobindex', you may want an inner join (joinInner()) instead.
The setIntegrityCheck(false) disables referential integrity between the tables, which is only important if you are writing to them. For queries like this one, you can just disable it and move on (else it will throw an exception).