problems in using DBI - perl

I'm new to all this this stuff. I'm trying to execute the following code
use DBI;
my $dsn = 'DBI:mysql:db:localhost';
my $db_user_name = 'root';
my $db_password = '*******';
my $dbh = DBI->connect($dsn, $db_user_name, $db_password);
my $sth = $dbh->prepare("select id from table where field = 'value'");
$sth->execute();
($id) = $sth->fetchrow_array();
print "id is $id";
$sth->finish();
print outputs nothing. Can you tell me what am I doing wrong?
Thank you in advance!

You said in one of the comments that you had an # in the value. If you're having a quoting issue, you should use a placeholder. Let the database driver handle the quoting issues for you:
my $sth = $dbh->prepare("select id from table where field = ?");
$sth->execute($some_value);

Related

Perl/DBI - Insert rows from Postgres to an Oracle table

I am trying to write a script that will read the data from postgresql table and insert it to an oracle table, here is my script :
#!/usr/local/bin/perl
use strict;
use DBI;
use warnings FATAL => qw(all);
my $pgh = pgh(); # connect to postgres
my $ora = ora(); # connect to oracle
my #rows;
my $rows =[] ;
my $placeholders = join ", ", ("?") x #rows;
my $sth = $pgh->prepare('SELECT * FROM "Employees"');
$sth->execute();
while (#rows = $sth->fetchrow_array()) {
$ora->do("INSERT INTO employees VALUES($placeholders)");
}
#connect to postgres
sub pgh {
my $dsn = 'DBI:Pg:dbname=northwind;host=localhost';
my $user = 'postgres';
my $pwd = 'postgres';
my $pgh = DBI -> connect($dsn,$user,$pwd,{'RaiseError' => 1});
return $pgh;
}
#connect to oracle
sub ora {
my $dsn = 'dbi:Oracle:host=localhost;sid=orcl';
my $user = 'nwind';
my $pwd = 'nwind';
my $ora = DBI -> connect($dsn,$user,$pwd,{'RaiseError' => 1});
return $ora;
}
I am getting the following error :
DBD::Oracle::db do failed: ORA-00936: missing expression (DBD ERROR: error possibly near <*> indicator at char 29 in 'INSERT INTO employees VALUES(<*>)') [for Statement "INSERT INTO employees VALUES()"] at /usr/share/perlproj/cgi-bin/scripts/nwind_pg2ora.pl line 19.
Please help me to get my code correct.
Many thanks !!
Tonya.
See the documentation for DBD::Oracle you have to bind the parameter value for the BLOBs like :
use DBD::Oracle qw(:ora_types);
$sth->bind_param($idx, $value, { ora_type=>ORA_BLOB, ora_field=>'PHOTO' });
my #rows;
my $rows =[] ;
my $sth = $pgh->prepare('SELECT * FROM "Employees"');
$sth->execute();
while (#rows = $sth->fetchrow_array()) {
my $placeholders = join ", ", ("?") x #rows;
$ora->do("INSERT INTO employees VALUES($placeholders)");
}
You're joining an empty #rows to create an empty $placeholders.
perform the join inside the while loop, before the do().
The following lazily creates a statement handle for inserting into the Oracle database based off the number of columns in the returned records.
It then inserts those column values into the database, so obviously we're assuming the table structures are identical:
use strict;
use DBI;
use warnings FATAL => qw(all);
my $pgh = pgh(); # connect to postgres
my $ora = ora(); # connect to oracle
my $sth = $pgh->prepare('SELECT * FROM "Employees"');
$sth->execute();
my $sth_insert;
while (my #cols = $sth->fetchrow_array()) {
$sth_insert ||= do {
my $placeholders = join ", ", ("?") x #cols;
$ora->prepare("INSERT INTO employees VALUES ($placeholders)");
};
$sth_insert->execute(#cols);
}

Fetching one single row from database using Perl

I am trying to run a simple database connection with Perl using postgreSQL
use DBI;
$database = "postgres";
$user = "postgres";
$password = "admin";
my $dbh = DBI->connect( "dbi:Pg:dbname=$database"
, $user
, $password
)
or die "Can't Connect to database: $DBI::errstr\n";
# get data from the URL string
my $firstname = "haroon";
my $lastname ="ash";
my $age = 24;
# insert the data into the database
my $query = "INSERT INTO people (firstname, lastname, age)
VALUES ('$firstname','$lastname', '$age')";
$dbh->do($query);
# get the ID of the inserted person
$query = "SELECT MAX(id) FROM people";
my $sth = $dbh->prepare($query);
my $rv =$sth->execute;
if($rv < 0){
print $DBI::errstr;
}
else {
my $row = $sth->fetchrow_hashref;
my $person_id = $row->{'max'};
print $firstname, $lastname
. "was successfully inserted at position "
. $person_id;
}
I am trying to print the person id which i had entered latest. But my $person_id = $row->{'max'} seems to give me the correct answer instead of my $person_id = $row->{'id'};. I am not understanding why is that.
You might want to set column alias for query,
$query = "SELECT MAX(id) AS id FROM people";
as postgres is putting his own alias for you, and that is max.
If all you want is last inserted id, you can
my $query = "INSERT INTO people (firstname, lastname, age)
VALUES (?,?,?)
returning id
";
and fetch query as you would do with select. (check pg docs)
You can use the RETURNING keyword to return the id associated with the row you just inserted:
my $query = '
INSERT INTO people (firstname, lastname, age)
VALUES ($1, $2, $3)
RETURNING id';
my $sth = $dbh->prepare($query);
$sth->execute($firstname, $lastname, $age);
my $rv = $sth->fetchrow_hashref();
printf "%s, %s was successfully inserted at position %d\n",
$firstname, $lastname, $rv->{id};
You did not enter a PERSON_ID in your insert statement.
Instead it seems the ID field was populated by the DB, an auto increment value during insert, it seems.
Without knowing the table definition (and potential insert trigger on the table) it is hard/impossible to give you a better answer.

Perl dbi sqlite 'select * ..' only returns first elem

got a problem with perl dbi sqlite.
I have set up a database (and checked it with sqlite command line).
Now i want to search in this database, which did not work.
So i tried to just do a 'SELECT *'
this prints only the first element in the database, but not as it should everything in this table.
I think the error that causes the select * to fail is the same that prevents me from using "like %..%" stuff.
This is the relevant code, if the code is correct and the database table seems good what else could have caused the problems ?
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","","") || die "Cannot connect: $DBI::errstr";
my $sth = $dbh->prepare('SELECT * FROM words');
$sth->execute;
my #result = $sth->fetchrow_array();
foreach( #result) {
print $_;
}
fetchrow_array() only fetches one row.
Try
while ( my #row = $sth->fetchrow_array ) {
print "#row\n";
}
According to the documentation, fetchrow_array
Fetches the next row of data and returns it as a list containing the field values.
If you want all of the data you can call fetchrow_array (or fetchrow_arrayref) repeatedly until you reach the end of the table, or you can use fetchall_arrayref:
The fetchall_arrayref method can be used to fetch all the data to be returned from a prepared and executed statement handle. It returns a reference to an array that contains one reference per row
The code would look like this
use strict;
use warnings;
use DBI;
my $dbfile = 'words.db';
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile", '', '') or die "Cannot connect: $DBI::errstr";
my $sth = $dbh->prepare('SELECT * FROM words');
$sth->execute;
my $result = $sth->fetchall_arrayref;
foreach my $row ( #$result ) {
print "#$row\n";
}

Update in Perl DBI not working, why? (full source posting, including DDL to create database in MySQL)

Why is the UPDATE in "Example 2" not working?
# MySQL DDL to create database used by code
#
# CREATE DATABASE sampledb;
#
# USE sampledb;
#
# CREATE TABLE `dbtable` (
# `id` int(11) NOT NULL AUTO_INCREMENT,
# `demo` longtext,
# PRIMARY KEY (`id`)
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# PERL MODULES WE WILL BE USING
use strict;
use warnings;
use DBI;
# CONFIG VARIABLES
my $platform = "mysql";
my $database = "sampledb";
my $host = "localhost";
my $port = "3306";
my $username = "root";
my $password = "password";
# DATA SOURCE NAME
my $dsn = "dbi:$platform:$database:$host:$port";
# PERL DBI CONNECT
my $connect = DBI->connect($dsn, $username, $password);
# VARS for Examples
my $query;
my $query_handle;
my $id;
my $demo;
# Example 1 using prepare() and execute() INSERT
# SAMPLE VARIABLE AND VALUES TO PASS INTO SQL STATEMENT
$id = 1;
$demo = "test";
# prepare() and execute() INSERT
$query = "INSERT INTO dbtable (id, demo) VALUES ('$id', '$demo')";
$query_handle = $connect->prepare($query);
# EXECUTE THE INSERT
$query_handle->execute();
print STDERR "ERROR: $DBI::errstr";
print STDERR "INFO: $query_handle rows updated";
undef $query;
# Example 2 using do() UPDATE
# SAMPLE VARIABLE AND VALUES TO PASS INTO SQL STATEMENT
$id = 2;
$demo = "test 2";
# do() THE UPDATE
$query = "UPDATE dbtable SET demo = '$demo' WHERE id = $id;";
$query_handle = $connect->prepare($query);
# EXECUTE THE UPDATE
$query_handle = $connect->do($query);
print STDERR "ERROR: $DBI::errstr";
print STDERR "INFO: $query_handle rows updated";
undef $query;
You're trying to update a record with id=2, which doesn't seem to exist.
Are you getting an error in $DBI::errstr? Aside from any output DBI might be giving you, the initial potential problem I see is that you insert a row with id=1, but your update is trying to update rows with id=2. There won't be any rows where id=2 to update.
A couple of other things you may also want to be aware of. Interpolating your variables right into your queries like that is bad practice and is what leads to SQL injection attacks. You should look at the DBI documentation on using placeholders for this. Placeholders also let you make the most effective use of prepare() when you need to do the same query on different values in a loop. If you just did that because it's just a quick test and you wouldn't do that in "real" code, then sorry for harassing you about it.
You also don't need to call prepare() before do(). do() handles the call to prepare() itself.

Best way to use Perl's DBI to UPDATE a row, and print the response to the cmd-line?

Have some Perl code which is using the DBI module - (the code is at work, I can post it in the morning if needed) - but mainly trying to get a sense of what DBI needs to do an update to a row -- and get either errors back, or confirmation that the UPDATE was executed.
(Below is just a basic example, feel free to give your own example and sample DDL if you want... just want some code that I know works. I've run my code via the Perl PtkDB debugger, and can "see" the SQL it generating and executing -- even paste in in the MySQL consol and execute it... but it's doing nothing in the Perl, even thought the select statements are working. Mainly just want a better idea of how DBI is handling UPDATE to MySQL, and if there's any built in feature in DBI that would make debugging this more simple. Thanks!)
So, please supply one full Perl script that:
Sets the connection (MySQL)
SELECT row two based on ID and get the first and last name
Lowercase the names
UPDATE the table
disconnect
Sample TABLE
<COL01>Id <COL02>FirstName <COL03>LastName
<ROW01-COL01>1 <ROW01-COL02>John <ROW01-COL03>Smith
<ROW02-COL01>2 <ROW02-COL02>Jane <ROW02-COL03>Doe
UPDATE (1): Code in question is below. The ONLY thing I've changed is remove code not related to the issue and the config info (eg database name, user, password, etc.) and made the value production for the variables super simple. This code was created by someone else and in a legacy code base.
use strict;
use warnings;
use DBI;
sub dbOpen {
my $dsn;
my $dbh;
$dsn = "DBI:mysql:database=databasename;host=localhost;port=3306";
$dbh = DBI->connect( $dsn, "root", "password" ) ||
print STDERR "FATAL: Could not connect to database.\n$DBI::errstr\n";
$dbh->{ AutoCommit } = 0;
return($dbh);
} # END sub dbOpen
my $Data;
$Data = &dbOpen();
my ($sql,$rs,$sql_update_result);
my $column2,
my $column3;
my $id;
$column2 = 2,
$column3 = 3;
$id = 1;
$sql = "UPDATE table SET column1 = NULL, column2 = ".$column2.", column3 = ".$column3." WHERE id = ".$id.";";
$rs = $Data->prepare( $sql );
$rs->execute() || &die_clean("Couldn't execute\n$sql\n".$Data->errstr."\n" );
($sql_update_result) = $rs->fetchrow;
$Data->disconnect();
DDL for MySQL -- if needed, just comment and I'll post one.
UPDATE (2):
Final found one complete example, though it's only for a select statement and not even inserting any VARs into the SQL: http://search.cpan.org/~timb/DBI/DBI.pm#Simple_Examples
Almost copy and paste from DBI Synopsis:
use DBI;
$dbh = DBI->connect($data_source, $username, $auth, \%attr);
$statement = "UPDATE some_table SET som_col = ? WHERE id = ?";
$rv = $dbh->do($statement, undef, $som_val, $id);
$DBI::err && die $DBI::errstr;
$rc = $dbh->disconnect;
I prefer to use do when updating or deleting since these operations doesn't return any row.
So, in order to have a little debug, i would modify your code like this:
my $sql = "UPDATE table SET column1=NULL, column2=$column2, column3=$column3 WHERE id=$id";
print STDERR "SQL: $sql\n"
my $numrows = $Data->do($sql);
if (not defined $numrows) {
print STDERR "ERROR: $DBI::errstr";
} else {
print STDERR "INFO: $numrows rows updated";
}
You can measure query response times from within your perl code, but since it is a database thing, i recommend you using any Mysql specialized tool (i don't use MySQL, sorry).
Have you considered something a bit higher level - like DBIx::Class?
You don't need to return the values, lowercase them in Perl, then update the rows. Just do that in one SQL statement:
my $sql = "UPDATE table SET column2=lower(column2) WHERE id = ?";
$sth = $dbh->prepare($sql);
foreach my $id (#ids) {
$sth->execute($id);
}
You also want to use placeholders to prevent Bobby Tables from visiting.