#!/usr/bin/perl
use DBI;
$fund=103;
$mobile_number1="7700009896";
$city_address="hello word";
$sql_query3=(qq{ exec "INSERT INTO [192.168.14.28].CommunicationLog.dbo.sms_processedfeeds (pf_Fund,pf_trtype,pf_acno,pf_ihno,pf_Mobile,pf_msgtrtype,pf_msg,pf_entdt) VALUES ($fund,'CALL',0,NULL,'$mobile_number1','CALL','$city_address',Getdate())"});
my $sql_sms = $dbh->prepare($sql_query3);
$sql_sms->execute();
I'm getting the following error:
DBD::ODBC::db prepare failed: [unixODBC][FreeTDS][SQL Server]The identifier that starts with 'INSERT INTO [192.168.14.28].CommunicationLog.dbo.sms_processedfeeds (pf_Fund,pf_trtype,pf_acno,pf_ihno,pf_Mobile,pf_msgtrtype,pf' is too long. Maximum length is 128. (SQL-42000)
[unixODBC][FreeTDS][SQL Server]Statement(s) could not be prepared. (SQL-42000) at Mobile_verification.pl line 8.
Can't call method "execute" on an undefined value at Mobile_verification.pl line 9.
You don't need exec and the nested quotes in the statement. Use this instead
my $mobile_number1_lit = $dbh->quote($mobile_number1);
my $city_address_lit = $dbh->quote($city_address);
$sql_query3 = <<END_SQL;
INSERT INTO [192.168.14.28].CommunicationLog.dbo.sms_processedfeeds (pf_Fund, pf_trtype, pf_acno, pf_ihno, pf_Mobile, pf_msgtrtype, pf_msg, pf_entdt)
VALUES ($fund, 'CALL', 0, NULL, $mobile_number1_lit, 'CALL', $city_address_lit, Getdate())
END_SQL
my $sql_sms = $dbh->prepare($sql_query3);
$sql_sms->execute;
or, preferably, use placeholders in the prepare and pass the parameters to execute, like this
$sql_query3 = <<'END_SQL';
INSERT INTO [192.168.14.28].CommunicationLog.dbo.sms_processedfeeds (pf_Fund, pf_trtype, pf_acno, pf_ihno, pf_Mobile, pf_msgtrtype, pf_msg, pf_entdt)
VALUES (?, 'CALL', 0, NULL, ?, 'CALL', ?, Getdate())
END_SQL
my $sql_sms = $dbh->prepare($sql_query3);
$sql_sms->execute($fun, $mobile_number1, $city_address);
I'm not familiar with exec, but the message says the first argument should be an identifier, not a SQL query. If you meant to use the exec SQL command, you're misusing it.
But you say you want to perform an INSERT, so maybe you didn't mean to use EXECUTE at all. An INSERT would look like:
my $stmt = "
INSERT INTO [192.168.14.28].CommunicationLog.dbo.sms_processedfeeds (
pf_Fund,
pf_trtype,
pf_acno,
pf_ihno,
pf_Mobile,
pf_msgtrtype,
pf_msg,
pf_entdt
) VALUES (
?,?,?,?,?,?,?,Getdate()
)
";
my $sth = dbh->prepare($stmt);
$sth->execute(
$fund,
'CALL',
0,
undef,
'$mobile_number1',
'CALL',
$city_address,
);
Note: You could replace prepare+execute with $dbh->do($stmt, undef, ...data...);
Note: I'm assuming [192.168.14.28].CommunicationLog.dbo.sms_processedfeeds is a valid table designation.
Related
I have used the following code many times before when inserting values into database tables using perl
my $SRV='xxx';
my $DB='dbname';
my $db = DBI->connect("dbi:Oracle:$SRV/$DB", "user", "pword" ) or die "impossible de se connecter à $SRV / $DB";
my $insert_T1 = "INSERT INTO tablename (ColA, ColB) VALUES ( ?, ?) " ;
my $insert_T1_sth = $db->prepare($insert_T1) ;
Later in the code I can then call the following to do the insertion
$insert_T1_sth->execute('val1','val2');
$insert_T1_sth->execute('val3','val4');
So basically when I use the prepare function above I can replace the entries I want to insert by question marks and then put the values of these question marks in the execute statements later on.
So to my question: Can I use question marks in place of column names in the prepare statement? I'm thinking no because when I try the following I get a runtime error on the line where the execute statement(s) are.
my $SRV='xxx';
my $DB='dbname';
my $db = DBI->connect("dbi:Oracle:$SRV/$DB", "user", "pword" ) or die "impossible de se connecter à $SRV / $DB";
$db->{AutoCommit} = 0 ;
my $insert_T1 = "INSERT INTO tablename (ColA, ?) VALUES ( ?, ?) " ;
my $insert_T1_sth = $db->prepare($insert_T1) ;
Then later, as before, use
$insert_T1_sth->execute('colname1','val1','val2');
$insert_T1_sth->execute('colname2','val3','val4');
You can't use dynamic column names with prepare like you are trying to do.
Your column names shouldn't be known to the user, and therefore don't really need to be part of the parameters, since they are not sensitive (and don't need to be protected against SQL injection). Preparing is still useful for performances though.
What I'd suggest is to do a prepare for each of you column name, and store those in a hash:
my #col_names = qw(colname1 colname2);
my %inserts;
for my $col (#col_names) {
$inserts{$col} = $db->prepare("INSERT INTO tablename (ColA, $col) VALUES (?, ?)");
}
...
$inserts{colname1}->execute('val1', 'val2');
# I am saving output to an array and the array looks like this:-
60=20130624-09:45:02.046|21=1|38=565|52=20130624-09:45:02.046|35=D|10=085|40=1|9=205|100=MBTX|49=11342|553=2453|34=388|1=30532|43=Y|55=4323|54=1|56=MBT|11=584|59=0|114=Y|8=FIX.4.4|
# Then i converted this array to scalar variable like this:-
$scal=join('' , #arr);
# And now I am trying to save this into db:-
my $st = qq(INSERT INTO demo (fix)
VALUES ($scal));
my $r = $dbh->do($st) or die $DBI::errstr;
#And my table schema is:-
CREATE TABLE demo (fix varchar);
And I keep getting errors :- DBD::SQLite::db do failed: near ":45": syntax error at pdb.pl line 92, <STDIN> line 1.
DBD::SQLite::db do failed: near ":45": syntax error at pdb.pl line 92, <STDIN> line 1.
Any help will be appreicated
The way you denote your array is a bit weird. Usually you would write it as
my #arr = ( '60=20130624-09:45:02.046',
'21=1',
'38=565',
... );
or whatever your actual content is. But this is not the problem here because you flatten it to the string $scal anyway.
One way to insert this string into your DB is to put ticks (') around it:
my $st = qq(INSERT INTO demo (fix) VALUES ('$scal'));
my $r = $dbh->do($st) or die $DBI::errstr;
But this is bad because it's vulnerable to SQL injection (http://imgs.xkcd.com/comics/exploits_of_a_mom.png).
Consider the case your string is foo'); delete from demo; --. The final result would then be
INSERT INTO demo (fix) VALUES ('foo'); delete from demo; --')
The second reason why this is bad: Your string could contain ticks ($scal="foo's bar") and that also would mess up the resulting INSERT statement:
INSERT INTO demo (fix) VALUES ('foo's bar');
Conclusion: it's always better to use parameterized queries:
my $st = 'INSERT INTO demo (fix) VALUES (?)';
my $r = $dbh->do($st, undef, $scal) or die $DBI::errstr;
The undef is for additional SQL options (I've rarely seen anything different from undef here). The following parameters are replaced for the ?s in the statement. The DB driver does all the quoting for you. The more ? you use, the more parameters you must supply to do():
my $st = 'INSERT INTO sample_tbl (col1, col2, col3) VALUES (?, ?, ?)';
my $r = $dbh->do($st, undef, 'foo', 42, $scal) or die $DBI::errstr;
i am getting below error while running below perl script. Can anybody help to figure it out?
$ENV{PATH}= '/appl/OMS/scripts:/etc:/usr/bin:/usr/sbin:/b...';
$ENV{PATH}= '/appl/OMS/scripts:/etc:/usr/bin:/usr/sbin:/bin:/usr/local/bin:/usr/local/opt/oracle/client/11.2.0.4/bin';
$ENV{ORACLE_HOME} ='/usr/local/opt/oracle/client/11.2.0.4';
$ENV{NLSPATH} = '/usr/lib/nls/msg/%L/%N:/usr/lib/nls/msg/%L/%N.cat';
$ENV{CLASSPATH} = 'CLASSPATH=/usr/local/opt/oracle/client/11.2.0.4/jdbc/lib';
$ENV{JAVA_HOME} = '/appl/OMS/Software/java';
$ENV{PERL5LIB} = '/appl/OMS/perl/lib';
use lib "/appl/OMS/perl/lib";
}
use DBI;
use DBD::Oracle;
use Data::Dumper;
use POSIX qw/strftime/;
use Switch;
use Term::ANSIColor;
print " Input the environment name:\n";
chomp($env=<STDIN>);
print " Input attuid:\n";
chomp($attuid=<STDIN>);
print " Input first name:\n";
chomp($fname = <STDIN>);
print " Input last name:\n";
chomp($lname= <STDIN>);
#chomp($lname);
my $dbInst="t1oms4d8.db.att.com";
my $dbUser="OMS1AT01utils";
my $dbPass="pswd4conn";
my $host = "t1oms5c1.sldc.sbc.com";
#$dsn= "dbi:oracle:T2OMS1D4.db.att.com:t2oms1c1.hydc.sbc.com:1521";
#$DBIconnect= DBI->connect($dsn,OMS0BT08utils,Pwd0wner1);
my $dbh=DBI->connect("dbi:Oracle:$dbInst", $dbUser, $dbPass);
my $sth = $dbh->prepare('create table temp_table1 as (select * from users where user_id like '%SR508W%')');
$sth-> execute();
print "test1";
my $sth = $dbh->prepare("update temp_table1 set user_id= ".$attuid.", first_nm= ".$fname.", last_nm= ".$lname." where user_id like '%SR508W%' " );
$sth-> execute();
print "test2";
my $sth = $dbh->prepare("insert into users (select * from temp_table1)");
$sth-> execute();
my $sth = $dbh->prepare("insert into user_password(user_id,password1) values (".$attuid." ,(select PASSWORD1 FROM user_password where user_id like '%SR508W%'))");
$sth-> execute();
my $sth = $dbh->prepare("insert into user_role(user_id,role_id) values (".$attuid." ,'1')");
$sth-> execute();
my $sth = $dbh->prepare("select * from temp_table1");
$sth-> execute();
my $sth = $dbh->prepare("drop table temp_table1");
$sth->execute();
$sth->finish();
$dbh->commit or die $DBI::errstr;
I am running the script as below:
$ ./dbtrial.pl
Input the environment name:
oms1at01
Input attuid:
sm501u
Input first name:
swapnil
Input last name:
mahindrakar
The error message is the following:
DBD::Oracle::st execute failed: ORA-00904: "MAHINDRAKAR": invalid identifier (DBD ERROR: error possibly near <*> indicator at char 69 in 'update temp_table1 set user_id= sm501u, first_nm= swapnil, last_nm= <*>mahindrakar where user_id like '%SR508W%' ') [for Statement "update temp_table1 set user_id= sm501u, first_nm= swapnil, last_nm= mahindrakar where user_id like '%SR508W%' "] at ./dbtrial.pl line 45, <STDIN> line 4.
DBD::Oracle::st execute failed: ORA-00984: column not allowed here (DBD ERROR: error possibly near <*> indicator at char 53 in 'insert into user_password(user_id,password1) values (<*>sm501u ,(select PASSWORD1 FROM user_password where user_id like '%SR508W%'))') [for Statement "insert into user_password(user_id,password1) values (sm501u ,(select PASSWORD1 FROM user_password where user_id like '%SR508W%'))"] at ./dbtrial.pl line 50, <STDIN> line 4.
DBD::Oracle::st execute failed: ORA-00984: column not allowed here (DBD ERROR: error possibly near <*> indicator at char 47 in 'insert into user_role(user_id,role_id) values (<*>sm501u ,'1')') [for Statement "insert into user_role(user_id,role_id) values (sm501u ,'1')"] at ./dbtrial.pl line 52, <STDIN> line 4.
commit ineffective with AutoCommit enabled at ./dbtrial.pl line 58, <STDIN> line 4.
test1test2----- websphe cldv0011 /appl/OMS/scripts/trials ---
Apart from missing a #! /usr/bin/perl (or similar) line, the most obvious thing wrong with your script is that you're not properly quoting your variables when you use them in SQL statemnents.
The easiest way to fix that is to use placeholders (?) in your $dbh->prepare() statements. And then supply the actual values in the $sth-execute()
For example:
my $sth = $dbh->prepare("update temp_table1 set user_id=?,
first_nm=?, last_nm=?
where user_id like '%SR508W%'");
$sth->execute($attuid,$fname,$lname);
This will automagically quote the variables that need quoting, which seems to be all of them for this example as they're all string values.
Also, you only have to define the scope of your variables once. You don't need to (and shouldn't) say my $sth= every time you set it to a new value. Either declare it separately before using it at all (with just my $sth;, or only declare it the very first time you use it.
And add a blank line or two to separate each different section of the script. That will make it MUCH easier to read than the ugly wall of text it is now.
Finally, you might want to consider taking the input from the command line. This will make testing much easier as you can use your shell's command-line history and recall features (i.e. hit up arrow and enter to execute the same command again) rather than having to enter the same four values into the script every time you run it. e.g.
# environment name is first arg
my $env = shift;
# attuid is second arg
my $attuid = shift;
# First name is third arg
my $fname = shift;
# Last name is fourth arg
my $lname = shift;
Run it like this:
$ ./dbtrial.pl oms1at01 sm501u swapnil mahindrakar
(Note: this is really primitive argument handling. Use Getopt::Std or Getopt::Long if you need something better than just taking the first four args from the command line).
Personally, I'd be inclined to rewrite your script to something more like this (with better formatting, removal of variables and modules that aren't used, better usage of DBI features, and improved sql string construction):
#! /usr/bin/perl
use strict;
use warnings;
use lib "/appl/OMS/perl/lib";
use DBI;
use DBD::Oracle;
my ($env,$attuid,$fname,$lname);
# environment name is first arg
$env = shift;
# attuid is second arg
$attuid = shift;
# First name is third arg
$fname = shift;
# Last name is fourth arg
$lname = shift;
my ($dbInst, $dbUser, $dbPass, $host, $dbh, $sth, $sql, $where);
$dbInst="t1oms4d8.db.att.com";
$dbUser="OMS1AT01utils";
$dbPass="pswd4conn";
$dbh=DBI->connect("dbi:Oracle:$dbInst",$dbUser,$dbPass);
$where=' where user_id like \'%SR508W%\'';
$dbh->do('create table temp_table1 as (select * from users ' . $where . ')');
print "test1";
$sql = 'update temp_table1 set user_id=?, first_nm=?, last_nm=?' . $where;
$sth = $dbh->prepare($sql);
$sth->execute($attuid,$fname,$lname);
print "test2";
$dbh->do('insert into users (select * from temp_table1)');
$sql = 'insert into user_password(user_id,password1) values (?,(select PASSWORD1 FROM user_password' . $where . ' ))';
$sth = $dbh->prepare($sql);
$sth->execute($attuid);
$sql = 'insert into user_role(user_id,role_id) values (?,?)';
$sth = $dbh->prepare($sql);
# does '1' need to be quoted here? if field is a varchar or similar then yes, otherwise no. assuming yes as in the original script.
$sth->execute($attuid,'1');
$dbh->do('select * from temp_table1');
$dbh->do('drop table temp_table1');
$sth->finish();
$dbh->commit or die $DBI::errstr;
$dbh->finish();
I recently had some help with dbi and using placeholders in Perl for Mysql queries. However I am having an issue when using multiple statements for the previously declared or prepared variable in the dbi script.
Code:
use strict;
use warnings;
use DBI qw(:sql_types);
my $dbh = DBI->connect("DBI:mysql:...", ...);
## TABLE CREATION
$dbh->do("USE test;")
$dbh->do("CREATE TEMPORARY TABLE day5 (id INT, temp VARCHAR(4), time TIME, sumadd INT(11))");
$dbh->do("CREATE TEMPORARY TABLE humid (temp VARCHAR(4), i24 INT (10))");
$dbh->do("INSERT INTO day5 (id,temp,time) VALUES(1,'30','03:00:00') ");
$dbh->do("INSERT INTO humid (temp,i24) VALUES('30',8321) ");
## FAILING CODE
my $inter1 = 'i24'; # Generated value
my $sth = $dbh->prepare("SET \#sumadd5 = (SELECT ? FROM humid WHERE temp ='30') ");
$sth->bind_param( 1, $inter1 );
$sth->finish();
$dbh->do("UPDATE day5 SET sumadd= (SELECT \#sumadd5) WHERE time= '03:00:00' ");
my $sumadd = $dbh->selectrow_array("SELECT sumadd FROM day5");
print "$sumadd\n";
$dbh->disconnect();
$sumadd is undefined, but I expect 8321.
My question is how can I make it so the #sumadd5 variable can be inserted into the above query [UPDATE day5 SET sumadd=]? I have added some remarks in the syntax in the spirit of clarity.
IF I RUN MANUALLY BY APPLYING THE SYNTAX INTO MYSQL REMOVING PERL SPECIFICS MY TABLE UPDATE. IF I RUN THE SCRIPT NOTHING HAPPENS TO THE TABLE AND NO ERRORS ARE DISPLAYED.
I suspect that the break is with the UPDATE, however I can't confirm the $inter1 is being passed to the placeholder.
Problem #1
You never execute the statement you prepare. Use
my $sth = $dbh->prepare(q{...});
$sth->bind_param(1, $inter1);
$sth->execute(); <---
$sth->finish();
Shortcut #1:
my $sth = $dbh->prepare(q{...});
$sth->execute($inter1);
$sth->finish();
Shortcut #2:
$dbh->do(
q{...},
undef,
$inter1,
);
Problem #2
SELECT ? ...
behaves as if you had done
SELECT "i24" ... // As opposed to: SELECT i24 ...
just like
SELECT time ...
behaves as if you had done
SELECT '03:00:00' ...`
You can't build the SQL statement you are executing. You need to build it before you execute it. Use
$dbh->do(q{
SET #sumadd5 = (
SELECT }.( $dbh->quote_identifier($inter1) ).q{
FROM humid
WHERE temp = '30'
)
});
I want to insert values into Sqlite3 table using Perl DBI. I was able to insert hard coded values without any problem. When I tried to use perl variables, then I get an error "DBD::SQLite::db do failed: no such column:"
This works:
$dbh->do("insert into Gene values (12, 'AAAAAA', 66, 86, 76)");
But this code
$dbh->do("INSERT INTO Gene values (NULL, $sequence, $siteNumber, $begin, $length)");
throws the error
DBD::SQLite::db do failed: no such column
You should always prepare and execute your SQL statements and use placeholders for variable values as a matter of course.
Try this code
my $sth = $dbh->prepare('INSERT INTO Gene VALUES (?, ?, ?, ?, ?)');
$sth->execute(undef, $sequence, $siteNumber, $begin, $length);
Your problem will have been at $sequence, which required quoting to be a valid SQL string literal in the insert statement. As a result it thought you were trying to refer to a column called AAAAAA, and not the string 'AAAAAA' that you intended. Perl's string interpolation doesn't add the quotes for you.
Placeholders and $dbh->prepapre are by far the most robust solution here though (for example, what to do if your string contains the quote character ' ? $dbh->prepare already has that coded correctly).