You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Dave Ingram <da...@dmi.me.uk> on 2008/10/12 19:58:29 UTC

apr_dbd_prepare() corrupts arguments on failure

Hi all,

I've been trying to use the APR-util DBD API (v1.3.2) while writing an
Apache 2.2 module, and I've run into a problem with my code and prepared
statements, which I really don't understand. I've been taking
inspiration from Apache's mod_dbd module, and so I'm slightly at a loss
as to why there would be a problem. The offending code fragment:

fprintf(stderr, "DBINFO: %p %p %d\n", dbinfo->driver, dbinfo->handle, rv);
rv = apr_dbd_prepare(dbinfo->driver, prepared_pool, dbinfo->handle,
query, NULL, &stmt);
if (rv) {
  fprintf(stderr, "DBINFO: %p %p %d\n", dbinfo->driver, dbinfo->handle, rv);
  const char *dberrmsg = apr_dbd_error(dbinfo->driver, dbinfo->handle, rv);
  ap_log_error(APLOG_MARK, APLOG_ERR, rv, cmd->server,
               "DBD: failed to prepare SQL statements: %s",
               (dberrmsg ? dberrmsg : "[???]"));
  // free the temporary sub-pool
  apr_pool_destroy(prepared_pool);
  return "Failed to prepare SQL statement";
}


This all appears to work fine if the statement is valid. If there is a
problem (e.g. a syntax error in the SQL) then apr_dbd_prepare() seems to
destroy its driver and handle arguments, as shown by the fprintf() output:

DBINFO: 0xb7b3adc0 0x819fb30 0
DBINFO: 0x81ba928 (nil) 1064

I don't quite see how it can do this though! In any case, the code I
have used is virtually identical to that used by mod_dbd, which doesn't
seem to have this trouble. What have I missed? Let me know if you need
more context.

Thanks,


Dave Ingram

Re: apr_dbd_prepare() corrupts arguments on failure

Posted by Dave Ingram <da...@dmi.me.uk>.
Tom Donovan wrote:
> Dave Ingram wrote:
>> <SQLRepeat "SELECT hostname, domain FROM hosts WHERE status = 1">
>> <VirtualHost *:80>
>>   ServerName ${hostname}.${domain}
>>   <SQLRepeat "SELECT * FROM host_aliases WHERE hostname=? AND
>> domain=?" "${hostname}" "${domain}">
>>     ServerAlias ${alias}
>>   </SQLRepeat>
>>   # ...
>> </SQLRepeat>
>>
>> without worrying about what the hostname/domain strings actually
>> contain.
>
> With APR 1.3 you must pass string parameters as %s, rather than ?
Ah, thanks - I didn't know that. I might do an automagic conversion from
? to %s. Still, it shouldn't break like this on a query that doesn't
contain any parameters...

> mod_vhost_dbd is a little bit like your module.  You might want to
> look over the source code for it at http://code.google.com/p/dbd-modules/
Thanks for the link. It's a little similar, but there are some very
important differences. All of my directives are executed as they are
parsed at configuration time (like mod_macro) as it is intended to be
extremely flexible (again, like mod_macro). Unfortunately, this means
that I can't use mod_dbd (much as I'd like to), as it isn't initialised
until the server starts. This has to be done as the directives are
parsed, because template sections can contain any directives:

<SQLRepeat ...>
<VirtualHost ...>
...
<SQLSimpleIf ${has_custom_config}>
  Include "vhost.custom/${hostname}.${domain}.conf"
</SQLSimpleIf>
...
</SQLRepeat>

So it all has to be done at parse time. I wish I knew more about how APR
worked so I can get to the bottom of this issue! :-)


D

Re: apr_dbd_prepare() corrupts arguments on failure

Posted by Tom Donovan <do...@bellatlantic.net>.
Dave Ingram wrote:
> Dave Ingram wrote:
>> Bojan Smojver wrote:
>>>> Actually, it turns out that apr_dbd_prepare() is destroying its
>>>> arguments no matter whether it succeeds or not. What's going on? Does
>>>> anyone have any handy examples of how to use the DBD code?    
>>>
...
> 
> <SQLRepeat "SELECT hostname, domain FROM hosts WHERE status = 1">
> <VirtualHost *:80>
>   ServerName ${hostname}.${domain}
>   <SQLRepeat "SELECT * FROM host_aliases WHERE hostname=? AND domain=?" 
> "${hostname}" "${domain}">
>     ServerAlias ${alias}
>   </SQLRepeat>
>   # ...
> </SQLRepeat>
> 
> without worrying about what the hostname/domain strings actually contain.

With APR 1.3 you must pass string parameters as %s, rather than ?

e.g.
      SELECT * FROM host_aliases WHERE hostname=%s AND domain=%s

mod_vhost_dbd is a little bit like your module.  You might want to look over the source code for it 
at http://code.google.com/p/dbd-modules/

-tom-

Re: apr_dbd_prepare() corrupts arguments on failure

Posted by Dave Ingram <da...@dmi.me.uk>.
Dave Ingram wrote:
> Bojan Smojver wrote:
>>> Actually, it turns out that apr_dbd_prepare() is destroying its
>>> arguments no matter whether it succeeds or not. What's going on? Does
>>> anyone have any handy examples of how to use the DBD code?    
>>
>> My best bet is that you have pool hierarchy/lifetime problems.
>>   
> That's entirely possible - I'm not 100% sure on how I should be using
> them. What would be the best place to find out?

Update: After finding some minimal documentation on the difference
between "cmd->pool" and "cmd->temp_pool", I now allocate prepared_pool
as a sub-pool of cmd->pool and apr_dbd_select() works without any
segfaults, but I'm still having the same problem with apr_dbd_prepare().

I still don't understand how it's changing the contents of my pointer
variables. Am I right to be calling it with NULL for the label argument,
as I'm only using the prepared statement once, in that function? My
reason for using a prepared statement is so that people can use:

<SQLRepeat "SELECT hostname, domain FROM hosts WHERE status = 1">
<VirtualHost *:80>
  ServerName ${hostname}.${domain}
  <SQLRepeat "SELECT * FROM host_aliases WHERE hostname=? AND domain=?"
"${hostname}" "${domain}">
    ServerAlias ${alias}
  </SQLRepeat>
  # ...
</SQLRepeat>

without worrying about what the hostname/domain strings actually contain.


Dave

Re: apr_dbd_prepare() corrupts arguments on failure

Posted by Dave Ingram <da...@dmi.me.uk>.
Bojan Smojver wrote:
>> Actually, it turns out that apr_dbd_prepare() is destroying its
>> arguments no matter whether it succeeds or not. What's going on? Does
>> anyone have any handy examples of how to use the DBD code?
>>     
>
> My best bet is that you have pool hierarchy/lifetime problems.
>   
That's entirely possible - I'm not 100% sure on how I should be using
them. What would be the best place to find out?

I'm thinking of writing up all of this somewhere once it all works, so
other people can find it and hopefully avoid these problems.


D

Re: apr_dbd_prepare() corrupts arguments on failure

Posted by Bojan Smojver <bo...@rexursive.com>.
On Sun, 2008-10-12 at 19:11 +0100, Dave Ingram wrote:

> Actually, it turns out that apr_dbd_prepare() is destroying its
> arguments no matter whether it succeeds or not. What's going on? Does
> anyone have any handy examples of how to use the DBD code?

My best bet is that you have pool hierarchy/lifetime problems.

-- 
Bojan


Re: apr_dbd_prepare() corrupts arguments on failure

Posted by Dave Ingram <da...@dmi.me.uk>.
Some additional info:
> This all appears to work fine if the statement is valid.
Actually, it turns out that apr_dbd_prepare() is destroying its
arguments no matter whether it succeeds or not. What's going on? Does
anyone have any handy examples of how to use the DBD code?


D