SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 19.04.2011 19:02:39

xcom256
Участник
Зарегистрирован: 19.04.2011
Сообщений: 6

MySQL embedded как SQLite

Здравстуйте! Возможно, вопрос немного странный, но я не нашел пока тривиального ответа на него.

Можно ли сделать так, чтобы MySQL embedded, встаиваясь в приложение, работала исключительно с файлом БД, используемым в приложении и лежащим в папке с приложением, как SQLite. Грубо говоря, чтобы приложение не лезло в таблицы привилегии, леащие в /var/... и не зависело от глобальных настроек в системе (устанавливаемых в mysql-admin) и, соответсвенно не трогало системный my.cnf.

Если можно, то как? Задача под Linux.

Неактивен

 

#2 19.04.2011 19:24:45

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: MySQL embedded как SQLite

Можно запустить mysql-сервер так, чтобы он читал другой конфигурационный файл (не обязательно /etc/my.cnf). Встроить в приложение открыто распространяемую версию MySQL Community нельзя.

Неактивен

 

#3 20.04.2011 13:00:40

xcom256
Участник
Зарегистрирован: 19.04.2011
Сообщений: 6

Re: MySQL embedded как SQLite

Есть библиотека libmysqld.a, которая и есть MySQL embedded, входит в MySQL Community Server. Если линковать с ней, то мы и получаем встроенный сервер. Запускается это через

mysql_server_init(mydb,0,0,0);

или, как в моем случае, через драйвер qt-mysql. Таким образом, вопрос присоединения MySQL сервера решен (или я допустил здесь принципиальную ошибку, тогда прошу пояснить, какую). Единственное но: запуск этого сервера исползует общий /etc/my.cnf и полностью согласуется с базами MySQL, доступными из MySQL Administrator (соответсвенно, и с пользователями тоже, и любые изменения настроек через mysql-admin влияют на этот встроенный сервер). Мне же нужно сделать так, чтобы мой сервер никак не был согласован с централизованным сервером.

Итого 3 вопроса:
1. Правильно ли я понял, что именно это в Community версии сделать нельзя и получается, что при переносе на другую машину даже с прилинкованным libmysqld.a mysql работать не будет? Если все же желаемое осуществимо, то как это сделать?
2. Как именно в embedded-версии (в не embedded это понятно) подключить другой конфигурационный файл?
3. Есть ли какие-либо альтернативы SQLite с более широкой поддержкой стандарта SQL. Единственное, почему не устраивает SQLite - это отсутствие поддержки некоторых конструкций SQL (например, TRIGGER)

Неактивен

 

#4 20.04.2011 21:39:08

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: MySQL embedded как SQLite

Конфиг-файл надо написать свой (вопросы 1 и 2):
http://dev.mysql.com/doc/refman/5.5/en/ … tions.html

Триггеры в sqlite (вопрос 3):
http://www.sqlite.org/lang_createtrigger.html

Что касается MySQL embedded — Вы обязаны распространять приложение,
слинкованное бинарно с библиотекой GPL2 по лицензии GPL2 или выше.

Неактивен

 

#5 21.04.2011 16:29:59

xcom256
Участник
Зарегистрирован: 19.04.2011
Сообщений: 6

Re: MySQL embedded как SQLite

Нашел замечательную статью, где разжевано все про начало работы с MySQL Embedded.

http://dev.mysql.com/tech-resources/articles/embedding-mysql-server.html

Исправил все согласно этой статье. Теперь что мы имеем:

#include "mysqlTest.h"

#include <iostream>
#include <ctime>
#include <sys/time.h>
#include <string>
#include <QDebug>

using namespace std;

MYSQL_RES *results;
MYSQL_ROW record;


   static char *server_options[] = {"mysql_test", "--defaults-file=my.cnf"};
   int num_elements = sizeof(server_options) / sizeof(char *);

   static char *server_groups[] = {"libmysqd_server", "libmysqd_client"};

char *itoa2(int i)
{
    char *str = new char[16];
    sprintf(str, "%i", i);

    return str;
}

bool PerformTest()
{
    MYSQL *one = db_connect("TestDB");
    if (one == NULL)
        return false;

    db_do_query(one,"SHOW TABLE STATUS",true);
    timeval ltime, etime, dtime;
    double timedif = 0.0;

    gettimeofday(&ltime,NULL);
    db_do_query(one,"SELECT * FROM person WHERE field18 =4",false);
    gettimeofday(&etime,NULL);
    timersub(&etime,&ltime,&dtime);

    timedif = dtime.tv_usec/1000000.0;
    cout << "--------->pid: " << getpid() << " MYSQL query time: " << timedif << endl;
}

bool CreateTest()
{

    MYSQL *two = db_connect(NULL);
    if (two == NULL)
        return false;

    mysql_query(two,"DROP DATABASE TestDB");
    mysql_query(two,"CREATE DATABASE TestDB");
    MYSQL *one = db_connect("TestDB");

    if (one == NULL)
        return false;
    db_do_query(one, "create table person (id int primary key, "
                "firstname varchar(20), lastname varchar(20), field1 int, field2 int, field3 int, field4 int, field5 int, "
                "field6 int, field7 int, field8 int, field9 int, field10 int, field11 int, field12 int, field13 int, "
                "field14 int, field15 int, field16 int, field17 int, field18 int)",true);
    db_do_query(one,"SHOW TABLES",true);
    timeval ltime, etime, dtime;
    double timedif = 0.0;


    for (int i = 1; i < 30000; i++)
    {
        string aa;
        const char* num = itoa2(i);

        aa = "insert into person values("; aa += num; aa += ",'Danny', 'Young'";
        for (int j = 1; j <= 17; j++)
        {
            aa += ", "; aa += num;
        }
        const char* num2 = itoa2(i%10);
        aa += ", "; aa += num2;
        aa += ")";
        cout << aa << endl;
        gettimeofday(&ltime,NULL);
        db_do_query(one,aa.c_str(),false);
        gettimeofday(&etime,NULL);
        timersub(&etime,&ltime,&dtime);

        timedif = dtime.tv_usec/1000000.0;
        cout << "--------->pid: " << getpid() << " MYSQL INSERT query time: " << timedif << endl;
    }
//    query

    mysql_close(two);
    mysql_close(one);

    return true;
}

static void die(MYSQL *db, char *fmt, ...)
{
    if (db)
        db_disconnect(db);
    exit(EXIT_FAILURE);
}


MYSQL* db_connect(const char *dbname)
{
    MYSQL *db = mysql_init(NULL);
    qDebug() << mysql_error(db) << endl;
    if (!db)
        die(db, "mysql_init failed: no memory");
    /*
* Обратите внимание: клиент и сервер используют разные имена групп.
* Это обязательное условие, поскольку сервер не должен использовать опции
* клиента и наоборот.
*/

    mysql_options(db, MYSQL_READ_DEFAULT_GROUP, "libmysqld_client");
    mysql_options(db, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);
    if (!mysql_real_connect(db, NULL, NULL, NULL, dbname, 0, NULL, 0))
    {
        return NULL;
    }
    return db;
}

void db_disconnect(MYSQL *db)
{
    mysql_close(db);
}

bool db_do_query(MYSQL *db, const char *query, bool isShow)
{
    if (isShow)
        cout << query << endl;
    if (mysql_query(db, query) != 0)
        return false;

    if (mysql_field_count(db) > 0)
    {
        MYSQL_RES *res;
        MYSQL_ROW row;
        int num_fields = 0;
        if (!(res = mysql_store_result(db)))
        {
            num_fields = mysql_field_count(db);

        }
        while ((row = mysql_fetch_row(res)))
        {
            if (isShow)
                cout << " >> " << *row << endl;
        }
    }
    else
        (void)printf("Affected rows: %lld\n", mysql_affected_rows(db));
    return true;
}


void mysqlMain(int mode)
{
    MYSQL *two;
    qDebug() << mysql_library_init(num_elements, server_options, server_groups) << endl;
    two = db_connect(NULL);
    db_do_query(two, "SHOW DATABASES",true);
    mysql_close(two);

    if (mode == MD_CREATE)
        CreateTest();
    else
        PerformTest();

    mysql_library_end();
}



(В качестве main-функции выступает mysqlMain).

Что получаем: при попытке запустить от от пользователя:
mysql_library_init возвращает 1. и ошибка:
Fatal error: Can't open and lock privilege tables: Can't find file: '/var/lib/mysql/mysql/host.frm' (errno: 13)

При поыпытке запустить через sudo (хотя причем тут sudo и файл привилегий вообще?) на этапе mysql_real_connect получаем
Access denied for user 'root'@'localhost' (using password: NO)

Согласно инструкции, embedded-сервер по умолчанию не запрашивает привилегий. Тем не менее, тут он их требует. В чем может быть дело?

Неактивен

 

#6 21.04.2011 16:50:38

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: MySQL embedded как SQLite

А в конфиге у Вас написано?

Неактивен

 

#7 21.04.2011 17:00:40

xcom256
Участник
Зарегистрирован: 19.04.2011
Сообщений: 6

Re: MySQL embedded как SQLite

в конфиге:

# my.cnf

[libmysqd_server]
datadir = ./data
language = ./english
skip-innodb

[libmysqld_client]
language = ./english

Папки data и english существуют, english скопирована из /usr/share/mysql.



По совету людей удалил весь mysql подчистую, предварительно поместив libmysqld в папку с программой, указав линковщику, где библиотеку искать. Скомпилил, запустил. теперь mysql_library_init возвращает 1, а mysql_init нулевой указатель.

Похоже, косяк где-то в libmysqld.a. Ставил версию из репозиториев (5.1). Известно ли что-нибудь на этот счет?

Неактивен

 

#8 21.04.2011 21:48:19

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: MySQL embedded как SQLite

А ошибку не возвращает?

Неактивен

 

#9 22.04.2011 12:41:50

xcom256
Участник
Зарегистрирован: 19.04.2011
Сообщений: 6

Re: MySQL embedded как SQLite

Из документации по mysql_init:


Errors

In case of insufficient memory, NULL is returned.

Чтобы посмотреть текст ошибки, должен быть создан mysql объект, т.е. mysql_init должен завершится успешно. Однако этого не происходит, и все падает, т.е. нельзе посмотреть текст ошибки, т.к. объект mysql банально не создается при отсутствии установленного mysql

Неактивен

 

#10 22.04.2011 14:22:06

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: MySQL embedded как SQLite

Что-то Вы делаете страшное и ужасное.

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "mysql.h"

MYSQL *mysql;
MYSQL_RES *results;
MYSQL_ROW record;

static char *server_options[] = { "", "--defaults-file=my.cnf" };
int num_elements = sizeof(server_options)/ sizeof(char *);

static char *server_groups[] = { "mysqld", NULL };

int main(void)
{
    mysql_library_init(num_elements, server_options, server_groups);
    mysql = mysql_init(NULL);
    mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, "libmysqld_client");
    mysql_options(mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);

    printf("connecting\n");
    mysql_real_connect(mysql, NULL,NULL,NULL, NULL, 0,NULL,0);
    printf("error = %s\n", mysql_error(mysql));

    printf("selecting\n");
    mysql_query(mysql, "SELECT 1, VERSION()");
    printf("error = %s\n", mysql_error(mysql));

    printf("storing\n");
    results = mysql_store_result(mysql);
    printf("error = %s\n", mysql_error(mysql));

    while((record = mysql_fetch_row(results)))
        printf("result: %s - %s \n", record[0], record[1]);

    mysql_free_result(results);
    mysql_close(mysql);
    mysql_library_end();

    return 0;
}


silentia:~/tmp$ cat my.cnf
[mysqld]
datadir=./data
silentia:~/tmp$ cat Makefile
blah: a.c
    g++ -I/usr/include/mysql -L/usr/lib/mysql a.c -o blah -lz -lmysqld -lpthread -ldl -lcrypt
silentia:~/tmp$ ls data
mysql/
silentia:~/tmp$ ./blah
connecting
error =
selecting
error =
storing
error =
result: 1 - 5.1.53-1-embedded

Неактивен

 

#11 22.04.2011 15:22:12

xcom256
Участник
Зарегистрирован: 19.04.2011
Сообщений: 6

Re: MySQL embedded как SQLite

Спасибо за пример! В точности его скопировал, переустановил заново, под чистую mysql, скомпилировал пример, и встретил уже знакомые ошибки. mysql_library_init требует файл привилегий, выдает 1, после чего mysql_init возвращает NULL. Если запускать из-под рута, то:

xcom@xcom:~/Proging/Job/tmp$ sudo ./blah
connecting
error = Access denied for user 'root'@'localhost' (using password: NO)
selecting
error = MySQL server has gone away
storing
error = MySQL server has gone away
Ошибка сегментирования



Возникает такой вопрос: А где вы брали собственно mysql?

Неактивен

 

#12 22.04.2011 16:02:00

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: MySQL embedded как SQLite

Воо, Вам не хватило прав подсоединиться к базе. Нужно выдать права,
чтобы root@localhost мог присоединиться без пароля. Можете схитрить
и прописать user и password в раздел libmysqld_client my.cnf. Ну или
подсунуть таки базу mysql с правильными грантами, записанными внутри.

Под sudo запускать не нужно! Скорее всего, в my.cnf Вы указали плохой
путь к базе. В идеале путь должен быть абсолютным. Может быть ./data,
но просто data быть не может. И у текущего пользователя должны быть
права для записи в этот каталог и все файлы, разумеется.

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson