friends could one of the perl expert tell me what I'm doing wrong here?
I'm still learning perl so newbie with this..whatever I do my connection string doesn't work.
trying to connect oracle database with perl script with below argument on cmd prompt.
$ list_tables /#testdb
Query dba_tables and list tables of user ABC
Also get output in logfile
#!/usr/local/bin/perl -w
use strict;
use Getopt::Std;
use OracleAgent;
use OracleLoginString;
my exitStatus = 0;
my %options = ();
my $oracleLogin;
getopts("o",\%options);
if (defined $options{o}) {
$oracleLogin = $options{o};
}
else {
exitWithError());
}
my $db = DBI->connect('dbi:Oracle:',$oracleLogin,'')
or die "Can't connect to Oracle database: $DBI::errstr\n";
exit($exitStatus);
Basically when I execute script I just want to provide instance name and not password.
I can connect from sqlplus prompt without password since using oracle login e.g. $sqlplus "/#testdb"
add DBD::Oracle
use DBD::Oracle;
Write a proper connection string:
my $db = DBI->connect("dbi:Oracle:host=$host;sid=$sid", $user, $passwd);
Related
I am on Windows 10 using Strawberry Perl version 5.30 and trying to print out the values of the Registry key HKEY_CLASSES_ROOT/Directory/Background/shell/WSL using the Perl module Win32::TieRegistry. Here is a screen shot from the Registry Editor app in Windows 10:
I am using this Perl script to print the value:
use feature qw(say);
use warnings;
use strict;
use Data::Dumper qw(Dumper);
use Win32::TieRegistry( Delimiter=>"/", ArrayValues=>0 );
{
dump_keys("HKEY_CLASSES_ROOT/Directory/Background/shell/WSL");
dump_keys("HKEY_CLASSES_ROOT/Directory/Background/shell/AnyCode");
}
sub dump_keys {
my ($key) = #_;
say "Dumping keys for $key:";
my $tree= $Registry->{$key};
my #keys = keys %$tree;
print Dumper(\#keys);
}
The output is (running from a CMD terminal with adminstration privileges):
>perl p.pl
Dumping keys for HKEY_CLASSES_ROOT/Directory/Background/shell/WSL:
$VAR1 = [];
Dumping keys for HKEY_CLASSES_ROOT/Directory/Background/shell/AnyCode:
$VAR1 = [
'command/',
'/'
];
as seen it prints the AnyCode subkey but not the WSL subkey. I also checked with running reg query from the same CMD:
>reg query HKEY_CLASSES_ROOT\Directory\Background\shell\WSL
HKEY_CLASSES_ROOT\Directory\Background\shell\WSL
(Default) REG_SZ #wsl.exe,-2
Extended REG_SZ
NoWorkingDirectory REG_SZ
So that works fine, but why doesn't the Perl script print the value of the WSL subkey?
It turns out that even if you run the Perl script as admin, you do not necessarily have write access to a given registry key, see this blog post for more information.
According to the documentation for Win32::TieRegistry, the default $Registry (the tied hash exported by Win32::TieRegistry) is opened with both read and write access:
The virtual root of the Registry pretends it was opened with access
KEY_READ()|KEY_WRITE() so this is the default access when opening keys
directory via $Registry
This explains why some keys cannot be accessed from $Registry since it when accessing a key the write permission is required.
As explained in the blog post it is possible to grant yourself write access to any key in the registry by using the regedit app in Windows 10.
Another approach is to only require read access (not write access) when opening a tied hash with Win32::TieRegistry:
use feature qw(say);
use warnings;
use strict;
use Data::Dumper qw(Dumper);
use Win32::RunAsAdmin qw(force);
use Win32API::Registry qw(regLastError KEY_READ);
use Win32::TieRegistry( Delimiter=>"/", ArrayValues=>0 );
{
my $reg = $Registry->Open("HKEY_CLASSES_ROOT/Directory",
{ Access=>KEY_READ(), Delimiter=>"/" }
);
dump_keys($reg, "Background/shell/WSL");
dump_keys($reg, "Background/shell/AnyCode");
}
sub dump_keys {
my ($reg, $key) = #_;
my $tree= $reg->{$key};
if (!$tree) {
say "failed: $^E";
}
else {
my #keys = keys %$tree;
print Dumper(\#keys);
}
}
Below is my Oracle query which is running via PowerShell. It is working fine with no error if I am running it locally on that machine.
[Reflection.Assembly]::LoadFile("E:\oracle\product\11.2.0\ODP.NET\bin\2.x\Oracle.DataAccess.dll")
$constr = "User Id=system;Password=pass;Data Source=API"
$conn= New-Object Oracle.DataAccess.Client.OracleConnection($constr)
$conn.Open()
$sql="select * from dba_users"
$command = New-Object Oracle.DataAccess.Client.OracleCommand($sql,$conn)
$reader=$command.ExecuteReader()
while($reader.Read()){
$reader.GetString(0)
}
$conn.Close()
I want to run same query on other machine from this machine. I can say I want to run it remotely.
When I run it I am getting this error:
Exception calling "Open" with "0" argument(s): "ORA-12541: TNS:no
listener"
I can't add entry in Tnsora file.
Can anybody advise me any alternative way to achive this?
If you can't modify the tnsora, you have to use either EZConnect or the connect descriptor as your connection string. Try this:
$userId = 'system'
$password = 'pass'
$host = 'ip or hostname'
$port = '1521'
$serviceName = 'Your service name'
$constr = "User Id=$userId;Password=$password;Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=$host)(PORT=$port))(CONNECT_DATA=(SERVICE_NAME=$serviceName)))"
I simply want to have a rest api server which I can call to update a file via a URL, that's it.
Here is the file:
mytextfile:
key1 = value1
key2 = value2
On the client, a script will be run which sends a string or strings to the API server.
The API server will receive them, for example /update.script?string1="blah"&string2="fun" (pretend its url encoded)
The server should then parse these strings, and then call an exec function, or another script even on the system which does some sed command to update a file
Language or implementation doesn't matter.
Looking for fresh ideas.
All suggestions are appreciated.
I don't get it: What exactly is your problem/question?
My approach to the problem "modifying a file from inside a cgi script using url-encoded arguments" would be:
Pick a language you like and start coding, in my case with Perl.
#!/usr/bin/perl
use strict; use warnings;
Fetch all your arguments. I will use the CGI module of Perl here:
use CGI::Carp;
use CGI;
my $cgi = CGI->new;
# assuming we don't have multivalued fields:
my %arguments = $cgi->Values; # handles (almost) *all* decoding and splitting
# validate arguments
# send back CGI header to acknowledge the request
# the server will make a HTTP header from that
Now either call a special subroutine / function with them …
updateHandler(%arguments);
...;
my $filename = 'path to yer file name.txt';
sub updateHandler {
my %arguments = #_;
# open yer file, loop over yer arguments, whatever
# read in file
open my $fileIn, '<', $filename or die "Can't open file for reading";
my #lines = <$fileIn>;
close $fileIn;
# open the file for writing, completely ignoring concurrency issues:
open my $fileOut, '>', $filename or die "Can't open file for writing";
# loop over all lines, make substitutions, and print it out
foreach my $line (#lines) {
# assuming a file format with key-value pairs
# keys start at the first column
# and are seperated from values by an '=',
# surrounded by any number of whitespace characters
my ($key, $value) = split /\s*=\s*/, $line, 2;
$value = $arguments{$key} // $value;
# you might want to make sure $value ends with a newline
print $fileOut $key, " = ", $value;
}
}
Please don't use this rather insecure and suboptimal code! I just wrote this as a demonstration that this isn't really complicated.
… or contrieve a way to send your arguments to another script (although Perl is more than well suited for file manipulation tasks). Choose one of the qw{}, system or exec commands, depending on what output you need from your script, or decide to pipe your arguments to the script using the open my $fh, '|-', $command mode of open.
As for the server to run this script on: Apache looks fine to me, unless you have very special needs (your own protocol, single-threading, low security, low performance) in which case you might want to code your own server. Using the HTTP::Daemon module you might manage <50 lines for a simplicistic server.
When using Apache, I'd strongly suggest using mod_rewrite to put the /path into the PATH_INFO environment variable. When using one script to represent your whole REST API, you could use the PATH_INFO to choose one of many methods/subroutines/functions. This also eliminates the need to name the script in the URL.
For example, turn the URL
http://example.com/rest/modify/filename?key1=value1
into
/cgi-bin/rest-handler.pl/modify/filename?key1=value1
Inside the Perl script, we would then have $ENV{PATH_INFO} containing /modify/filename.
This is a bit Perl-centric, but just pick any language you are comfortable with and start coding, leveraging whatever module you can use on the way.
I would use a newer Perl framework, like Mojolicious. If I make a file (test.pl):
#!/usr/bin/env perl
use Mojolicious::Lite;
use Data::Dumper;
my $file = 'file.txt';
any '/' => sub {
my $self = shift;
my #params = $self->param;
my $data = do $file;
$data->{$_} = $self->param($_) for #params;
open my $fh, '>', $file or die "Cannot open $file";
local $Data::Dumper::Terse = 1;
print $fh Dumper $data;
$self->render( text => "File Updated\n" );
};
app->start;
Then run morbo test.pl
and visit http://localhost:3000/?hello=world (or run ./test.pl get /?hello=world)
then I get in file.txt:
{
'hello' => 'world'
}
and so on.
#!/bin/bash
MYSQL="/usr/bin/mysql -uroot "
function create_db()
{
local db_name=${1}
$MYSQL<<!
create database IF NOT EXISTS ${db_name};
!
}
###-------------------------tb_bind_userid_xxx-------------------------------------
function create_table_userid
{
$MYSQL << !
create table if NOT EXISTS bind_pay.tb_bind_userid_${1}(
b_userid bigint not null,
b_membercode bigint not null ,
PRIMARY KEY (b_userid)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
!
}
Will $MYSQL be persistent across function calls,or reconnect each time?
If it reconnects every time,I don't think create_table_userid will work as expected though,because it hasn't specify a database name yet.
Well, because you will be calling the function each time you want to create the table, you will call mysql to connect to the database each time. If you want persistent connection, one way is to use a mysql library that is supported by most major programming languages these days, Perl/Python/Ruby/PHP etc. You can make a DB connection, then do whatever stuff you want, then finally close the connection. for example in the documentation of Python/Mysql
import MySQLdb
conn = MySQLdb.connect (host = "localhost",
user = "testuser",
passwd = "testpass",
db = "test")
cursor = conn.cursor ()
cursor.execute ("SELECT VERSION()")
row = cursor.fetchone ()
print "server version:", row[0]
cursor.close ()
conn.close ()
As you can see, a connection conn is opened to connect to database. Then using the connection handle (or rather database handle), stuff are done and then finally, the connection is closed.
$MYSQL is just a variable, so your code runs mysql each time it calls one of these functions.
You can create a persistant connection to mysql easily enough; just have your program write its sql to output, then pipe the whole results into mysql:
(
create_table "foo"
create_table "bar"
) | mysql
create_table() {
cat <<!
create table $1 ....
!
}
I'm trying to port a Perl script over from Unix to Windows but am having a near impossible time getting it to work due to the unsupported forking pipes in the open function. Here's the code:
sub p4_get_file_content {
my $filespec = shift;
return 'Content placeholder!' if ($options{'dry-run'});
debug("p4_get_file_content: $filespec\n");
local *P4_OUTPUT;
local $/ = undef;
my $pid = open(P4_OUTPUT, "-|");
die "Fork failed: $!" unless defined $pid;
if ($pid == 0) { # child
my $p4 = p4_init();
my $result = undef;
$result = $p4->Run('print', $filespec);
die $p4->Errors() if $p4->ErrorCount();
if (ref $result eq 'ARRAY') {
for (my $i = 1; $i < #$result; $i++) {
print $result->[$i];
}
}
$p4->Disconnect();
exit 0;
}
my $content = <P4_OUTPUT>;
close(P4_OUTPUT) or die "Close failed: ($?) $!";
return $content;
}
The error is:
'-' is not recognized as an internal or external command,
operable program or batch file.
Does anyone know how to make this work? Thanks!
Mike
I know it's not a direct answer to your question, but it looks like you're scripting something on top of Perforce in Perl? If so you might find an existing library does what you want already and save yourself a lot of headaches, or at least give you some sample code to work from.
For example:
P4Perl
P4::Server
P4::C4
EDIT: Now that I know what you're doing I'm guessing you're trying to port p42svn to Windows, or rather make it compatible with Windows at least. See this thread for a discussion of this exact issue. The recommendation (untested) is to try the code samples listed at http://perldoc.perl.org/perlfork.html under "Forking pipe open() not yet implemented" to explicitly create the pipe instead.
It's not going to work as-is. You'll need to find another method to accomplish what it's doing. It doesn't look like there's that burning a need for the fork-pipe, but it's hard to tell since I don't know what a p4 is and a lot of your code is being lost to angle bracket interpretation.