SQLite, С++: пример пользовательской функции, возвращающей строку
strncpy( ym, s_null_date, 23 );
А эта строка не смущает?
7 должно быть? Ну это уже моя бага.
Либо тут <=7, либо строкой выше >=23. Либо надо менять обе строки.
ym может быть и не static. Не static даже лучше, ящетаю.
ym может быть и не static. Не static даже лучше, ящетаю.
Небольшой пример: выполняется запрос select foo("123" foo("321"), выводящий 321 321, т.е. использование static в данном случае не работает. Или я опять где накосячил?
P.S. Проверил в Билдере и gcc.
P.P.S. Книжка вроде ниче так, надо будет почитать. Спасибо
P.S. Проверил в Билдере и gcc.
P.P.S. Книжка вроде ниче так, надо будет почитать. Спасибо

#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"
static int callback(void *notused, int coln, char **rows, char **colnm)
{
int i;
static int b = 1;
if (b)
{
for(i=0; i<coln; i++)
printf("%s\t", colnm[i]);
printf("\n");
b = 0;
}
// разделитель строк
for(i=0; i<coln; i++)
printf("-------\t");
printf("\n");
//печать значений
for(i=0; i<coln; i++)
printf("%s\t|", rows[i]);
printf("\n");
return 0;
} // end callback
void foo (sqlite3_context* cx, int cnt, sqlite3_value** v)
{
static char y[3];
memset(y, 3, 0);
const char* arg0 = (const char*)sqlite3_value_text( v[0] );
strncpy( y, arg0, 3);
sqlite3_result_text( cx, y, 3, 0 );
}
int main
{
int rc, i;
sqlite3 *db; // указатель на открытую базу данных
char * errmsg; // сообщение об ошибке
// SQL инструкций
char *sql[] = {"select foo(\"123\" foo(\"321\")"};
// создадим новую базу данных
rc = sqlite3_open("exam2.db", &db);
if (rc)
{
//если ошибка при открытии БД
errmsg = (char*) sqlite3_errmsg(db);
printf("%s\n", errmsg);
sqlite3_free(errmsg);
sqlite3_close(db);
exit(1);
}
sqlite3_create_function(db, "foo", 1, SQLITE_UTF8, 0, &foo, 0, 0 );
// выполнение SQL инструкций
rc = sqlite3_exec(db, sql[0], callback, NULL, &errmsg);
if (rc != SQLITE_OK)
{
//если ошибка при выполнении запроса
printf("%s\n", errmsg);
sqlite3_free(errmsg);
sqlite3_close(db);
exit(1);
}
//закрытие БД
sqlite3_close(db);
system("pause");
return 1;
}
sqlite3_result_text( cx, y, 3, 0 );sqlite3_result_text( cx, y, 3, -1 );
void foo (sqlite3_context* cx, int cnt, sqlite3_value** v)
{
static char y[3];
memset(y, 3, 0);
const char* arg0 = (const char*)sqlite3_value_text( v[0] );
strncpy( y, arg0, 3);
sqlite3_result_text( cx, y, 3, 0 );
}
Тут есть несколько проблем.
1. Никто не гарантирует, что длина строки в v[0] будет равна 2. Вообще, если у строки длина n, она должна занимать n+1 байт ('\0' должен в конце присутствовать).
2. Последний параметр в sqlite3_result_text кое-что значит. Это указатель на функцию, которая чего-нибудь сделает с переданным указателем в конце выполнения. Есть три возможных значения для неё:
а) SQLITE_TRANSIENT --- в этом случае зовется sqlite3_malloc, результат копируется в новый буфер памяти, и эта память в итоге и приходит в callback после выполнения запроса.
б) Указатель на функцию, которая берёт void* и возвращает void*. Эта функция зовется в конце, как деструктор для переданного указателя на результирующую строку.
в) SQLITE_STATIC --- в этом случае предполагается, что данные по переданному указателю никуда не исчезнут static char[100], например, поэтому и копировать их не обязательно. Тогда в callback придет тот самый указатель, который был отправлен в sqlite3_result_text
Твой случай --- в) потому что так оказывается, что SQLITE_STATIC == 0, что ты и передаешь. Поскольку переменная y объявлена как static, массив всё ещё существует на момент вызова callback. А проблема состоит в том, что в запросе было два вызова функции foo. Соответственно, в этом месте памяти лежит результат работы последней функции.
, после сообщения полез смотреть, что же значат параметры.
Насколько я понял надо модифицировать функцию вот так:
Все верно? Что такое callback в данном случае не совсем понятно.
В чем засада была - понятно
3 поставил просто для примера, поскольку строки там заведомо длины 3. Про длину нуль-терминантных строк я в курсе.
Насколько я понял надо модифицировать функцию вот так:
void foo (sqlite3_context* cx, int cnt, sqlite3_value** v)
{
char ym[7];
strncpy( ym, s_null_date, 7);
sqlite3_result_text( cx, ym, 7, SQLITE_TRANSIENT);
}
Все верно? Что такое callback в данном случае не совсем понятно.
В чем засада была - понятно
3 поставил просто для примера, поскольку строки там заведомо длины 3. Про длину нуль-терминантных строк я в курсе.
Теперь лучше. Дальше надо, наверное, в callback после обработки результатов сделать sqlite3_free на тех данных, которые придут.
Поискал по инету, как прилепить callback для освобождения ресурсов. С текстовыми вообще что то примеров мало, да и народ особо не парится, напр. тут - http://gnu.ethz.ch/debian/gworkspace/gworkspace-0.8.6/GWMeta...
Так что наверно забью. Определю переменную как static, а для результата поставлю SQLITE_TRANSIENT.
static void path_moved(sqlite3_context *context, int argc, sqlite3_value **argv)
{
const unsigned char *oldbase = sqlite3_value_text(argv[0]);
int oldblen = strlenconst char *)oldbase);
const unsigned char *newbase = sqlite3_value_text(argv[1]);
int newblen = strlenconst char *)newbase);
const unsigned char *oldpath = sqlite3_value_text(argv[2]);
int oldplen = strlenconst char *)oldpath);
char newpath[PATH_MAX] = "";
int i = newblen;
int j;
strncpy(newpath, (const char *)newbase, newblen);
for (j = oldblen; j < oldplen; j++) {
newpath[i] = oldpath[j];
i++;
}
newpath[i] = '\0';
sqlite3_result_text(context, newpath, strlen(newpath SQLITE_TRANSIENT);
}
...
sqlite3_create_function(db, "pathMoved", 3, SQLITE_UTF8, 0, path_moved, 0, 0);
Так что наверно забью. Определю переменную как static, а для результата поставлю SQLITE_TRANSIENT.
Да, внутри исходников в sqlite3_exec зовется sqlite3_column_text память за которой вычищать не нужно, так что утечек памяти не будет.
Если многопоточное приложение, то static нужно удалить, если не многопоточное, то разницы никакой нет почти.
Если многопоточное приложение, то static нужно удалить, если не многопоточное, то разницы никакой нет почти.
Спасибо 
Приложение однопоточное, так что все гут.

Приложение однопоточное, так что все гут.
Оставить комментарий
0000
Имеется вот такойКод писал не я. Я только правлю. Смушает static char ym[7]; .
Можно как то без него обойтись?
P.S. Пример возвращения числа не нужен - в интернете находится без проблем. А вот строковой - вопрос.