How do I call Informix stored procedures from Perl? - perl

How do I call informix stored procedures from Perl? I use DBD::ODBC to connect to informix database, but I don't know how to call procedures. my code like this:
my $dbh = DBI->connect("dbi:".DBDRIVE.":".DBNAME,DBUSER,DBPASS,
{RaiseError=>0,PrintError=>0,AutoCommit=>1}) ||
die $DBI::errstr;
$dbh->do("execute procedure sp_test('2010-05-01 00:00:00')") ||
warn "failed\n";
$dbh->disconnect();
When I run it, it didn't get error. But I get nothing when I check the database. The store procedure works fine if I run it in database directly.
Anyone can help me out?

As strange as it sounds, you need to fetch() from your statement handle in order to actually execute your stored procedure. Try changing your do() call to this instead:
my $sth = $dbh->prepare("execute procedure sp_test('2010-05-01 00:00:00')")
or die $dbh->errstr
$sth->execute() or die $dbh->errstr
$sth->fetch(); # SPL actually executed here
(You may also want to consider setting RaiseError => 1 in your connect() options to avoid having to do all the ... or die ... stuff after every call.)

Pass 1
I suppose DBDRIVE, DBNAME, DBUSER and DBPASS have been defined via the constant module:
use constant DBDRIVE => "informix"; # ...mitsake...
use constant DBNAME => "stores"; # Or whatever
use constant DBUSER => "me";
use constant DBPASS => "mine";
You should use 'or' rather than '||' after the call to DBI->connect().
From 'perldoc DBI':
$dbh = DBI−>connect($data_source, $username, $password, \%attr)
or die $DBI::errstr;
You can can get better help while resolving problems by using 'RaiseError=>1' and/or 'PrintError=>1'; that is what they are there for.
In general terms, the syntax of the EXECUTE PROCEDURE is correct, and should work OK as long as the procedure doesn't return anything...
Pass 2
Oh, you stipulate DBD::ODBC rather than DBD::Informix. Therefore, you are are at the mercy of a lot of code that I don't know so well as I know DBD::Informix.
Can we assume that you can connect to the database successfully using DBD::ODBC? And modify it and so on?
You will probably need to turn on the DBI tracing. You may also need to turn on lower level. Is the ODBC driver you are using provided by Informix, or is it the IBM DB2 CLI (C Common Client) driver, or one provided by someone else? Which version of Informix (IDS) are you using? Which platform are you running on? Which versions of Perl, DBI, DBD::ODBC and the various drivers are you using?
ODBC drivers can go munging SQL sent to it. I'm not clear what the various drivers I mentioned would do with the statement.
Pass 3
Did you consider contacting the dbi-users#perl.org mailing list? That's where the maintainers of DBI and DBD::ODBC hang out.

Related

Connectivity issue to Sybase DB from Perl script

I have to connect my Perl script to a newly constructed Sybase server version - 16.0.03.08.1019
Error - login Failed (due to encrypt password issue)
Previously the script was written in Perl:
$conn = Sybase::DBlib->new($user,$pass,$server,"$dbase Handle");
$conn->sql("use $dbase");
I searched online every where it is written put EncryptPassword=1.
I tried two ways shown below, but couldn't succeed.
$conn = Sybase::DBlib->new($user,$pass,$server,"$dbase Handle","EncryptPassword=1");
$conn = Sybase::DBlib->new("EncryptPassword=1",$user,$pass,$server,"$dbase Handle");
My question is, where to use EncryptPassword=1 in Perl script. Am I using it in correct place.
Wow! DBlib - that takes me back. When I last worked with DBlib (in about 1995), one of the tasks on my list was to replace all use of DBlib with CTlib - which was Sybase's new technology that was intended to replace DBlib. Soon after that, the system was rewritten again to use DBI and DBD::Sybase - which has been the recommended way to talk to Sybase databases from Perl programs for over twenty years. You'll note that the most recent release of sybperl (which is the CPAN distribution containing Sybase::DBlib and Sybase::CTlib) was over ten years ago. I'm pretty sure that Sybase themselves haven't supported DBlib since about the start of this millennium.
So, bearing in mind that you're using ancient technology that is largely dead and shouldn't be used, is there anything that can be done to help you without rewriting the whole system?
Perhaps.
Looking at the documentation for Sybase::DBlib, I see this example of how to write calls to new():
$dbh = new Sybase::DBlib [$user [, $pwd [, $server [, $appname [, {additional attributes}]]]]]
Ignore the fact that it's using the new Class syntax that any rational programmer would avoid - the Class->new() version is this:
$dbh = Sybase::DBlib->new([$user [, $pwd [, $server [, $appname [, {additional attributes}]]]]])
Note the "additional attributes" field at the end. I bet that's where your stuff needs to go. Note also, that it's { additional attributes } - so it looks like it expects a hash reference.
So it seems likely that the syntax you want is this:
$conn = Sybase::DBlib->new($user, $pass, $server, "$dbase Handle", {
EncryptPassword => 1,
});
Note that there are huge caveats in this. Not least, given that Sybase::DBlib has been unsupported for ten years, I wouldn't be at all surprised if it didn't support encrypted passwords at all.
But it might work. It's probably your best hope.
And please do whatever you can to update your codebase to use tools and libraries that haven't been unsupported for such a long time.

"Insecure dependency error while running with -T switch" using cicindela2

I am applying the cicindela2 recommendation engine
It uses Apache mod_perl and the Perl DBI module.
Here is the rough flow of how it works
Data input by Record Handler
Data is passed through the filter chain for batch processing
Temporary tables are output from batch processing
Recommendation result is requested by accessing the Recommend Handler which trigger the action of Recommender
I configured an aggregation and ran the project batch script. I know that the batch processing succeeded because I saw the output of processing from DB. But when I tried to access the recommendation result with URL that triggers the Recommend Handler, I saw a blank white page and the log said
FATAL: Insecure dependency in parameter 1 of DBIx::ContextualFetch::db=HASH(0x7f2a76169e78)->prepare_cached method call while running with -T switch at /usr/local/share/perl5/Ima/DBI.pm line 398.
This is where the error was thrown from the
Ima::DBI
base module
/usr/local/share/perl5/Ima/DBI.pm.
sub _mk_sql_closure {
my ($class, $sql_name, $statement, $db_meth, $cache) = #_;
return sub {
my $class = shift;
my $dbh = $class->$db_meth();
# Everything must pass through sprintf, even if #_ is empty.
# This is to do proper '%%' translation.
my $sql = $class->transform_sql($statement => #_);
return $cache # Line 398
? $dbh->prepare_cached($sql)
: $dbh->prepare($sql);
};
}
It seems that the SQL query prepared by the program is insecure, right?
What is reason for this error?
Is it related to the function of cache management of DBI?
Would it be solved if I clear the cache regularly?
Also, I tried to log the SQL statement generated, but the output failed even when I placed something like $LOGGER->warn("123") in the handle subroutine of the Recommend Handler.
How come the log failed and how to log it correctly?
Insecure dependency... while running with -T switch is Perl's way of telling you that you're running with taint mode active and attempting to do something with tainted data which could be potentially unsafe. In this particular case, $sql is tainted, because some or all of its content came from sources external to the program - probably user input, although it could also have been read from a file.
To fix this, you need to think about where $sql came from, so that you can work out the appropriate way to clean it up.
In the most likely scenario, you've asked a user to supply search terms and then inserted those terms directly into your SQL string. This is a bad idea in general, as it opens you up to the possibility of SQL injection attacks. (Obligatory Bobby Tables link.) Revise your SQL handling to make use of SQL placeholders instead of inserting user input into the WHERE clause and this vulnerability should go away.
If tainted data is making its way into $sql in some other way, you need to clean up the tainted data by using a regular expression to validate it and capture the validated data, then assign the captured data to your variable. e.g.,
my $tainted = <STDIN>;
$tainted =~ /([A-Z]*)/; # Only allow uppercase characters
my $clean = $1; # No longer tainted because it came from $1
If you need to take this route, DO NOT use .* as your regex to untaint the data without serious, serious consideration, because, if you just blindly accept any and all data, you will be discarding any and all benefit provided by taint mode.

Unable to execute an oracle update statement within perl

I have a problem in a perl script that I'm writing. When I run the script it hangs after prepare(). I've tried to run the update statement from SQL Developer and it works fine.
I've also tried to print out all parameters and they are correct.
What am I missing here?
my $upd = 'update ngs.pp_subscr_data set address=?, city=?, postalcode=?, kennitala=?, email=?, firstname=?, lastname=?, last_upd=systimestamp where snb=?';
my $s = $dbh->prepare ($upd) || exitError(-9802, 'Couldn\'t prepare update statement.');
$s->execute($addr, $city, $pcode, $ktala, $email, $fname, $lname, $snb) || exitError(-9803, 'Couldn\'t execute statement: ' . $s->errstr);
Thanks.
First, what version of Oracle?
Ok, I see couple of problems with your description. When you say "hang", is it really a hang? Could it be spinning?
Also, second, you say "... it hangs after prepare()". Does that mean it hangs after you call prepare(), or after it returns from prepare()?
Is it hanging in the database, and your client program is waiting for a database call to complete?
You need to run the program, then look at V$SESSION, identify the SID that corresponds to the database session of your program, and see what it's doing. Look at the EVENT column in V$SESSION. Also, look at the STATUS column to tell if the session is currently in a database call (ACTIVE), or waiting for the client program to call the database (INACTIVE).
Report some information back, and I may be able to provide further insight.
Hope that helps.

Disable prepared statements on a per-query basis in DBIx::Class with Postgres

I have a few queries which are much slower when using prepared statements in Postgres (this is a known issue, see http://www.postgresql.org/docs/current/static/sql-prepare.html). I therefore want to turn off statement preparation for these queries.
in DBIx::Class, I can turn off prepared statements globally when connecting to the database by passing the parameter "pg_server_prepare => 0" in the connect_info. but I can't see how to change this for an existing connection. given a DBIx::Class::Schema, I tried this:
$schema->storage->connect_info->[0]->{'pg_server_prepare'} = 0;
if I log the connect_info after that call, I see the new value for this parameter, but the database driver still uses prepared statements. I also tried to disconnect and reconnect
$schema->storage->connect_info->[0]->{'pg_server_prepare'} = 0;
$schema->storage->disconnect;
$schema->connect(#{ $schema->storage->connect_info->[0] });
but this didn't help either.
any ideas?
I'm not using DBD::Pg, so I can't say for sure, but this -might- be working:
$schema->storage->dbh_do(sub {
my (undef, $dbh) = #_;
local $dbh->{pg_server_prepare} = 0;
# now do anything with $dbh you want
});

Dump prepared sql query from DBI statement in PERL

im using DBI in Perl to connect to my PostgreSQL Database.
Everything is working fine but in my debugging (printing results etc.) iam not able to see if the query prepared by perls DBI module is really correct.
I have something like this:
$sth->prepare( qq{SELECT * FROM company WHERE companyname LIKE ? AND city = ?});
$sth->execute( $name.'%', $city);
Iam not able to see how the sql query looks after calling execute, as execute is the latest step where parameters are binded to the query.
I would like to have something like $sth->getLastExecutedQuery() or something to see how the query looked like.
In this case the function getLastExecutedQuery() would return:
SELECT * FROM company WHERE companyname LIKE 'Company Name%' AND city = 'City name';
Is there any way to get this? Its only for debugging purposes.
DBI supports the following:
There is the DBI->trace($tracefile_handle) method (traces all DBI interactions), or $dbh->trace($tracefile_handle) which would trace just the interactions on a specific handle. Output defaults to STDERR, but by supplying $tracefile_handle, you can explicitly send output to a different file (or just use shell redirection).
DBD::pg also supports $h->trace('SQL'); This must be supported by your DBD driver to work, but fortunately DBD::Pg does support the feature.
The documentation for DBI, at CPAN - DBI,
and for DBD::Pg at CPAN - DBD::Pg really gives you all you need to know on tracing.
Use the DBI tracing facility. It works like this:
use strict;
use warnings;
use DBI;
my %opt = ( RaiseError => 1 );
my $dbh = DBI->connect( 'dbi:mysql:test', 'fred', 'secret', \%opt );
$dbh->trace(2); # level 2 shows statement with inserted parameters
my $sql_i = 'insert into t1 (a, b) values ( ?, ? )';
my $sth_i = $dbh->prepare( $sql_i );
for ( qw/ eins zwei drei / ) {
$sth_i->execute( $_, $_ );
}
$dbh->disconnect;
Beyond the tracing others have mentioned you should look at https://metacpan.org/pod/DBI#Statement which gives you the SQL last executed and https://metacpan.org/pod/DBI#ParamValues and https://metacpan.org/pod/DBI#ParamTypes which tell you about your parameters.
There is also DBIx::Log4perl which can log what you want without all the DBI tracing.