PL/Perl trigger cannot use ENV variables defined in .bashrc - postgresql

I'm trying to use an environment variable (for example HOME) inside a PL/perl trigger in postgresql and it appears to be empty.
Running printenv | grep HOME in the terminal returns the desired path.
I am defining the trigger as
CREATE EXTENSION IF NOT EXISTS plperlu;
CREATE OR REPLACE FUNCTION update_solved() RETURNS trigger AS $update_solved$
elog(NOTICE, "Hello");
elog(NOTICE, $ENV{'HOME'});
return;
$update_solved$ LANGUAGE plperlu;
When a query activates the trigger, I get the output
NOTICE: Hello
NOTICE:
I checked what %ENV contains inside the script(using use Data::Dumper;
elog(NOTICE, Dumper(%ENV));:
$VAR1 = 'LANG';
$VAR2 = 'en_US.UTF-8';
$VAR3 = 'LC_TIME';
$VAR4 = 'C';
$VAR5 = 'LC_MONETARY';
$VAR6 = 'C';
$VAR7 = 'PGSYSCONFDIR';
$VAR8 = '/etc/postgresql-common';
$VAR9 = 'PG_GRANDPARENT_PID';
$VAR10 = '513';
$VAR11 = 'PGLOCALEDIR';
$VAR12 = '/usr/share/locale';
$VAR13 = 'LC_CTYPE';
$VAR14 = 'en_US.UTF-8';
$VAR15 = 'LC_COLLATE';
$VAR16 = 'en_US.UTF-8';
$VAR17 = 'PGDATA';
$VAR18 = '/var/lib/postgresql/9.6/main';
$VAR19 = 'LC_MESSAGES';
$VAR20 = 'en_US.UTF-8';
$VAR21 = 'LC_NUMERIC';
$VAR22 = 'C';
$VAR23 = 'PWD';
$VAR24 = '/var/lib/postgresql';
$VAR25 = 'PG_OOM_ADJUST_FILE';
$VAR26 = '/proc/self/oom_score_adj';
Do you know how I can set the env variables that I need that are defined in the terminal session, to be used inside the PL/perl trigger?

Although you are correctly calling the untrusted plperlu variant of PL/Perl, the initial environment is still the same restricted environment as for the normal "trusted" PL/Perl.
One solution would be to run a sub-shell which will then initialise its environment. Something like:
my $home = `bash -lc "echo \$HOME"`;
You may need to tweak the arguments to bash to get what you want. The above command explicitly runs bash as I'm not sure what default shell you are going to have, and you mentioned your .bashrc so the -l might be needed to ensure that gets read.
You could also explicitly read the information you want from an arbitrary text file on the system, which might be easier than messing with environment variables.

Related

How can I pass arguments for a subroutine from the command line

First off, my background is primarily in Python and I am relatively new at using Perl.
I am using tcsh for passing options into my .pl file.
In my code I have:
if( scalar #ARGV != 1)
{
help();
exit;
}
# Loading configuration file and parameters
our %configuration = load_configuration($ARGV[0]);
# all the scripts must be run for every configuration
my #allConfs = ("original");
sub Collimator
{
my $z = -25.0;
my %detector = init_det();
$detector{"pos"} = "0*cm 0.0*cm $z*cm"
}
foreach my $conf ( #allConfs )
{
$configuration{"variation"} = $conf ;
#other geometries ....
Collimator();
}
I want to add something that allows me to change the parameters of the subroutine in the .pl file from the command line. Currently, to generate the geometry I pass the following command into the tcsh CLI: perl file.pl config.dat. What I want is to be able to pass in something like this: perl file.pl config.dat -20.0.
I'm thinking that I need to add something to the effect of:
if($ARGV[1]){
$z = ARGV[1]}
However, I am not sure how to properly implement this. Is this something that I would specify within the subroutine itself or outside of it with the loading of the configuration file?
Use a library to handle command-line arguments, and Getopt::Long is excellent
use warnings;
use strict;
use Getopt::Long;
my ($config_file, #AllConfs);
my ($live, $dry_run) = (1, 0);
my $z;
GetOptions(
'config-file=s' => \$config_file,
'options-conf=s' => \#AllConfs,
'geom|g=f' => \$z,
'live!' => \$live,
'dry-run' => sub { $dry_run = 1; $live = 0 },
# etc
);
# Loading configuration file and parameters
# (Does it ===really=== need to be "our" variable?)
our %configuration = load_configuration($config_file);
my #data_files = #ARGV; # unnamed arguments, perhaps submitted as well
Options may be abbreviated as long as they are unambiguous so with my somewhat random sample above the program can be invoked for example as
prog.pl --conf filename -o original -o bare -g -25.0 data-file(s)
(Or whatever options for #AllConf are.) Providing explicitly g as another name for geom makes it a proper name, not an abbreviation (it doesn't "compete" with others).
Note that one can use -- or just -, and choose shorter or long(er) names for convenience or clarity etc. We get options, and there is a lot more than this little scoop, see docs.
Once the (named) options have been processed the rest on the command line is available in #ARGV, so one can mix and match arguments that way. Unnamed arguments are often used for file names. (The module offers a way to deal with those in some capacity as well.)
if ( #ARGV != 2 ) {
help();
}
my ( $path, $z ) = #ARGV;
perl gets input as list, so you can get its value using #ARGV or using $ARGV[0] and $ARGV[1]
die if ($#ARVG != 1);
#the first argument
print "$ARGV[0]\n";
#the second argument
print "$ARGV[1]\n"

perl parse command line arguments using shift command

I have a question regarding parsing command line arguments and the use of the shift command in Perl.
I wanted to use this line to launch my Perl script
/home/scripts/test.pl -a --test1 -b /path/to/file/file.txt
So I want to parse the command line arguments. This is part of my script where I do that
if ($arg eq "-a") {
$main::john = shift(#arguments);
} elsif ($arg eq "-b") {
$main::doe = shift(#arguments);
}
I want to use then these arguments in a $command variable that will be executed afterwards
my $var1=$john;
my $var2=$doe;
my $command = "/path/to/tool/tool --in $line --out $outputdir $var1 $var2";
&execute($command);
Now here are two problems that I encounter:
It should not be obligatory to specify -a & -b at the command line. But what happens now is that when I don't specify -a, I get the message that I'm using an uninitialized value at the line where the variable is defined
Second problem: $var2 will now equal $doe so it will be in this case /path/to/file/file.txt. However I want $var2 to be equal to --text /path/to/file/file.txt. Where should I specify this --text. It cannot be standardly in the $command, because then it will give a problem when I don't specify -b. Should I do it when I define $doe, but how then?
You should build your command string according to the contents of the variables
Like this
my $var1 = $john;
my $var2 = $doe;
my $command = "/path/to/tool/tool --in $line --out $outputdir";
$command .= " $var1" if defined $var1;
$command .= " --text $var2" if defined $var2;
execute($command);
Also
Don't use ampersands & when you are calling Perl subroutine. That hasn't been good practice for eighteen years now
Don't use package variables like $main:xxx. Lexical variables (declared with my) are almost all that is necessary
As Alnitak says in the comment you should really be using the Getopt::Long module to avoid introducing errors into your command-line parsing
GetOpt::Long might be an option: http://search.cpan.org/~jv/Getopt-Long-2.48/lib/Getopt/Long.pm
Regarding your sample:
You didn't say what should happen if -a or -b are missing, but defaults may solve your problem:
# Use 'join' as default if $var1 is not set
my $var1 = $john // 'john';
# Use an empty value as default if $var2 is not set
my $var2 = $doe // '';
Regarding the --text prefix:
Do you want to set it always?
my $command = "/path/to/tool/tool --in $line --out $outputdir $var1 --text $var2";
Or do you want to set it if -b = $var2 has been set?
# Prefix
my $var2 = "--text $john";
# Prefix with default
my $var2 = defined $john ? "--text $john" : '';
# Same, but long format
my $var2 = ''; # Set default
if ($john) {
$var2 = "--text $john";
}

Setting variables in perl config file eval

I've got a perl script and a .config file and want to store some hashes in the config file with some variables as its value, then dynamically change them from my perl script.
Config File:
$hash{"hello"} = ["$blah", "$blah2"];
And my perl script:
if (-e ".config")
{
$blah = "hello";
$blah2 = "world!";
eval ('require(".config")');
$val1 = $hash{"hello"}[0];
$val2 = $hash{"hello"}[1];
print "$val1 $val2\n";
# Now I want to CHANGE blah and blah2
$blah = "world!";
$blah2 = "hello";
$val1 = $hash{"hello"}[0];
$val2 = $hash{"hello"}[1];
print "$val1 $val2\n";
}
But both prints show hello world! as if the change didn't happen.. Am I missing something?
Thanks.
(Strange... I've never seen a question of this sort previously, and then variations on it (which are different enough to clearly not be just a cross-post) appeared both here and on PerlMonks in the same day.)
The point you're missing is that
$hash{"hello"} = ["$blah", "$blah2"];
just copies the values of $blah and $blah2 into (an anonymous array referenced by) $hash{hello}. It does not create any lasting connection between the hash and $blah/$blah2.
As a side note, none of the quotes in that line serve any purpose. It would more commonly be written as:
$hash{hello} = [$blah, $blah2];
Or, if you want to create references so that $blah and $hash{hello}[0] are forever linked and changing one will also change the other:
$hash{hello} = [\$blah, \$blah2];
Note that in this case, you must not use quotes. Although "$blah" and $blah are equivalent, "\$blah" and \$blah are not - \$blah gives you a reference to $blah, but "\$blah" gives you the literal string "$blah" with no variables involved at all.

Why is this hash not displaying correctly?

after being sick for a few week I am trying to get back into my scripting projects and seems to be running into a newbie speed bump.
I am trying to assemble a script to slurp a file and then process parameters from the file using regex and build a hash from parameters found.
But the problem I am running into is the hash is not being constructed the way I want it, or atleast I think it is not.
Here is the tiny script I am working on.
#!/usr/bin/perl
use strict;
use warnings;
use File::Slurp;
use Data::Dumper;
my %config;
my $text = read_file("./config/settings.cfg");
if ($text =~ /^esxi\.host\s+=\s+(?<host>.+)/xm) {
$config{host} = "$+{host}";
}
print Dumper (%config);
For those wishing to execute the script here is the config file I am building
Connection Options:
######################################################
esxi.host = server01
esxi.port = 22
esxi.username = root
esxi.password = password
######################################################
Backup Options:
#########################
Compression Options:
0 = none
1 = tar
2 = gzip
3 = tar+gzip
#########################
backup.compression = 0
Just save it to a file called settings.cfg unless you feel like changing the parameter in the script.
Anyhow this is the output I am getting from Data::Dumper.
$VAR1 = 'server01';
$VAR2 = {
'host' => 'esxi01'
};
What I am trying to do is make server01 the root key of the hash and host a subkey because I will also have subkeys for user, password, and port number.
I have been chewing on this for about a half hour (partly distracted) trying to figure out why it is not working, any help would be most appreciated.
Are you wanting output like this?
$VAR1 = {
'server01' => {
'host' => 'esxi01'
}
};
If so, your %config is fine. Your problem is you're passing a hash (which gets interpreted as an array a list) rather than a hashref to Dumper. Try Dumper(\%config) instead.

How can I suppress Excel's password prompt in Perl?

Please tell me a solution to suppress passsword prompting of an excel file.
use Win32::OLE;
my $xlApp = Win32::OLE->new('Excel.Application');
$xlApp->{Visible} = 0;
$xlApp->{DisplayAlerts} = 0;
# Open excel file.
my $xlBook = $xlApp->Workbooks->Open("C:\\Documents and Settings\\username\\Desktop\\testfile.xls");
my $Sheet1 = $xlBook->Worksheets(1);
my $row = 1;
my $col = 1;
$Sheet1->Cells($row,$col)->{'Value'} = 5;
if (Win32::OLE->LastError)
{
print "File protected";
}
$xlBook ->Close();
undef $xlBook;
If you know the passwords, you can supply them in the password and/or writerespassword arguments of the open command. Excel will not prompt for the passwords if they are supplied this way.
If you don't know the passwords but want to prevent the dialog box from appearing, you can supply dummy passwords in these parameters ("ThisIsNotAPassword", for instance). I have not found this in the documentation, but tested it in Excel 2003:
If the Excel file does not have passwords, it is opened.
If it does have passwords (other than those supplied), it will not ask the user for a password, but fail with an error you can detect.
You may convert the following vb code to perl and give a try,
Please note that this code is for vbproject, similary you can check for the worksheets, cells, or entire sheet, the same way.
' returns TRUE if the VB project in the active document is protected
' Please not
Function ProtectedVBProject(ByVal wb As Workbook) As Boolean
Dim VBC As Integer
VBC = -1
On Error Resume Next
VBC = wb.VBProject.VBComponents.Count
On Error GoTo 0
If VBC = -1 Then
ProtectedVBProject = True
Else
ProtectedVBProject = False
End If
End Function
Example:
If ProtectedVBProject(ActiveWorkbook) Then Exit Sub
For Worksheet
If ActiveWorkbook.ProtectStructure=True Then Exit Sub
For active work book windows
If ActiveWorkbook.ProtectWindows= True Then Exit sub
and so on..
Or You can open excel sheet with password
The Open method for the Workbook
object, takes 12 arguments. To open a workbook with password protection, you would need to write the following code:
Workbooks.Open "Book1.xls", , , ,"pswd"
You can also check with perl the same with empty arguments. I am not sure how to give...
Working off of lakshmanaraj's idea, and unknown's response:
use Win32::OLE;
sub is_protected_vb_project {
my $work_book = shift;
eval {
my $count = $work_book->{VBProject}{VBComponents}{Count};
};
Carp::carp $# if $#;
return $# ? 1 : 0;
}
my $work_book = Win32::OLE->GetObject( 'd:/some/path/somewhere.xls' );
printf "is_protected_vb_project( \$work_book )=%s\n"
, is_protected_vb_project( $work_book )
;