This behavior change is in response to ticket
http://www.sqlite.org/src/info/406d3b2ef9 - a diff across several check-ins
that makes this change can be seen here:


http://www.sqlite.org/src/vdiff?from=b1b0de29fdf7de83&to=62465ecba7431e1d&sbs=1&dc=25

Note that the behavior changes brings the implementation into agreement
with the historical documentation.  The document was clarified and enhanced
as part of this change.  But the key statements in the old documentation
where:

"If [the sqlite3_set_auxdata destructor] is not NULL, SQLite will invoke
the destructor function given by the 4th parameter to sqlite3_set_auxdata()
on the metadata when the corresponding function parameter changes or when
the SQL statement completes, whichever comes first. SQLite is free to call
the destructor and drop metadata on any parameter of any function at any
time. The only guarantee is that the destructor will be called before the
metadata is dropped."

The corresponding text in the revised documentation is similar:

"SQLite is free to discard the metadata at any time, including:
  *  when the corresponding function parameter changes, or
  * when [sqlite3_reset()] or [sqlite3_finalize()] is called for the  SQL
statement, or
  * when sqlite3_set_auxdata() is invoked again on the same parameter, or
  * during the original sqlite3_set_auxdata() call when a memory
allocation error occurs. "

The revised documentation is on the website here:
http://www.sqlite.org/c3ref/get_auxdata.html

So as far as I can tell, the current implementation is doing what it is
suppose to do. Or did I misunderstand the complaint?





On Sun, Feb 9, 2014 at 10:50 AM, gwenn <gwenn.k...@gmail.com> wrote:

> Hello,
> I am not sure but it seems there is a regression between versions
> 3.7.17 and 3.8.0.
> It's impacting custom/user declared function and auxiliary data.
>
> sqlite-amalgamation-3071700 gwen$ gcc
> -I/usr/local/Cellar/glib/2.38.2/include/glib-2.0
> -I/usr/local/Cellar/glib/2.38.2/lib/glib-2.0/include sqlite3.c
> auxdata.c -o auxdata -L/usr/local/Cellar/glib/2.38.2/lib -lglib-2.0
> sqlite-amalgamation-3071700 gwen$ ./auxdata
> loop 1
> (0) compiling...
> zzzzz
> (0) reusing...
> yyyyy
> loop 2
> (0) reusing...
> zzzzz
> (0) reusing...
> yyyyy
>
> sqlite-amalgamation-3080300 gwen$ gcc
> -I/usr/local/Cellar/glib/2.38.2/include/glib-2.0
> -I/usr/local/Cellar/glib/2.38.2/lib/glib-2.0/include sqlite3.c
> auxdata.c -o auxdata -L/usr/local/Cellar/glib/2.38.2/lib -lglib-2.0
> sqlite-amalgamation-3080300 gwen$ ./auxdata
> loop 1
> (0) compiling...
> zzzzz
> (0) reusing...
> yyyyy
> loop 2
> (0) compiling...
> zzzzz
> (0) reusing...
> yyyyy
>
> The auxiliary data is reused in the second loop with SQLite 3.7.17 but
> not with SQLite 3.8.0.
> What is the expected/correct behaviour?
>
> Regards
>
> Here is the content of auxdata.c:
> #include <stdlib.h>
> #include <stdio.h>
> #include <glib.h>
> #include "sqlite3.h"
>
> static void log(void *pArg, int iErrCode, const char *zMsg) {
> printf("(%d) %s\n", iErrCode, zMsg);
> }
>
> static void glibRegexpDelete(void *p){
>   GRegex *pRegex = (GRegex *)p;
>   g_regex_unref(pRegex);
> }
>
> static void glibReplaceAllFunc(
>   sqlite3_context *ctx,
>   int argc,
>   sqlite3_value **argv
> ){
> GError *err = NULL;
> GRegex *p;
> gchar *result = NULL;
>
> (void)argc;  /* Unused parameter */
>
> const gchar *str = (const gchar *) sqlite3_value_text(argv[1]);
> if (!str) {
> return;
> }
>
> const gchar *replacement = (const gchar *) sqlite3_value_text(argv[2]);
> if (!replacement) {
> sqlite3_result_error(ctx, "no replacement string", -1);
> return;
> }
>
> p = sqlite3_get_auxdata(ctx, 0);
> if( !p ){
> const gchar *re = (const gchar *) sqlite3_value_text(argv[0]);
> if( !re ){
> //sqlite3_result_error(ctx, "no regexp", -1);
> return;
> }
> p = g_regex_new(re, 0, 0, &err);
>
> if( p ){
> sqlite3_set_auxdata(ctx, 0, p, glibRegexpDelete);
> }else{
> char *e2 = sqlite3_mprintf("%s: %s", re, err->message);
> sqlite3_result_error(ctx, e2, -1);
> sqlite3_free(e2);
> g_error_free(err);
> return;
> }
> sqlite3_log(0, "compiling...");
> } else {
> sqlite3_log(0, "reusing...");
> }
>
> result = g_regex_replace(p, str, -1, 0, replacement, 0, &err);
> if (err) {
> sqlite3_result_error(ctx, err->message, -1);
> g_error_free(err);
> return;
> }
> sqlite3_result_text(ctx, result, -1, g_free);
> }
>
> int main(int argc, char **argv) {
> sqlite3_config(SQLITE_CONFIG_LOG, log, NULL);
> sqlite3 *db = NULL;
> sqlite3_stmt *stmt = NULL;
> char *zErrMsg = NULL;
> const char *z;
> int rc = 0;
> rc = sqlite3_open_v2(":memory:", &db, SQLITE_OPEN_FULLMUTEX |
> SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
> if (db == NULL || SQLITE_OK != rc) {
> fprintf(stderr, "Error: unable to open database: %s\n",
> sqlite3_errmsg(db));
> exit(1);
> }
> sqlite3_create_function_v2(db, "regex_replace", 3, SQLITE_UTF8, 0,
> glibReplaceAllFunc, NULL, NULL, NULL);
>   rc = sqlite3_prepare_v2(db, "select regex_replace('.', 'abcde', r)
> from (select 'z' as r union all select 'y')", -1, &stmt, NULL);
>   if (stmt == NULL || SQLITE_OK != rc) {
> fprintf(stderr, "Error: prepare stmt: %s\n", sqlite3_errmsg(db));
> exit(1);
>   }
>   for (int i = 1; i <= 2; i++) {
>   printf("loop %d\n", i);
>  rc = sqlite3_step(stmt);
>  while (rc == SQLITE_ROW) {
>   z = (const char*)sqlite3_column_text(stmt, 0);
>   printf("%s\n", z);
>   rc = sqlite3_step(stmt);
>  }
>  if (SQLITE_OK != rc && SQLITE_DONE != rc) {
> fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
> exit(1);
> }
>  rc = sqlite3_reset(stmt);
>  if (SQLITE_OK != rc) {
> fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
> exit(1);
> }
> }
>   sqlite3_finalize(stmt);
> sqlite3_close(db);
> }
> _______________________________________________
> sqlite-users mailing list
> sqlite-users@sqlite.org
> http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users
>



-- 
D. Richard Hipp
d...@sqlite.org
_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to