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

I have a module that return SQL statements upon request.

Calling module (Mason component):

<%args> $action => '' </%args> <%perl> use strict; use warnings; use lib "/home/httpd/starfrontiers/modules"; use SQLlib; use DBI; # is user logged in? If so, get user id my $auid = $m->comp('auth.mas'); my $dbh2 = $m->comp('dbh2.mas'); # get statement defined from form my $sql = SQLlib->new; my $statement = $sql->$action(); #print "statement = ".$statement; dbh($statement, $dbh2); $m->redirect("/wiki/access_granted.html"); $m->auto_send_headers(0); $m->clear_buffer; $m->abort; sub dbh{ my ($statement, $dbh2) = @_; my $sth = $dbh2->prepare($statement) or die "dbh2 = $dbh2 Couldn't + prepare statement: $statement ".$dbh2->errstr; $sth->execute or die "dbh2 = $dbh2 Couldn't execute statement: $st +atement ".$dbh2->errstr; return $sth; } </%perl>

Module snippet

sub insert_lexicon{ my ($self) = @_; $statement = 'INSERT INTO lexicon ( word, meaning, auid) VALUES( \'$word\', \'$meaning\', \'$auid\');'; return ($statement); }

The statement has variables that are passed to the component. Currenlty the insert statement works but, the string "$word" and "$meaning" are literally inserted. In the module I need the variables to be literal strings but, once returned to the component I need the variables to be their actual values. Does that make sense? Is there a better way?

Neil Watson
watson-wilson.ca

Replies are listed 'Best First'.
Re: Module and variable place holders?
by edan (Curate) on Aug 29, 2004 at 15:00 UTC

    You'll be wanting to use placeholders, which are described in further detail in the DBI docs. This gist of it would be the following, in the context of your code:

    sub dbh{ my ($statement, $dbh2, @values) = @_; my $sth = $dbh2->prepare($statement) or die "dbh2 = $dbh2 Couldn't + prepare statement: $statement ".$dbh2->errstr; $sth->execute(@values) or die "dbh2 = $dbh2 Couldn't execute state +ment: $statement ".$dbh2->errstr; return $sth; } # ........................ sub insert_lexicon{ my ($self) = @_; $statement = 'INSERT INTO lexicon ( word, meaning, auid) VALUES( ?, ?, ?)'; return ($statement); }

    You basically put question-marks in the SQL statement, and pass a list of values to the $dbh->execute() method.

    HTH

    --
    edan

      I thought about place holders. If I do that then I believe I will have to go over a bunch of if-elsif statements so that certain values are passed to execute based on what $action is (it is defined from several forms e.g. "insert_lexicon, update_lexicon".

      Neil Watson
      watson-wilson.ca

        You would need some code, at any rate. Personally, I solved that part of the problem by keeping an array of bind parameters, and then bits of SQL that form that part of the WHERE clause. I would assume the same theory would hold with insert and update.

        sub options_sql_filter { my($self, $request) = @_; my @options = $self->options; my @sql_bits; my @bind_params; foreach my $option (@options){ my($sql_bit, @bind_param) = $option->sql_filter($request); push @sql_bits, $sql_bit; push @bind_params, @bind_param; } return (join ' AND ', @sql_bits), @bind_params; }

        sql_filter here returns a list that looks like ('foo = ?', 'bar')

        This lets you piece together SQL that uses bind parameters but is generated dynamically.

        Doing that work is better than leaving major security holes in your application. See Use placeholders. For SECURITY! for a brief explanation of what SQL injection attacks are, why you're vulnerable, and why you should care.
Re: Module and variable place holders?
by PodMaster (Abbot) on Aug 29, 2004 at 15:02 UTC
    print ' blah blah @this blah $that blah $that $blah $blah $blash $blah + $blah';
    will print  blah blah @this blah $that blah $that $blah $blah $blash $blah $blah as expected (single quotes don't interpolate). When you prepare, you're generally supposed to use placeholders, see Tutorials for a tutorial on placeholders (or see the DBI documentation).

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.