I'm new to PowerShell and have a specific question about working with MySQL in PowerShell.
I got this function:
Function run-mySQLInsertQuery{
param(
$connection,
[string[]]$insertQuery
)
foreach ($command in $insertQuery){
$MySQLCommand = $connection.CreateCommand()
$MySQLCommand.CommandText = $command
$rowsInserted = $MySQLCommand.ExecuteNonQuery()
if ($rowsInserted) {
return $rowsInserted
} else {
return $false
}
}
}
With this version of the function i get the following Error:
Cause:
"The CommandText property has not been properly initialized."
Errorline:
$rowsInserted = $MySQLCommand.ExecuteNonQuery()
I searched for a solution and edited my function a bit to the following (for testing purpose):
Function run-mySQLInsertQuery{
param(
$connection,
[string[]]$insertQuery
)
$abcd = $insertQuery[1]
foreach ($command in $insertQuery){
$MySQLCommand = $connection.CreateCommand()
$MySQLCommand.CommandText = $abcd
$rowsInserted = $MySQLCommand.ExecuteNonQuery()
}
}
With this code, the function executes the query without a problem. My question now is, why? i cant really see a difference, because in $command should be the exact same query like it is in $abcd. Or am I getting something wrong?
EDIT:
As its asked it the comments, here is how i call the function:
[String[]]$statements = ""
foreach($key in $arrayStatus.Keys){
$item = $arrayStatus[$key]
$insertStatus = "INSERT INTO tx_tphbusinessofferings_domain_model_status (status_id, status) VALUES ('$key', '$item')"
$statements += $insertStatus
}
$Rows = run-mySQLInsertQuery -connection $mySQLconnection -insertQuery $statements
The problem is that you are initializing your array (the one you are passing in) with an empty string:
[String[]]$statements = ""
And then adding elements to it... so your first iteration of the passed array is an empty string, which won't work (it'll set the command text as empty, that's the error you are getting). It works on the second code because you are grabbing the second object of the array (which is your insert statement).
Initialize your array to empty and it should work:
[String[]]$statements = #()
Apart from that, your first script always returns on the first iteration, so it'll only work once (not for every insert you pass). Not sure what do you want to return if you are passing in more than one query, but that's up to your design decisions
Related
I was assuming that "return" in PowerShell function will return the value and exit the function, but instead of that I am getting the values for two times!!!!???
Please assist me.
I have a default value, I have logic for retreiving the real value (if exists) but instead I am getting two fules as output - but I do not want that! I need just one value.
Thank you in advance!!!
function GetTenantTagValue($TAG_SET_NAME) {
Write-Host("Tag Set Name:"+$TAG_SET_NAME)
$TAG_SET_VALUE = "N/A"
$TENANT_TAGS = "Customer Code/HEDGE"
$TENANT_TAGS | ForEach-Object {
$TAG_NAME = $_.split("/")[0]
$TAG_VALUE = $_.split("/")[1]
if ($TAG_NAME -eq $TAG_SET_NAME) {
# $TAG_SET_VALUE = $TAG_VALUE
Write-Host("Tag Value:"+$TAG_VALUE)
Write-Host("#########################")
return $TAG_VALUE
}
}
Write-Host("Tag Set Value:"+$TAG_SET_VALUE)
return $TAG_SET_VALUE
}
I invoke the function with:
GetTenantTagValue "Customer Code"
function ExtractLocations([ref]$lp_Locations) {
$lp_Locations.Value = "A STRING VALUE"
return 0
}
...
$Locations = ""
if (#(ExtractLocations([ref]$Locations)) -ne 0) {
RecordErrorThenExit
}
$Locations always ends up as a blank string.
Apart from what #mklemen0 said, to set the value, you need not to do it like $Variable.Value = 'Something' , its just $Variable = 'Something'
With the #() expression, you are converting the output to an array which is not what you need here. Declaring functions similar to methods in c# is not suggested in PowerShell. You could do it like below.
function ExtractLocations{
Param([ref]$lp_Locations)
$lp_Locations = "A STRING VALUE"
return 0
}
ExtractLocations -lp_Locations ([ref]$Locations)
Could not get it working with parameters no matter what I tried so returned the value as a string and that works:
function ExtractLocations
{
....
return $lp_Locations
}
$Locations = ExtractLocations
write "MODIFY $TABLE TO REORGANIZE WITH LOCATION = ($($Locations.value)) \p\g" | sql $SQLFLAGS $TARGETDB
#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils 'uniq';
my %functiontable =();
$functiontable{foo} = \&foo;
sub iterate {
my ($function, $iterations, $argument) = #_;
return $argument unless 0 < $iterations;
return $argument unless $function = $functiontable{$function};
my #functioned = $function->($argument);
my #refunctioned = ();
for my $i (0 .. #functioned - 1) {
push #refunctioned, iterate ($function, ($iterations - 1), $functioned[$i]);
}
return uniq #refunctioned;
}
sub foo {
my ($argument) = #_;
my #list = ($argument, $argument.'.', $argument.',');
return #list;
}
my #results = iterate 'foo', 2, 'the';
print "#results";
This prints the the. the,, i.e. it doesn't iterate (recurse). I would expect it to print the the. the, the.. the., the,. the,,.
(I used Smart::Comments to check whether it enters iterate a second time, and it does, but it doesn't seem to do everything in the function.)
I can't figure out why. Can someone please help me figure out why, or propose a fix?
This line:
return $argument unless $function = $functiontable{$function};
doesn't make sense. In your subroutine iterate, $function is a string and $functiontable{$function} is a reference to a subroutine. I am not sure what the purpose of this is: is it to compare against the stored function? is it to use the function referenced by the name $function?
Assuming the latter it would make more sense to simply pass in a reference to a function when you call iterate:
sub iterate {
my ($function, $iterations, $argument) = #_;
return $argument unless 0 < $iterations;
my #functioned = $function->($argument);
my #refunctioned = ();
for my $i (0 .. #functioned - 1) {
push #refunctioned, iterate ($function, ($iterations - 1), $functioned[$i]);
}
return uniq #refunctioned;
}
my #results = iterate($functiontable{foo}, 2, 'the');
print "#results";
output:
the the. the, the.. the., the,. the,,
The problem is this line.
return $argument unless $function = $functiontable{$function};
The variable $function is being repurposed and overwritten from a string (the function name) to a code reference (the function to be executed). Later, it's passed into iterate which faithfully ignores it.
Two things would improve this code and avoid that sort of problem. First is to not repurpose variables, use two variables.
return $argument unless $function_ref = $functiontable{$function_name};
Now the mistake cannot happen. One strong indicator that you're repurposing a variable is that it changes type, like from a string to a code reference.
Note that I threw out $function entirely because it's too generic in this context. Is that the function's name or the function's reference? Neither one is obvious, so make it obvious.
Finally, iterate can be made more flexible by eliminating the function table entirely. Pass in the code reference directly. If you want a function table, write a wrapper.
sub select_iteration {
my($iteration_type, $iterations, $argument) = #_;
my $iteration_code = $iteration_types{$iteration_type};
return iterate($iteration_code, $iterations, $argument);
}
The first time your subroutine iterate is called it translates the subroutine name in $function from a name to a subroutine reference
So the first time iterate calls itself it is passing the subroutine reference, and the line
return $argument unless $function = $functiontable{$function};
will stringify the reference and attempt to find an element of the hash using a key something like CODE(0x23e0838)
Clearly that element doesn't exist, so your unless fails and $argument is returned immediately without continuing the recursion
Update
I would write something like this
#!/usr/bin/perl
use strict;
use warnings;
use 5.10.0;
my %functions = ( foo => \&foo );
sub iterate {
my ($func, $arg, $depth) = #_;
return $arg unless $depth;
map {iterate($func, $_, $depth - 1); } $functions{$func}->($arg);
}
sub foo {
my ($arg) = #_;
map "$arg$_", '', '.', ',';
}
my #results = iterate('foo', 'the', 2);
say "#results";
output
the the. the, the. the.. the., the, the,. the,,
I'm writing a Perl script that is meant to deal with an API which returns metrics about a set of URLs that I pull from MySQL then post these metrics back into a different table. Currently this piece of code:
my $content = $response->content;
my $jsontext = json_to_perl($content);
my $adsql = 'INSERT INTO moz (url_id,page_authority,domain_authority,links,MozRank_URL,MozRank_Subdomain,external_equity_links) VALUES (?,?,?,?,?,?,?)';
my $adrs = $db->prepare( $adsql );
my $adsql2 = 'UPDATE url
SET moz_crawl_date = NOW()
where url_id = ?;';
my $adrs2 = $db->prepare( $adsql2 );
my $currentUrlId = 0;
foreach my $row (#$jsontext){
$adrs->execute($url_ids[$currentUrlId], $row->{'fmrp'}, $row->{'upa'}, $row->{'pda'}, $row->{'uid'}, $row->{'umrp'}, $row->{'ueid'});# || &die_clean("Couldn't execute\n$adsql\n".$db->errstr."\n" );
$adrs2->execute($url_ids[$currentUrlId]);
$currentUrlId++;
}
is throwing this error:
Not an ARRAY reference at ./moz2.pl line 124.
this is line 124:
foreach my $row (#$jsontext){
this whole chunk of code is in a while loop. I am actually able to iterate a couple times and fill my MySQL table before the script fails (technically the program works, but I don't want to just leave an error in it).
Anybody have any suggestions?
Perl gave you the correct answer
Not an ARRAY reference: #$jsontext
You are dereferencing $jsontext, which is the result of json_to_perl(string), to an array.
But json_to_perl() didn't return an arrayref.
json_to_perl seems to be from this API: http://search.cpan.org/~bkb/JSON-Parse-0.31/lib/JSON/Parse.pod#json_to_perl
which returns according to the doc either an arrayref or a hashref.
Apparently it did return a hashref in your case, so you have to add the logic to deal with the HASH case. Which seems to be a single row.
if (ref $jsontext eq 'HASH') {
# seems to be a single row
$adrs->execute($url_ids[$currentUrlId], $jsontext->{'fmrp'}, $jsontext->'upa'}, $jsontext->'pda'}, $jsontext->'uid'}, $jsontext->'umrp'}, $jsontext->'ueid'});# || &die_clean("Couldn't execute\n$adsql\n".$db->errstr."\n" );
$adrs2->execute($url_ids[$currentUrlId]);
$currentUrlId++;
} elsif (ref $jsontext eq 'ARRAY') {
foreach my $row (#$jsontext){
$adrs->execute($url_ids[$currentUrlId], $row->{'fmrp'}, $row->{'upa'}, $row->{'pda'}, $row->{'uid'}, $row->{'umrp'}, $row->{'ueid'});# || &die_clean("Couldn't execute\n$adsql\n".$db->errstr."\n" );
$adrs2->execute($url_ids[$currentUrlId]);
$currentUrlId++;
}
}
Spent my whole morning trying to find where my return value was getting garbled. Now that I've finally found where, I still have no idea why. Function looks like this:
function Run-RemoteCommand {
param(...) # params are $Remote (host) $Command $Credentials $Quiet (optional switch)
if($Quiet) {
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo.UseShellExecute=$false
$Process.StartInfo.Domain=$Credentials.GetNetworkCredential().Domain
$Process.StartInfo.UserName=$Credentials.GetNetworkCredential().UserName
$Process.StartInfo.Password=$Credentials.Password
$Process.StartInfo.WindowStyle="Hidden"
$Process.StartInfo.FileName=$PSExec
$Process.StartInfo.Arguments=#("/acceptEULA",$Remote,"-s",$Command)
$Process.Start()
$Process.WaitForExit()
$result = $Process.ExitCode
return $result
} else {
...
}
}
What's odd is that I can step through this in a debugger and watch everything work fine. The command runs, $result is filled with the return code, but the calling function receives True appended to the return code (eg True0 on success). I even tried overriding the return value and just saying
return "false"
The calling function receives "Truefalse." All I can tell is that it's tied to $Process running. If I comment out $Process.Start(), the return code functions normally. Someone please save my sanity.
$Process.Start() returns a boolean value which is True if it succeeds. Remember that functions in PowerShell behave differently than standard programming languages. PowerShell functions "return" or more technically correct "output" any command output that isn't captured by a variable or redirected to a file or Out-Null. In this case change the Start line to:
[void]$Process.Start()
or
$Process.Start() | Out-Null
Check out this blog post for a deeper explanation.