Re: UPDATE syntax problem

From: Doug McNaught <doug(at)mcnaught(dot)org>
To: MT <mt(at)open2web(dot)com>
Cc: pgsql-general <pgsql-general(at)postgresql(dot)org>
Subject: Re: UPDATE syntax problem
Date: 2002-12-09 01:16:33
Message-ID: m3ptsc6lfy.fsf@varsoon.wireboard.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

MT <mt(at)open2web(dot)com> writes:

> Hello,
>
> I would just like to follow up on what you suggested since it went a
> little over my head.
>
> > A couple points:
> >
> > 1) You're wide open to an SQL injection attack.
>
> What's that?

STFW.

http://www.google.com/search?hl=en&ie=ISO-8859-1&q=SQL+injection+attack

>
> > You'll need to
> > preprocess the parameter values to make sure single quotes are
> > properly escaped before building the SQL statement.
>
> Do you mean:
>
> string category = \'param["new_prodname"]\'
>
> Does this prevent an sql injection attack?

Not quite--you need to look inside the string for single quote
characters and escape them. It's a bit tedious but not hard.

> > 2) The code structure you're using is awkward--you have to add a new
> > clause if you add a parameter. I'd be more likely to make a list
> > of parameters, and loop through it checking for changed values and
> > adding clauses to the SQL statement (this would be a good time to
> > do the quote escaping). If no values have changed, just don't
> > execute the SQL at all (your code doesn't handle this case).
>
> I'm not sure how this is done. I would appreciate it if you could
> elaborate on this by perhaps providing a quick example.

Sure. I don't actually know C++ that well--I use Perl and Java
generally, and I've been writing Perl tonight, so the below is mostly
Perlish--but you should be able to follow along:

$any_changed = 0; # false
$sql = "UPDATE mytable SET ";
@param_list = ('catid', 'prodname', 'unitcnt', 'price'); # create a list
foreach $p (@param_list) { # iterate through it
if ($param{"old_$p"} ne $param{"new_$p"}) {
$any_changed = 1;
if ($p ne $param_list[0]) { # if we're not on the first element
$sql .= ", "; # put in a comma
}
$fixed_param = escape_param($param{"new_$p"}); # escape single quotes
$sql .= "$p = '" . $fixed_param . "'";
}
if ($any_changed) {
$sql .= " WHERE prod_code = '4455GGF'";
exec_sql($sql);
}
}

Here, '.' is the Perl string concatenation operator (instead of '+')
and variable values are interpolated into double-quoted strings for
you (so "new_$p" ends up being "new_catid", say). '#' denotes a
comment just as '//' does in C++.

You get the idea? This way, if you add a parameter, you just add it
to the array, rather than copy/pasting a bunch of code and hacking it
around.

> This works, but I'm always interested in finding better ways to do
> things. Your way looks better. I realize this is more a programming
> question than a postgres question. By the way, should I be using
> transactions if I do it this way, or the way you have suggested?

Basically, you should use transactions any time you want to execute
two or more SQL statements that should be seen as a unit by other
database users.

-Doug

In response to

Browse pgsql-general by date

  From Date Subject
Next Message Aasmund Midttun Godal 2002-12-09 01:17:55 Re: How to make silently truncate for char type
Previous Message Peter Eisentraut 2002-12-09 00:38:43 Re: 7.3 no longer using indexes for LIKE queries