perl dbi rollback not working - sql

i am using this approach. If there is an error in the sql, rollback only happens for the first id of the asset_group. Rest of the ids are ignored. Am i doing it the right way?
my $sql = "sql batch that update and insert depending on the condition";
$dbh->{RaiseError} = 1;
$dbh->{PrintError} = 0;
$dbh->{AutoCommit} = 0;
my $sth = $dbh->prepare($sql);
my #error = ();
my $num = 0;
foreach my $id (#asset_group) {
next if ($id eq '');
eval {
$sth->bind_param(1, $id);
$sth->bind_param(2, $vars{'other_id'});
$sth->execute();
};
if ($#) {
$dbh->rollback();
push #error, $#
} else {
$dbh->commit();
}
}

Depending on the database, you may need to issue a begin work before you start changing things. I seem to remember Informix requiring one.
Also, it looks like you are issuing a commit or a rollback after each execute. Once you commit, you can't rollback. Normally one says something like
$dbh->begin_work;
eval {
for my $id (#asset_group) {
next if ($id eq '');
$sth->execute($id, $vars{other_id});
}
1; #if it doesn't die then this will force it to return true
} or do {
my $error = DBI->errstr;
$dbh->rollback();
die "could not insert rows: $error\n"
};
$dbh->commit();
Note how I don't use $#. $# is untrustworthy.

Related

it is correct for a transaction?

I create a mysql transaction using pdo.
Please check my code is perfect or not. if its not correct then how i can set transaction correctly.
Do i need to use try block? how can i sort try block in this querys
if(is_null($this->pdo)){
return false;
} else {
$pdo = $this->pdo;
$pdo->beginTransaction();
$stmt = $pdo->prepare("SELECT mallu FROM users WHERE id=? LOCK IN SHARE MODE");
$stmt->execute([$alpharef]);
$reseller = $stmt->fetch();
$stmt = null;
$stmt = $pdo->prepare("UPDATE users SET mallu = mallu - :cost WHERE id=:userid");
$stmt->bindParam(':cost', $cost, PDO::PARAM_STR);
$stmt->bindParam(':userid', $alpharef, PDO::PARAM_INT);
if (stmt->execute() != true) {
$conn->rollBack();
return false
}
$stmt = null;
$dates = date("d-m-Y");
$statos = 0;
$stmt = $pdo->prepare("INSERT INTO request (rtyp, num, amount, cost, typ, usr, refid, tm, dates, status) VALUES (:rtyp, :num, :amount, :cost, :typ, :usr, :refid, NOW(), :dates, :status)");
$stmt->bindParam(':rtyp', $retyp, PDO::PARAM_STR);
............................................................
if (stmt->execute() != true) {
$conn->rollBack();
return false
}
$stmt = null;
$pdo->commit();
$this->msg = 'Request sent successfully';
return true;
}
$pdo = null;
Look at this pseudo-code. Try + catch helps you to handle failed transaction. All you have to do is to throw new exception when one of your sql's fail.
$pdo->beginTransaction();
try{
//DB_operation1
if (result==false){ throw new Exception("...message1...");}
//DB_operation2
if (result==false){ throw new Exception("...message2...");}
$pdo->commit();
}catch(exception $e){
$pdo->rollBack();
//do something with thrown message
}

Foreach PHP Loop into Array

I am trying to create an array containing results from an SQL table. But my foreach loop does not appear to be function correctly.
Here is my code:
$stmt->bind_param("i", $id);
$stmt->execute();
while ($stmt->fetch()) {
}
$stmt->close();
$i = 0;
foreach ($connected_items as &$value) {
print_r ($connected_items[$i]);
$stmt->bind_param("i", $connected_items[$i]);
$stmt->execute();
while ($stmt->fetch()) {
$result[] = array(,
);
}
$stmt->close();
$i++;
}
unset($value);
)
)
It appears to be running the for loop on my print statement and then MySQL statement, using the last connected_items_id, why is that? And why is it not returning the associated values for that id?
remove this [] at line number 6:
while ($stmt->fetch()) {
$connected_items = array($connected_items_id);
}
instead of this:
while ($stmt->fetch()) {
$connected_items[] = array($connected_items_id);
}
Try this,
"connected_item_id" => $connected_items[0],
instead of
"connected_item_id" => $connected_items_id,
Try
foreach ($connected_items as $value) {
......................
......................
$stmt = $this->db->prepare('SELECT name, serial FROM `glpi_monitors` WHERE id =?');
$stmt->bind_param("i", $value[0]);
................................
................................
}
Also you can use IN keyword instead of looping and querying each time.
$sql = "SELECT name, serial FROM `glpi_monitors` WHERE id IN('".implode("','",$connected_items)."'");
$stmt = $this->db->prepare($sql);
eg :

Get raw sql from Phalcon query builder

Is it possible to extract raw sql query from the query builder instance in Phalcon? Something like this?
$queryBuilder = new Phalcon\Mvc\Model\Query\Builder();
$queryBuilder
->from(…)
->where(…);
$rawSql = $queryBuilder->hypotheticalGetRawQueryMethod();
By error and trial the below seems to working. Would be great if someone could confirm if there's a better way.
$queryBuilder = new Builder();
$queryBuilder->from(…)->where(…);
$intermediate = $queryBuilder->getQuery()->parse();
$dialect = DI::getDefault()->get('db')->getDialect();
$sql = $dialect->select($intermediate);
Edit: As of 2.0.3 you can do it super simple, see comment for full details:
$modelsManager->createBuilder()
->from('Some\Robots')
->getQuery()
->getSql()
you can use getRealSqlStatement() (or similar function name) on the DbAdapter. See http://docs.phalconphp.com/en/latest/api/Phalcon_Db_Adapter.html
According to documentation you can get this way the resulting sql query.
Or wait, this might not work on querybuilder. Otherwise you can setup low level query logging: http://docs.phalconphp.com/en/latest/reference/models.html#logging-low-level-sql-statements
$db = Phalcon\DI::getDefault()->getDb();
$sql = $db->getSQLStatement();
$vars = $db->getSQLVariables();
if ($vars) {
$keys = array();
$values = array();
foreach ($vars as $placeHolder=>$var) {
// fill array of placeholders
if (is_string($placeHolder)) {
$keys[] = '/:'.ltrim($placeHolder, ':').'/';
} else {
$keys[] = '/[?]/';
}
// fill array of values
// It makes sense to use RawValue only in INSERT and UPDATE queries and only as values
// in all other cases it will be inserted as a quoted string
if ((strpos($sql, 'INSERT') === 0 || strpos($sql, 'UPDATE') === 0) && $var instanceof \Phalcon\Db\RawValue) {
$var = $var->getValue();
} elseif (is_null($var)) {
$var = 'NULL';
} elseif (is_numeric($var)) {
$var = $var;
} else {
$var = '"'.$var.'"';
}
$values[] = $var;
}
$sql = preg_replace($keys, $values, $sql, 1);
}
More you can read there
The following is the common solution:
$result = $modelsManager->createBuilder()
->from(Foo::class)
->where('slug = :bar:', ['bar' => "some-slug"])
->getQuery()
->getSql();
But you might not expect to see the query without its values, like in:
die(print_r($result, true));
Array
(
[sql] => SELECT `foo`.`id`, `foo`.`slug` FROM `foo` WHERE `foo`.`slug` = :bar
[bind] => Array
(
[bar] => some-slug
)
[bindTypes] =>
)
So, this simple code might be useful:
public static function toSql(\Phalcon\Mvc\Model\Query\BuilderInterface $builder) : string
{
$data = $builder->getQuery()->getSql();
['sql' => $sql, 'bind' => $binds, 'bindTypes' => $bindTypes] = $data;
$finalSql = $sql;
foreach ($binds as $name => $value) {
$formattedValue = $value;
if (\is_object($value)) {
$formattedValue = (string)$value;
}
if (\is_string($formattedValue)) {
$formattedValue = sprintf("'%s'", $formattedValue);
}
$finalSql = str_replace(":$name", $formattedValue, $finalSql);
}
return $finalSql;
}
If you're using query builder then like given below then getPhql function can serve the purpose as per phalcon 3.4.4 version.
$queryBuilder = new Builder();
$queryBuilder->from(…)->where(…)->getQuery();
$queryBuilder->getPhql();
if (!function_exists("getParsedBuilderQuery")) {
/**
* #param \Phalcon\Mvc\Model\Query\BuilderInterface $builder
*
* #return null|string|string[]
*/
function getParsedBuilderQuery (\Phalcon\Mvc\Model\Query\BuilderInterface $builder) {
$dialect = Phalcon\Di::getDefault()->get('db')->getDialect();
$sql = $dialect->select($builder->getQuery()->parse());
foreach ($builder->getQuery()->getBindParams() as $key => $value) {
// For strings work fine. You can add other types below
$sql = preg_replace("/:?\s?($key)\s?:?/","'$value'",$sql);
}
return $sql;
}
}
Simple function that im using for debugging.

PHP PDO dynamically updating db table with multiple records to a specific user ID

/* Newbie need some help; I am creating a class to auto update my apps db record when instructed to, but I am consistently getting this message below, and for the heck of it, I just not seeing what I am doing wrong. Can someone please look at my codes for me? Thank you.
Warning: PDOStatement::bindParam() expects at least 2 parameters, 1 given in……..on line 331; that where the "else if(is_string($val)){" is located.
*/
// vars given
// DBDriver: MySQL
$myTable = 'seeYou';
$loginDate = NULL;
$ip = $_SERVER['REMOTE_ADDR'];
$date = #date('m/d/Y \a\\t h:i a');
$_id =1;
// data array
$idata = array("last_logged_in"=>$loginDate,
"login_date"=>$date,
"ip_addr"=>$ip
);
class name
{
///------------ other methods here---------///
/**
*--------------------------------------------
* Method - PDO: SET FIELD VALUE PLACEHOLDER
*--------------------------------------------
* #return fields with prefix as placeholder
*/
protected function set_fieldValPlaceHolders(array $data)
{
$set = '';
foreach($data as $field => $value)
{
$set .= $field .'= :'.$field . ',';
}
// remove the last comma
$set = substr($set, 0, -1);
return $set;
}
public function save($data=NULL, $_id = NULL, $rows= NULL, $dbTable= NULL)
{
//----------------- some other codes goes here ----------------//
$id = (int)$_id;
// update row with a specific id
if (isset($id) !== NULL && $rows === NULL)
{
$set = $this->set_fieldValPlaceHolders($data);
$sql = "UPDATE {$dbTable} SET {$set} WHERE user_id = :uid";
try
{
// Build the database statement
$_stmt = $this->_dbConn->prepare($sql);
$_stmt->bindValue(':uid',$id, PDO::PARAM_INT);
foreach ($data as $field => $val)
{
if(is_int($val)){
$_stmt->bindValue(':'.$field.'\', '.$val.', PDO::PARAM_INT');
}
else if(is_string($val)){
$_stmt->bindValue(':'.$field.'\', '.$val.', PDO::PARAM_STR');
}
else if(is_bool($val)){
$_stmt->bindValue(':'.$field.'\', '.$val.', PDO::PARAM_BOOL');
}
else if(is_null($val)){
$_stmt->bindValue(':'.$field.'\', '.$val="null".', PDO::PARAM_NULL');
}
else {
$_stmt->bindValue(':'.$field.'\', '.$val.', NULL');
}
$result = $_stmt->execute();
$num = $_stmt->rowCount();
}
}
catch(PDOException $e)
{
die('Error! The process failed while updating your record. <br /> Line #'.__LINE__ .' '.$e);
}
if ($result === true)
{
return true;
}
}
Check your bindValue calls: You give 1 parameter (a long string). It needs at least two. Check all the '
for example, it should be:
$_stmt->bindValue(':'.$field, $val, PDO::PARAM_INT);

Migrating from ADODB to PDO

I have a database query which uses ADODB with unnamed placeholders to insert data into a database and I'm trying to convert it to use PDO but I'm getting an error which is probably due to the syntax I'm using.
What I'm trying:
In an included file I have the following shared function:
function insCOA($data) {
global $dbh;
try {
$sth=$dbh->prepare("
INSERT INTO
coa
(
nom_code,
acc_title,
acc_type_id,
acc_desc
) VALUES (
?,
?,
?,
?
)
");
for ($i = 0; $i < count($data); $i++) {
$sth->execute($data[$i]);
$last_insert_id = $dbo->lastInsertId();
}
}
catch(PDOException $e) {
echo "Something went wrong. Please report this error.";
file_put_contents('/PDOErrors.txt', $e->getMessage(), FILE_APPEND);
}
return $last_insert_id;
}
In my PHP page I have the following:
// Add to coa table
$data = array(
array(
$nom_code, /* nom_code */
$acc_title, /* acc_title */
$acc_type_id, /* acc_type_id */
$acc_desc /* acc_desc */
)
);
$coa_id = insCOA($data);
The connection is handled elsewhere and is connecting ok. It is exported in a global as $dbh.
The error I'm getting is
Fatal error: Call to a member function lastInsertId() on a non-object in /common.funcs.php on line 574 (which is where the reference is to lastInsertId() above.
Originally, when using ADODB, the shared function was as follows:
The shared function:
function insCOA($data) {
global $conn;
$sql = "
INSERT INTO
coa
(
nom_code,
acc_title,
acc_type_id,
acc_desc
) VALUES (
?,
?,
?,
?
)
";
for ($i = 0; $i < count($data); $i++) {
if ($conn->Execute($sql,$data[$i]) === false) {
print 'error' . $conn->ErrorMsg() . '<br />Query: ' . $sql;
} else {
$last_insert_id = $conn->Insert_ID();
}
}
return $last_insert_id;
}
In the PHP page nothing changed.
Once I've got this working, I'll be able to convert a bunch of other queries, so solving this will be very useful. This is my first attempt to use PDO. Thanks.
Found the error myself which was:
$dbo->lastInsertId();
should be
$dbh->lastInsertId();
It's now working perfectly.