PostgreSQL, Perl, DBD and the Insert command with "TO_TIMESTAMP" - perl

I'm programming a script which queries some devices and writes the data to a PostgreSQL database.
The data includes a date which is formatted like 31.12.2015 13:45:00. The database uses the DateType "German" and the column is of the type Timestamp without timezone.
I always get this error message
DBD::Pg::st execute failed: ERROR: invalid input syntax for type timestamp:
"TO_TIMESTAMP('19.06.2015 11:24:20','DD.MM.YYYY HH24:MI:SS')::timestamp without time zone"
at temp_alcp2e_db.pl line 80, line 289.
I'm using this code, where $date_db has the date value:
$date_db = 'TO_TIMESTAMP(\'' . $date_db . '\',\'DD.MM.YYYY HH24:MI:SS\')::timestamp without time zone';
$stmt = $dbh->prepare("INSERT INTO rifutemp (\"USER_LINK_ID\", \"IP\", \"DATUM\", \"TEMPERATURE\") VALUES (?, ?, ?, ?)");
$stmt->execute($key_bgtr, $key_ip, $date_db, $temperatur) or die $DBI::errstr;
Hopefully, someone can show me what I did wrong.

The function can (and must) be part of the prepared statement.
Re-write your code as follows:
$stmt =$dbh->prepare(q{
INSERT INTO rifutemp ("USER_LINK_ID","IP","DATUM","TEMPERATURE")
VALUES (?, ?,
TO_TIMESTAMP(?, 'DD.MM.YYYY HH24:MI:SS')::timestamp without time zone,
?)
});
$stmt->execute($key_bgtr,$key_ip,$date_db,$temperatur) or die $DBI::errstr;

Ok, I've found my problem / the source of the errors:
To manage the Database visually I'm using the "EMS SQL Manager Lite for PostgreSQL", and this nice GUI tool always sets the DateStyle options to "ISO, MDY".
I've just changed my code like this:
$dbh->do("SET datestyle = 'German'");
$stmt =$dbh->prepare("INSERT INTO rifutemp (\"USER_LINK_ID\",\"IP\",\"DATUM\",\"TEMPERATURE\")
VALUES (?, ?, ?, ?)");
$stmt->execute($key_bgtr,$key_ip,$date_db,$temperatur) or die $DBI::errstr;
and set the $date_db variable to the correct format:
$date_db = Time::Piece->new->strftime('%d.%m.%Y %H:%M:%S');
and now everything works fine!

Related

perl dbi prepare with variable table column name

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');

How to insert Perl variables into Sqlite3

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

Calling prepare with mysqli - SQL syntax error

$q2 = "UPDATE `tasks` SET `title` = ?, task = ?, rules = ?, media = ?, type = ?, xp = ?, available = ?, timestamp = ? WHERE id = ?";
if ($stmt = $mysqli->prepare($q2)) {
$stmt->bind_param("sssssissi", $_POST["tasktitle"], $_POST["editor"], $_POST["rules"], serialize($_POST["media"]), $_POST["type"], $_POST["xp"], $a = 0, strtotime("now"), $_GET['id']);
$stmt->execute();
$stmt->close();
}
$r = $mysqli->query($q2) or die($mysqli->error);
I got this error msg:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?, task = ?, rules = ?, media = ?, type = ?, xp = ?, available = ?, timestamp = ' at line 1
What is problem, and how can i solve it?
I'm pretty certain it's coming from the call to $mysqli->query() which needs a properly escaped query (ie, none of that nice safe parameter stuff). That explains why it's complaining at the first ?.
Quick way to check is to actually comment out the entire if statement and se if the error still appears. If so, you know it's the query rather than the prepared statement execution.
My question to you is: why are you executing the prepared statement and then trying to run it again as a query?
I think you'll find the execute does your update quite well enough. Get rid of the call to query and you should be fine.

I'm not able to execute insert command inside perl script?

#!/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.

String getting converted to number when inserting it in database through Perl's DBI $sth->execute() function

I'm using Perl's DBI and SQLite database (I have DBD::SQLite installed). I have the following code:
my $dbh = DBI->connect("dbi:SQLite:dbname=$db", "", "", { RaiseError => 1, AutoCommit => 1 });
...
my $q = "INSERT OR IGNORE INTO books (identica, book_title) VALUES (?, ?)";
my $sth = $dbh->prepare($q);
$sth->execute($book_info->{identica}, $book_info->{book_title});
The problem I have is when $book_info->{identica} begins with 0's they get dropped and I get a number inserted in the database.
For example, identica of 00123 will get converted to 123.
I know SQLite doesn't have types, so how do I make DBI to insert the identica as string rather than number?
I tried quoting it as "$book_info->{identica}" when passing to $sth->execute but that didn't help.
EDIT
Even if I insert value directly in query it doesn't work:
my $i = $book_info->{identica};
my $q = "INSERT OR IGNORE INTO books (identica, book_title) VALUES ('$i', ?)";
my $sth = $dbh->prepare($q);
$sth->execute($book_info->{book_title});
This still coverts 00123 to 123, and 0000000009 to 9...
EDIT
Holy sh*t, I did this on the command line, and I got this:
sqlite> INSERT INTO books (identica, book_title) VALUES ('0439023521', 'a');
sqlite> select * from books where id=28;
28|439023521|a|
It was dropped by SQLite!
Here is how the schema looks:
CREATE TABLE books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
identica STRING NOT NULL,
);
CREATE UNIQUE INDEX IDX_identica on books(identica);
CREATE INDEX IDX_book_title on books(book_title);
Any ideas what is going on?
SOLUTION
It's sqlite problem, see answer by in the comments by Jim. The STRING has to be TEXT in sqlite. Otherwise it treats it as number!
Changing schema to the following solved it:
CREATE TABLE books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
identica TEXT NOT NULL,
);
Use bind params
my $sth = $dbh->prepare($q);
$sth->bind_param(1, 00123, { TYPE => SQL_VARCHAR });
$sth->bind_param(2, $book_info->{book_title});
$sth->execute();
UPDATE:
Read about type affinity in SQLite. Because your column type is STRING (technically unsupported), it defaults to INTEGER affinity. You need to create your column as TEXT instead.
According to the docs, if the column type (affinity) is TEXT it should store it as a string; otherwise it will be a number.