Connectivity issue to Sybase DB from Perl script - perl

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.

Related

Autoload'd calls fail via Inline::Perl5 in Raku

I'm rewriting some perl/charting software in Raku but have run into an issue using the ChartDirector perl5 module (link below) via Inline::Perl5. The module is basically a perl interface to a DLL; using the module via Inline::Perl5 seems to work for method calls explicitly included in the code - but most of the method calls are executed via the autoload 'catch all' mechanism in perl5. These do not work in my raku code.
My question is can I expect this sort of application to work using Inline::Perl5? (perhaps there is no way to 'catch' these autoload'd method calls) and, if so, how to make it so.
Thanks for any pointers, suggestions.
wf
ChartDirector software (excellent graphics/charting software - have used it for nearly 2 decades with perl): https://www.advsofteng.com/index.html
Quoting verbiage (simplified), version info, and code from the start of a chartdir forum thread about this:
I'm using Inline::Perl5 which works with every other module I've tried.
I'm hitting problems reproducing the "first project" example on the chartdir site.
using chartdir 6, freebsd 12.2 (intel platform), raku 2022.04, perl 5.32.1.
#!/usr/bin/env raku
use lib:from<Perl5> '/usr/local/lib/perl5/site_perl';
use Inline::Perl5;
my $p5 = Inline::Perl5.new;
$p5.use('perlchartdir') ;
my $data = [85, 156, 179.5, 211, 123];
my $labels = ["Mon", "Tue", "Wed", "Thu", "Fri"];
my $c = $p5.invoke( 'XYChart', 'new', 250, 250);
$c.setPlotArea(30, 20, 200, 200);
$c.addBarLayer($data);
$c.xAxis().setLabels($labels);
$c.xAxis().setLabels($labels);
$c.makeChart("simplebar.png");
All seems fine (i.e., data-dumping $c after line 8 shows a large/reasonable looking structure) until line 9 where I receive "No such method setPlotArea for invocant of type XYChart". Line 10 does appear to work (no complaints) - remaining 3 lines don't (same type of error as for line 8).
And quoting some feedback that was given by Peter Kwan, the primary dev of chartdir:
I have never used Raku before. For your case, the methods that fail seem to be AUTOLOAD methods. ... I suspect may be Raku does not support Perl AUTOLOAD, so it reports undefined methods as not found instead of forwarding it to the "catch all" method. Or may be some additional things need to be imported for it to use the AUTOLOAD.
As dwarring notes in the comments below this SO question, Inline::Perl5 does support autoload (and has for 7 years), so perhaps that aspect is a red herring?
gratefully responding to p6steve's response, I am providing some additional information ..
The full output from various representations of $c (the XYChart object) is included here: https://pastebin.com/gY2ibDaM (hope it's ok to use pastebin for this (still finding my way through stackoverflow)) - the output was 600+ lines long and wasn't sure what I could usefully edit out).
to summarize though ..
dd $c returns nil (although prints out the equivalent of $c.perl (below) to stdout (not sure why))
say $c.perl returns:
XYChart.new(inline-perl5 => Inline::Perl5.new(thread-id => 1), wrapped-perl5-object => NativeCall::Types::Pointer.new(34651088744))
say $c.^methods returns:
(WHERE addHLOCLayer ACCEPTS WHY can new isa rakuseen defined getYCoor addHLOCLayer3 raku yZoneColor Numeric addLineLayer addAreaLayer DESTROY BUILDALL gist perl WHICH sink bless getYValue Str addBarLayer new_shadow_of_p5_object AT-KEY)
finally, say Dump $c (using Data::Dump module) yields about 600 lines of output (included in the pastebin output).
Hi wingfold and welcome to the raku SO tag!
I wonder what you get with dd $c; just before the line $c.setPlotArea(30, 20, 200, 200); - e.g. is $c truly an XYChart object?
If so then what does $c.^methods (the '^' indicates a meta method ... in this case you should get a list of the available methods).
Please do post the results here and hopefully that will help the diagnosis...
Thanks for the info!
Having seen the output of the $c.^methods call, it is clear that $c has no method $c.setPlotArea (reading the error message says the same - perhaps I should have given that due weight!)
I do not know the Inline::Perl5 module well, but I have seen similar issues with Inline::Python.
My experience in Python is that the target language objects only expose their "direct" methods and do not automatically pull in all the composed methods that they can perform.
My workaround has been on the lines of an "eval" style approach, something like:
$p5.run( qq[$c.setPlotArea(30, 20, 200, 200);] );
Hope this helps!

"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.

Special character handling when fetching data from MS SQL Server using Perl DBD

I have an MS SQL Server 2008 Database, from which I am fetching data using perl DBD::Sybase module. But there are some special characters in the DB, like the Copyright symbol, Trademark symbol etc., which are not getting imported properly. Perl seems to change all of these special characters to a Question mark character. Is there a way to fix this?
I have tried specifying charset=utf8 in the connection string. The doc mentions a syb_enable_utf8 (bool) setting, but whenever I try that, I get an error:
Can't locate object method "syb_enable_utf8" via package "DBI::db"
One solution I found was this:
use Encode qw(encode_utf8);
Then, wherever you are writing data to a file or anywhere else, use Encode::encode_utf8($data);
where $data is the column/value which you have fetched from MSSQL.
I don't use DBD::Sybase but a) I use a lot of other DBDs and b) I am currently collecting information about unicode support in DBDs. According to the pod you need at least OpenClient 15.x when using syb_enable_utf8. Are you using 15.x or later? Perhaps syb_enable_utf8 is not defined if your client is less than 15.x or perhaps you have too old a version of DBD::Sybase. Unfortunately I cannot see from the Changes file when syb_enable_utf8 was added.
However, when you say "can't locate method" I think that is a clue as syb_enable_utf8 is not a method, it is an attribute (it is under Sybase Specific Attributes) in the pod. So you need to add it to your connect call or set it via a connection handle like this:
my $h = DBI->connect("dbi:Sybase:something","user","password", {syb_enable_utf8 => 1});
or
$h->{syb_enable_utf8} = 1;
You should also read the bits in the pod describing what happens when syb_enable_utf8 is set as it appears from the documents it only applies to UNIVARCHAR, UNICHAR, and UNITEXT columns.
Lastly, you need to ensure you insert the data correctly in the first place. I'd guess if it is not inserted from Perl with syb_enable_utf8 and charset=utf8 and your data is not proper unicode characters in Perl before you insert you'll get garbage back.
The comment Raze2dust made had nothing to do with your issue but is worth heeding if you are going to write the data retrieved from your database elsewhere. Just remember to decode any data input to your script and encode any data output.

How do I call Informix stored procedures from 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.

After querying DB I can't print data as well as text anymore to browser

I'm in a web scripting class, and honestly and unfortunately, it has come second to my networking and design and analysis classes. Because of this I find I encounter problems that may be mundane but can't find the solution to it easily.
I am writing a CGI form that is supposed to work with a MySQL DB. I can insert and delete into the DB just fine. My problem comes when querying the DB.
My code compiles fine and I don't get errors when trying to "display" the info in the DB through the browser but the data and text doesn't in fact display. The code in question is here:
print br, 'test';
my $dbh = DBI->connect("DBI:mysql:austinc4", "*******", "*******", {RaiseError => 1} );
my $usersstatement = "select * from users";
my $projstatment = "select * from projects";
# Get the handle
my $userinfo = $dbh->query($usersstatement);
my $projinfo = $dbh->query($projstatement);
# Fetch rows
while (#userrow = $userinfo->fetchrow()) {
print $userrow[0], br;
}
print 'end';
This code is in an if statement that is surrounded by the print header, start_html, form, /form, end_html. I was just trying to debug and find out what was happening and printed the statements test and end. It prints out test but doesn't print out end. It also doesn't print out the data in my DB, which happens to come before I print out end.
What I believe I am doing is:
Connecting to my DB
Forming a string the contains the command/request to the DB
Getting a handle for my query I perform on the DB
Fetching a row from my handle
Printing the first field in the row I fetched from my table
But I don't see why my data wouldn't print out as well as the end text. I looked in DB and it does in fact contain data in the DB and the table that I am trying to get data from.
This one has got me stumped, so I appreciate any help. Thanks again. =)
Solution:
I was using a that wasn't supported by the modules I was including. This leads me to another question. How can I detect errors like this? My program does in fact compile correctly and the webpage doesn't "break". Aside from me double checking that all the methods I do use are valid, do I just see something like text not being displayed and assume that an error like this occurred?
Upon reading the comments, the reason your program is broken is because query() does not execute an SQL query. Therefore you are probably calling an undefined subroutine unless this is a wrapper you have defined elsewhere.
Here is my original posting of helpful hints, which still apply:
I hope you have use CGI, use DBI, etc... and use CGI::Carp and use strict;
Look in /var/log/apache2/access.log or error.log for the bugs
Realize that the first thing a CGI script prints MUST be a valid header or the web server and browser become unhappy and often nothing else displays.
Because of #3 print the header first BEFORE you do anything, especially before you connect to the database where the script may die or print something else because otherwise the errors or other messages will be emitted before the header.
If you still don't see an error go back to #2.
CGIs that use CGI.pm can be run from a command line in a terminal session without going through the webserver. This is also a good way to debug.