Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

DBI isn't using default row values

by exceltior (Initiate)
on Nov 28, 2016 at 14:07 UTC ( [id://1176704]=perlquestion: print w/replies, xml ) Need Help??

exceltior has asked for the wisdom of the Perl Monks concerning the following question:

Hey,
I'm using DBI to put my data on a table that has defaults values (like tinyint(1) ;default -> 0) if not set. The problem is that DBI doesn't seem to interpret ''as to use the default value instead.
Error I get is:
FATAL DBD::mysql::db do failed: Incorrect integer value: '' for column + 'debug_objretry_override' at row 1

Any thoughts?

Replies are listed 'Best First'.
Re: DBI isn't using default row values
by Corion (Patriarch) on Nov 28, 2016 at 14:09 UTC

    You don't pass an empty string to SQL to make it use the default values. You have to not pass the parameter at all, or maybe pass NULL to make SQL use the default value.

    Maybe you can show us your SQL statement and the placeholder values you're using? Also please show us the constraints on the relevant column(s) and the default statement.

    Update: See Marshall's reply below with some relevant code and some experimental evidence that a column cannot take an explicit value if you want the default to be used.

Re: DBI isn't using default row values
by Marshall (Canon) on Nov 28, 2016 at 17:13 UTC
    I am curious about what you are doing...defaults values (like tinyint(1) ;default -> 0) doesn't look like SQL to me. A do statement that creates a table with default values would look something like below. The default value is a property of the table when it is created:
    $dbh->do ("CREATE TABLE ScoreCard ( id integer PRIMARY KEY AUTOINCREMENT, Url varchar(80) DEFAULT '', Score integer DEFAULT 0, Club varchar(30) DEFAULT '' ); ");
    When executing a pre-prepared insert statement with place holders, '' would be an empty string, which is not an integer. In order to get the Score default of zero, I figure that variable needs to be undef. Without seeing code, I'm not sure what you have.

    I should mention a nice feature added in Perl 5.10.

    $score //= 0; #set to zero if undef
    I often have other Perl validation code before the insert and this feature comes in handy. Often my table defaults wind up essentially being, "if all else fails". Mileage varies a lot.

    Update: I just did a quick cut-n-paste for the above CREATE. There are other constraints, like NOT NULL that I often use with varchar(). The main point I wanted to show was the zero default for an integer. That does not look like ";default -> 0"

    Update 2:
    An attempt to reproduce the OP's problem yields more questions.
    What is the "right way" to coerce the DBI into using the DEFAULT value when using placeholders? Here is some runable code. I tried the obvious things like no parm, undef, null but couldn't get SQLite to use the default value. I'm sure I'm missing something obvious. But at least here is some code that can be run and modified...

    #!/usr/bin/perl use strict; use warnings; $|=1; #turn STDIO buffering off use Data::Dump qw(pp); use DBI; my $dbfile = "./monk_test.sqlite"; unlink $dbfile if -e $dbfile; my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","","",{RaiseError = +> 1}) or die "Couldn't connect to database: " . DBI->errstr; $dbh->do ("CREATE TABLE ScoreCard ( id INTEGER PRIMARY KEY AUTOINCREMENT, Score INTEGER DEFAULT 11 ); "); my $insert_row = $dbh->prepare("INSERT INTO ScoreCard(Score) + VALUES(?)"); # desired goal: get Score in the DB to be 11 if its not specified. $insert_row->execute(); #row 1 Score=undef $insert_row->execute(undef); #row 2 Score=undef $insert_row->execute(''); #row 3 Score=null string $insert_row->execute(333); #row 4 Score=333 my $get_all_rows = $dbh->prepare("SELECT * FROM ScoreCard"); $get_all_rows->execute(); my $aref = $get_all_rows->fetchall_arrayref; print "all rows="; pp $aref; __END__ all rows=[[1, undef], [2, undef], [3, ""], [4, 333]]
    Maybe this is what the OP had in mind?

    Update 3:

    I believe that Corion has got it right! If the INSERT references the column in any way, the table DEFAULT will NOT be used. There is no way to coerce the DBI into using the default value configured at the time of Table creation with a value of undef or any other value. What this means is: if you have an insert statement that can provide a value for a column, you must explicitly provide that default instead of undef.

    My typical DB code knows for sure that every column is defined with a known value instead of undef. Again the Perl operator "//=" is very helpful: $value //= $default.

    If you have an insert statement with some variable and don't have a valid value for it, the DB will NOT use the default value for that column - you will get undef. The default only comes into play when it is not possible for the INSERT to set that value.

      If you specify a column in your INSERT statement, it seems at least SQLite (but I guess SQL) won't use the default. I've added a third column, which is not mentioned in the INSERT statement and it always picks up the default value:

      #!/usr/bin/perl use strict; use warnings; $|=1; #turn STDIO buffering off use Data::Dump qw(pp); use DBI; my $dbh = DBI->connect("dbi:SQLite:dbname=:memory:","","",{RaiseError +=> 1}) or die "Couldn't connect to database: " . DBI->errstr; $dbh->do ("CREATE TABLE ScoreCard ( id INTEGER PRIMARY KEY AUTOINCREMENT, Score INTEGER DEFAULT 11, My_Info VARCHAR DEFAULT '<none>' ); "); my $insert_row = $dbh->prepare("INSERT INTO ScoreCard(Score) + VALUES(?)"); # desired goal: get Score in the DB to be 11 if its not specified. $insert_row->execute(); #row 1 Score=undef $insert_row->execute(undef); #row 2 Score=undef $insert_row->execute(''); #row 3 Score=null string $insert_row->execute(333); #row 4 Score=333 my $get_all_rows = $dbh->prepare("SELECT * FROM ScoreCard"); $get_all_rows->execute(); my $aref = $get_all_rows->fetchall_arrayref; print "all rows="; pp $aref; __END__ all rows=[ [1, undef, "<none>"], [2, undef, "<none>"], [3, "", "<none>"], [4, 333, "<none>"], ]
Re: DBI isn't using default row values
by CountZero (Bishop) on Nov 29, 2016 at 07:22 UTC
    More generally, I find default values to be hazardous.

    You can have defaults at the level of your database, or at the level of a framework like DBIx::Class or Moose, or in your application code.

    Invariably, after a while somehow working with your database and code will fail to read the docs or simply forgets about all these different defaults and introduces hard to trace errors. Or as in the case of the OP, just doesn't know how to trigger the defaults.

    I think it is much better if the database complains loudly when a required field remains empty. Then it is immediately obvious where the error is.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

    My blog: Imperial Deltronics
Re: DBI isn't using default row values
by Anonymous Monk on Nov 28, 2016 at 16:24 UTC
    I have to wonder why you'd want to explicitly tell it to use a default value in the first place. Defaults are for when you're feeling too lazy to tell it what value to use.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1176704]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (3)
As of 2024-04-25 13:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found