Beefy Boxes and Bandwidth Generously Provided by pair Networks vroom
Syntactic Confectionery Delight
 
PerlMonks  

SQL::Statement confusing literals and identifiers

by ikegami (Pope)
on Mar 11, 2008 at 02:52 UTC ( #673399=perlquestion: print w/ replies, xml ) Need Help??
ikegami has asked for the wisdom of the Perl Monks concerning the following question:

I'm getting an error with DBD::CSV, although it's actually thrown by SQL::Statement:

DBD::CSV::st execute failed: Execution ERROR: No such column 'PRINT."set"'. [for Statement " SELECT id, gid, card, "set", illus, num FROM Print "] at problem.pl line 41.

SQL::Statement doesn't seem to recognize that "set" means set. Unfortunately, set must be quoted since it's a reserved word and SQL::Statement dies complaining of that fact when set is left unquoted.

Does anyone have any workarounds for this? Has this been fixed in a newer version? Looks like I'll have to first copy the CSV with different field names. Fortunately, the tool on which I am working is only used to import CSV into a "real database".

>perl -le"use SQL::Statement; print SQL::Statement->VERSION" 1.15 >perl -le"use DBD::CSV; print DBD::CSV->VERSION" 0.22

Code and data to reproduce:

673399.pl:

use strict; use warnings; use DBI qw( ); use File::Spec::Functions qw( catfile ); { my $db = '.'; my $dsn = "dbi:CSV:f_dir=$db"; my $user = undef; my $passwd = undef; my $dbh = DBI->connect( $dsn, $user, $passwd, { RaiseError => 1, PrintError => 0, PrintWarn => 1, AutoCommit => 1, # No writing, so no need for +transactions. FetchHashKeyName => 'NAME_lc', } ); for (qw( Print )) { my $path = catfile($db, "$_.csv"); # Xyz and "Xyz" are erroneously considered different tables. $dbh->{csv_tables}{ $_ }{file} = $path; $dbh->{csv_tables}{qq{"$_"}}{file} = $path; } my $sth = $dbh->prepare(' SELECT id, gid, card, "set", illus, num FROM Print '); $sth->execute(); # ... }

Print.csv:

id,gid,card,set,illus,num 1,1,1,1,"Foo Bar",1

Comment on SQL::Statement confusing literals and identifiers
Select or Download Code
Re: SQL::Statement confusing literals and identifiers
by roboticus (Canon) on Mar 11, 2008 at 03:01 UTC
    ikegami:

    Update: Nevermind ... I just tried it and it doesn't like those either.

    Try using square brackets or single quotes:

    SELECT id, gid, [foo bar]

    I know some SQL servers don't care for double quotes (e.g., MS SQL server), so perhaps SQL::Statement doesn't like 'em either....

    ...roboticus

      The error occurs on the execute line after prepare successfully parsed the statement.
Re: SQL::Statement confusing literals and identifiers
by Thilosophy (Curate) on Mar 11, 2008 at 06:32 UTC
    Does anyone have any workarounds for this?

    Does DBD::CSV support select * from Print? That might work (if you do not mind getting columns you do not need), although I cannot test it, your sample fails for me with a rather cryptic error:

    DBD::CSV::st execute failed: Error while reading file /tmp/c/Print.csv +: Bad file descriptor at /usr/share/perl5/DBD/CSV.pm line 210, <GEN0> + chunk 1.
    :-(

      The error you are getting is due to an unrelated bug I fixed locally. It will probably stop manifesting itself if you installed Text::CSV_XS.

      Silly me, of course SELECT * will work, especially since I use fetchrow_hashref. The queries that use WHERE clauses are only done on the "real database" which has no problems with the quotes.

      Update: s/It will probably manifesting/It will probably stop manifesting/

        The error you are getting is due to an unrelated bug I fixed locally. It will probably manifesting itself if you installed Text::CSV_XS.

        Ahh, that would explain it. I installed everything using Ubuntu's apt-get, and yes, that gave me Text::CSV_XS, too.

Re: SQL::Statement confusing literals and identifiers
by grinder (Bishop) on Mar 11, 2008 at 08:36 UTC
    SQL::Statement doesn't seem to recognize that "set" means set.

    String constants use single quote (') delimiters. Column labels use double quotes ("), and set in your example is a string constant, not a column label.

    So the (non-) problem is that it doesn't like parsing illegal SQL. Rewrite your statement as the following, and you should be fine.

    SELECT id, gid, card, 'set', illus, num FROM Print

    • another intruder with the mooring in the heart of the Perl

      No, I think ikegami wants the (double-quoted) column set (that is what the column in his CSV file is called), not a constant string.

        Oh duh, silly me, I should have known ikegami would not make a mistake like that. Still, I think SQL::Statement is playing the game correctly. Witness:

        use strict; use warnings; use SQL::Statement; my $stmt = SQL::Statement->new(<<END_SQL, SQL::Parser->new); SELECT id, gid, card, "set", illus, num FROM Print END_SQL print join( "\n\t" => $stmt->command, map{ $_->name } $stmt->columns), + "\n"; __PRODUCES__ SELECT ID GID CARD "set" ILLUS NUM

        Perhaps Print."set" may be advisable. In that case, the output changes slightly:

        SELECT ID GID CARD "SET" ILLUS NUM

        • another intruder with the mooring in the heart of the Perl

        Ok, to restore my credibility, here's a workaround:

        It's a bug alright. At some point the code lines up the requested columns, and the columns the table has to offer. It chokes on the fact that the q{SET} eq q{"SET"} equality fails to hold. It's because at some point the double quotes need to be stripped away, to recover the bare column name underneath and that is not (no longer?) happening.

        What is strange is that there appears to be code in there that does just this, but has been commented out. In any event, the following patch seems to do the trick, but one would have to run the full regression test suite to be sure.

        --- Statement.pm Tue Mar 11 13:13:43 2008 +++ /usr/local/lib/perl5/site_perl/5.8.8/SQL/Statement.pm Tue Ma +r 11 13:23:05 2008 @@ -1590,6 +1590,7 @@ ); } next unless $col; + $col =~ s/\A"([^"]+)"\z/$1/; ###new if (ref $table eq 'SQL::Statement::Table') { $table = $table->name;

        • another intruder with the mooring in the heart of the Perl

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (15)
As of 2014-04-18 17:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (471 votes), past polls