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

In the statement:

eval $TabString

following a no strict; I'm getting this error in $@:

Can't modify constant item in scalar assignment at (eval 34)/home/bear/MC/MOB/DB/Utilities.pm:57 line 1, at EOF

where $TabString is:

DBI::db=HASH(0x40b8a38)->do("CREATE TABLE STAIP08FK (PROBKEY varchar(20),MOBPAITS varchar(15),SOLVER varchar(10),UNKNOWNS char(11),CONSTRAINTS char(11),OBJECTIVE char(11),MODEL char(16),CRITERIA char(11),ITERATIONS integer,primary key (PROBKEY) );");

The connected DBI handle seems to be the problem. I'm generating these joined DB tables dynamically. I can't get around that. Is there a way I can get past this eval error?

Replies are listed 'Best First'.
Re: Eval error on connectd DBI handle
by MidLifeXis (Monsignor) on Feb 23, 2016 at 21:43 UTC

    Multiple items:

    • I see no reason given the code provided, that this has to be done via eval. Do a $dbh->do($generated_table_data). I would recommend using the quoting or placeholder functions, if at all possible, of the dbi to avoid Bobby Tables issues.
    • You are stringifying the reference for the $dbh, which is where the DBI::db=HASH... stuff is coming from. Don't do that. As I said in the last point, eval is not necessary here.

    --MidLifeXis

      Note that quoting or placeholder functions will not work for database identifiers like table names, and only for content. So code like:
      my $query = $dbh->prepare('CREATE TABLE ?'); $query->execute('TABLE_NAME');
      will fail because the database engine will render that as
      CREATE TABLE 'TABLE_NAME'
      which is nonsense syntax.

      #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

        Note that quoting or placeholder functions will not work for database identifiers like table names

        DBI has a quote_identifier() method that handles all required quoting of database identifiers. Unfortunately, you can't use placeholders for identifiers, so you have to call quote_identifier() manually, like this:

        my $cmd='create table '.$dbh->quote_identifier($tablename); $dbh->do($cmd);

        And by the way: There is also a quote() method in DBI. For all but some very exotic cases, just forget that it exists and use placeholders. I think quote() should die or at least warn when being called from non-DBI, non-DBD code. It is usually just wrong to use it instead of using placeholders. See Re: Counting rows Sqlite, Re^2: Massive Memory Leak, Re^3: Variable interpolation in a file to be read in, Re^5: Variable interpolation in a file to be read in for more details.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
      Thanks so much for the alternative approaches. I'll pick one.
Re: Eval error on connectd DBI handle
by Discipulus (Canon) on Feb 23, 2016 at 22:03 UTC
    Even more with DB try to follow idiomatic and robust code style, the DBI docs and the old but still precious DBI recipes

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Eval error on connectd DBI handle
by kennethk (Abbot) on Feb 23, 2016 at 21:43 UTC
    The problem is that Perl will not dereference DBI::db=HASH(0x40b8a38) to the original reference; the equals it is complaining about is the one after the letters db. You can replicate this with:
    package PACK; sub func { print "1\n"; } package main; $obj = bless {}, 'PACK'; $obj->func; $str = "$obj->func;1"; eval $str or print $@;

    This sounds a lot like an XY Problem. Why are you trying to do a string eval, instead of just the code

    $dbh->do("CREATE TABLE STAIP08FK (PROBKEY varchar(20),MOBPAITS varchar +(15),SOLVER varchar(10),UNKNOWNS char(11),CONSTRAINTS char(11),OBJECT +IVE char(11),MODEL char(16),CRITERIA char(11),ITERATIONS integer,prim +ary key (PROBKEY) );"
    If there's a reason to do a string eval, why aren't you escaping the dollar sigil in your original string, e.g.
    $str = qq{\$dbh->do("CREATE TABLE STAIP08FK (PROBKEY varchar(20),MOBPA +ITS varchar(15),SOLVER varchar(10),UNKNOWNS char(11),CONSTRAINTS char +(11),OBJECTIVE char(11),MODEL char(16),CRITERIA char(11),ITERATIONS i +nteger,primary key (PROBKEY) );"};

    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.