Russian Qt Forum

Qt => Базы данных => Тема начата: MechanicalBear от Декабрь 08, 2008, 09:57



Название: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 08, 2008, 09:57
Срочно нужна помощь!
Есть класс
Код:
8  class smartQuery: public QSqlQuery
9  {
10 //Q_OBJECT
11 private:
12     QString         query;
13     QString         order;
14     QStringList     keys;
15     QVariantList    values;
16     Debugger        *dbg;
17
18 public:
19             smartQuery  ( QSqlResult * );
20             smartQuery  ( const QString &query = QString(), QSqlDatabase db = QSqlDatabase());
21             smartQuery  ( QSqlDatabase db);
22             smartQuery  ( const QSqlQuery & other);
23
24     bool    exec        (const QString str);
25
26     void    addKey      (QString key);
27     void    addValue    (QString key, const QVariant value);
28     void    setOrder    (QString key);
29
30     void    select      (QString table,
31                             /* WHERE */
32                             QString key = QString(),
33                             QVariant value = QVariant(),
34                             QString sign = QString()
35                             );
36     void    insert      (QString table);
37     void    update      (QString table, /* WHERE */ QString key, QVariant value);
38     void    remove      (QString table, /* WHERE */ QString key, QVariant value);
39 };
Debugger используется для вывода сообщений и прочих дебагов. в конструкторе инициализируется.
перегрузили метод exec(QString);
Код:
 24 bool    smartQuery::exec        (const QString str)
 25 { 
 26     bool result = false;
 27   
 28     keys.clear(); 
 29     values.clear();
 30     order.clear();
 31           
 32     dbg->sql(str);
 33     //clear ();
 34     dbg->sql(str);
 35
 36     //QSqlQuery::prepare(str);
 37     //result = QSqlQuery::exec();
 38     result = QSqlQuery::exec(str);
 39   
 40     if (lastError().isValid())
 41     {
 42         dbg->wrn(lastError().text());
 43         result = false;   
 44     }                     
 45     return result;         
 46 }
создаем объект класса и вызываем exec.
Код:
smartQuery sq;
sq.exec("SELECT * FROM table");
программа слетает segfault-ом при обращении к методам родителя. то есть
Код:
 32     dbg->sql(str);
 33     //clear ();
 34     dbg->sql(str);
 35
 36     //QSqlQuery::prepare(str);
 37     //result = QSqlQuery::exec();
 38     result = QSqlQuery::exec(str);
слетает на QSqlQuery::exec(str);
если раскоментировать clear() = слетит там.
gdb показывает:
Код:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1225332512 (LWP 16800)]
0xb6b79cf3 in mysql_next_result () from /usr/lib/libmysqlclient_r.so.15


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 08, 2008, 10:21
перегрузили метод exec(QString);
Код:
 24 bool    smartQuery::exec        (const QString str)
Ты не перегрузил метод exec().
Описание метода exec:
Код:
bool QSqlQuery::exec( const QString & str );
Сравни со своим (передача строки или передача ссылки на строку).

Почему ты везде передаешь в метод строку, а не константную ссылку?


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 08, 2008, 10:58
Спасибо за помощь!
Перегрузил:
Код:
 24 bool    smartQuery::exec        ()
 25 {
 26     return QSqlQuery::exec();
 27 }
изменил параметр для exec(QString&)
ничего не изменилось =(
приложил файл реализации. может будет удобнее.
изменил методы exec на virtual bool
появился warning при компиляции
Код:
../smartQuery/src/smartQuery.h:9: предупреждение: ‘class smartQuery’ has virtual functions but non-virtual destructor
если добавить деструктор - будет 
Код:
undefined reference to `smartQuery::~smartQuery()'
после добавления virtual - тоже всё по прежнему =(


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 08, 2008, 11:07
А версия Qt какая?
В Qt3 exec( const QString &) - виртуальный, а в Qt4 - нет.


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 08, 2008, 12:05
Qt 4.3.
Я попробовал просто наудачу. Щас сделал как было.
Почему ошибка происходит когда выполняется метод родителя?
то есть либо exec() либо clear() - и все segfault
может в конструкторах что-то?


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 08, 2008, 12:09
А у тебя компилябельный пример есть? Можешь сделать простой проект только с этим классом?


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 08, 2008, 12:31
во вложении.
всё компилится и работает =-O

в основном проекте не хочет =(


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 08, 2008, 12:40
во вложении.
всё компилится и работает =-O

в основном проекте не хочет =(
Сделай нормальный конструктор копирования и оператор присвоения.


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 08, 2008, 12:59
Цитировать
Оказывается explicit скрывает конструктор так, как даже private не может. Т.е. его как будто нет. Во втором случае вызовется конструктор для double без каких-либо предупреждений, что может быть довольно неожиданным поворотом событий. Будьте бдительны.

Конечно, если написать explicit для обоих конструкторов, то будет все в порядке и не будет таких опасных ситуаций. Поэтому explicit следует писать для всех конструкторов с одним параметром.

/usr/include/qt4/Qt/qsqlquery.h
Код:
 59     QSqlQuery(QSqlResult *r);
 60     QSqlQuery(const QString& query = QString(), QSqlDatabase db = QSqlDatabase());
 61     explicit QSqlQuery(QSqlDatabase db);
 62     QSqlQuery(const QSqlQuery& other);
 63     QSqlQuery& operator=(const QSqlQuery& other);
 64     ~QSqlQuery();

я чето ваще уже ниче не понимаю %(


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 08, 2008, 13:09
Определи:
Код:
smartQuery( const smartQuery & );
smartQuery &operator=( const smartQuery & );


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 08, 2008, 13:27
а можно использовать swap?
Код:
smartQuery &operator=( const smartQuery & other)
{
    swap(other);
    return *this;
}
или как правильно присвоить родителя?


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 08, 2008, 13:50
Код:
smartQuery &TestQuery::operator=( const smartQuery &query )
{
*((QSqlQuery*)this) = (const QSqlQuery&)query; [1]
// QSqlQuery::operator=( (const QSqlQuery &)query ); [2]
return *this;
}
Или первый или второй вариант.


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 08, 2008, 14:02
при компиляции warning:
Код:
../smartQuery/src/smartQuery.cpp: In copy constructor ‘smartQuery::smartQuery(const smartQuery&)’:
../smartQuery/src/smartQuery.cpp:23: предупреждение: base class ‘class QSqlQuery’ should be explicitly initialized in the copy constructor

Код:
29     qDebug() << QObject::tr("Конструктор без параметров");
30     smartQuery sq;
31     smartQuery sq3;
32
33     qDebug() << QObject::tr("Конструктор присваивания");
34     smartQuery sq2 = sq;
35
36     qDebug() << QObject::tr("Операция присваивания");
37     sq3 = sq2;
38
39     sq3.addKey("k");
40     sq3.addKey("value");
41     sq3.select("org");
выводит
Код:
"Конструктор без параметров" 
"Конструктор присваивания"
"Операция присваивания"
"знач 1"
"знач 2"
"знач 3"
...
а в основной опять та же херь! >_<


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 08, 2008, 14:18
а в основной опять та же херь! >_<
В тестовом примере класс работает, а в проекте нет?


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 08, 2008, 14:23
да.
щас кароче попробовал перед использованием объекта в основной использовать конструктор копирования
Код:
24     smartQuery sq2 = sq; 
25 
26     sq2.addKey("password");
27     sq2.addKey("fullname");
28     sq2.addKey("uid");
29     sq2.addKey("gid");
30     sq2.addKey("orgid");
31     sq2.addKey("orgsecid");
32     sq2.select(_tblUsers, "login", leLogin->text());
sq создается в хидере просто объектом (не указателем)
если использовать sq - будет segfault
если sq2 - всё пашет. =-O


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 08, 2008, 14:42
Такой еще вопрос. У smartQuery деструктора не описан, при его разрушении dbg не удаляется?


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 08, 2008, 15:10
нет. я пробовал создавать dbg объектом, а не указателем. та же песня.


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 08, 2008, 15:38
нет. я пробовал создавать dbg объектом, а не указателем. та же песня.
У меня не получается смоделировать segfault в тестовом примере. Если у тебя получиться это сделать, сбрось архив с проектом.


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 08, 2008, 16:01
ок. завтра. щас домой. спасибо за помощь!


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 09, 2008, 07:38
Код:
class Huis
{
        smartQuery sq;
public:
        void helo();
};

void Huis::helo()
{
        smartQuery sq2;

        sq.addKey("k");
        sq.addKey("value");
        sq.select("org");

        while (sq.next())
                qDebug() << sq.value(1).toString();
}

int main(int argc, char ** argv)
{
...
        Huis h;
        h.helo(); // это работает

        Huis *x;
        x->helo(); // это нет
...
}


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 09, 2008, 08:46
А объект создавать кто будет?

Код:
int main(int argc, char ** argv)
{
...
        Huis h;
        h.helo();

        Huis *x = new Huis;
        x->helo();
...
}


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 09, 2008, 09:04
А объект создавать кто будет?

Код:
int main(int argc, char ** argv)
{
...
        Huis h;
        h.helo();

        Huis *x = new Huis;
        x->helo();
...
}

Код:
Huis *x = new Huis;
Код:
Huis *x;
x = new Huis;
я чето не догоняю?


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 09, 2008, 09:09
я чето не догоняю?
В приведенном тобой выше примере, ты объявляешь указатель на Huis и сразу начинаешь его использовать, без создания самого объекта.


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 09, 2008, 09:13
я чето не догоняю?
В приведенном тобой выше примере, ты объявляешь указатель на Huis и сразу начинаешь его использовать, без создания самого объекта.

объект объявлен и сразу инициирован при помощи new. ты точно уверен что это может являться причиной?


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 09, 2008, 09:17
Код:
int main(int argc, char ** argv)
{
...
        Huis *x;
        x->helo(); // это нет
...
}

объект объявлен и сразу инициирован при помощи new. ты точно уверен что это может являться причиной?
Смотри, здесь объявлен указатель на объект Huis, сам объект еще не создан. Что-бы использовать указатель ему нужно присвоить валидное значение.


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 09, 2008, 09:20
А объект создавать кто будет?

Код:
int main(int argc, char ** argv)
{
...
        Huis h;
        h.helo();

        Huis *x = new Huis;
        x->helo();
...
}

сразу посмотрел в твой пост и не обратил внимания на свой. сорри.
щас разберусь с основным проектом.
тестовый работает.. почему??


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 09, 2008, 09:27
тестовый работает.. почему??
А тут может быть, что угодно.  :)
Где-то, что-то делаешь не так в основном проекте, не видя всего трудно что-то сказать определенное.
Ошибка может быть не обязательно в этом классе.


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 09, 2008, 09:28
Код:
  3 smartQuery::smartQuery  ( QSqlResult * result ) : QSqlQuery(result)
  4 {
  5     dbg.sql("Constructor by result");
  6 }
  7 smartQuery::smartQuery  ( const QString &str, QSqlDatabase db ) : QSqlQuery(str, db)
  8 {
  9     dbg.sql("Constructor by string and database");
 10 }
 11 smartQuery::smartQuery  ( QSqlDatabase db ) : QSqlQuery(db)
 12 {
 13     dbg.sql("Constructor by database");
 14 }
 15 smartQuery::smartQuery  ( const QSqlQuery & q ) : QSqlQuery(q)
 16 {
 17     dbg.sql("Constructor by query");
 18     *this = (const smartQuery&)q;
 19 } 
 20 smartQuery::smartQuery (const smartQuery & q)
 21 { 
 22     dbg.sql("Constructor by smartQuery");
 23     *this = q;
 24 } 
 25   
 26 smartQuery& smartQuery::operator= ( const smartQuery& q)
 27 {     
 28     dbg.sql("operator = smartQuery");
 29     query = q.query;
 30     order = q.order;
 31     keys = q.keys;
 32     values = q.values;
 33     *((QSqlQuery*)this) = (const QSqlQuery&)q;
 34     return *this;
 35 }
 36   
 37 smartQuery::~smartQuery()
 38 { 
 39     dbg.sql("destructor");
 40 }
на консоль выводит
Код:
Constructor by string and database
и всё равно рушится.
что делать с конструкторами? %(


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 09, 2008, 09:43
Пока я не смогу это воспроизвести у себя, трудно что-то сказать.
Покажи класс который использует smartQuery. Может там что-то. И заодно полностью покажи (h и cpp) smartQuery, в текущем виде.


Название: Re: Наследование. Segmentation fault
Отправлено: xintrea от Декабрь 09, 2008, 19:04
Выложи полный проект, в котором сегфолтица, не мучай людей догадками.


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 10, 2008, 13:58
Код:
../smartQuery/src/smartQuery.cpp: In copy constructor ‘smartQuery::smartQuery(const smartQuery&)’:
../smartQuery/src/smartQuery.cpp:21: предупреждение: base class ‘class QSqlQuery’ should be explicitly initialized in the copy constructor
что это значит?
похоже (я начинаю догадываться): базовый класс должен быть явно инициализирован в конструкторе копирования
буду пробовать


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 11, 2008, 13:59
всё же я нашел ответ на этот сегфолт =)
всё оказалось очень просто: Наследование QSqlQuery._Segfault (http://bsdhome.org/index.php/%D0%9D%D0%B0%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_QSqlQuery._Segfault)


Название: Re: Наследование. Segmentation fault
Отправлено: shade-khv от Декабрь 12, 2008, 03:06
Это у вас класс который реализует нормальную работу с запросами?


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 12, 2008, 07:14
да. более удобное использование запросов. отдельные методы update insert select. а также дополнительные проверки и отладочные сообщения


Название: Re: Наследование. Segmentation fault
Отправлено: shade-khv от Декабрь 12, 2008, 08:27
Насколько я понимаю готовый запрос распарсить на  order, keys, values класс не способен?

Вообще интересно, должен же быть какой то общий, эталонный, чтоли, алгоритм разбора запроса (по крайней мере соответсвующего стандарту) на части? Сами то СУБД его как то разбирают.
Хотя, по моему Posgtes использует yacc для разбора (не уверен).

У меня есть мой класс в PHP, который работает с запросами, но метод разбиения там написан топорно:
Код
PHP
function setSQL($string)    //принимает строку запроса и разбивает его на смысловые части (select-список полей, where-условие отбора строк, order by-порядок сортировки)
{
$string=trim($string, ';'); $s=strtolower($string);
$uparts=array();
$tokens=array(' where ', ' order by ', ' group by ', ' from '); //задаем слова, служащие точками разбиения запроса
$b=0;
for ($i=0; $i<strlen($s); $i++)
foreach ($tokens as $token) if (substr($s, $i, strlen($token))==$token) {$uparts[]=substr($string, $b, $i-$b); $b=$i+1;}
if (strlen($s)-$b) $uparts[]=substr($string, $b, strlen($s)-$b);
foreach ($uparts as $upart) //перебираем части разбитого запроса и определем их в соответствующие элементы ассоциативного массива.
{
if (strtolower(substr($upart,0,4))=='from') $this->SQL['from']=$upart;
if (strtolower(substr($upart,0,6))=='select') $this->SQL['select']=$upart;
if (strtolower(substr($upart,0,5))=='where') $this->SQL['where']=$upart;
if (strtolower(substr($upart,0,8))=='order by') $this->SQL['order']=$upart;
if (strtolower(substr($upart,0,8))=='group by') $this->SQL['group']=$upart;
}
}

А вообще грамотный класс работы с запросами мне очень-очень интересен.


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 12, 2008, 09:19
меня интересует один вопрос: зачем это нужно?
если ответишь - могу помочь, но несколько настораживает реализация. если нужно именно на PHP - думаю здесь не место.


Название: Re: Наследование. Segmentation fault
Отправлено: shade-khv от Декабрь 12, 2008, 09:52
Нет, на PHP у меня уже всё схвачено, я просто для примера привел.

Смысл такой что создавать объект проще. Можно создать его передав ему строку запроса (только что созданного и проверенного в PgAdmin-е, например). При создании в конструкторе строка разберется на where, sort, group и прочие части, каждую из которых можно легко менять. Например, чтобы позволить пользователю в процессе работы выбирать какие столбцы запрашивать из БД.


Название: Re: Наследование. Segmentation fault
Отправлено: shade-khv от Декабрь 12, 2008, 09:59
Просто я не совсем понял как будет строиться запрос если мы создали объект конструктором
 smartQuery      ( const QString &query = QString(), QSqlDatabase db = QSqlDatabase());


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 12, 2008, 10:40
допустим, часто используется конструкция добавить/изменить
Код
C++ (Qt)
smartQuery sq;
sq.addValue("value1", value1);
sq.addValue("value2", value2);
if (edit)
   sq.update(_table, "k", k);
else
   sq.insert(_table);
 
то есть smartQuery можно использовать как стандартную QSqlQuery с возможностью указать запрос в конструкторе, а также задействовать дополнительные методы, верные только для нее


Название: Re: Наследование. Segmentation fault
Отправлено: ритт от Декабрь 12, 2008, 10:53
Цитировать
QString QSqlDriver::escapeIdentifier ( const QString & identifier, IdentifierType type ) const   [virtual]
Returns the identifier escaped according to the database rules. identifier can either be a table name or field name, dependent on type.

Цитировать
QString QSqlDriver::formatValue ( const QSqlField & field, bool trimStrings = false ) const   [virtual]
Returns a string representation of the field value for the database. This is used, for example, when constructing INSERT and UPDATE statements.
The default implementation returns the value formatted as a string according to the following rules:
If field is character data, the value is returned enclosed in single quotation marks, which is appropriate for many SQL databases. Any embedded single-quote characters are escaped (replaced with two single-quote characters). If trimStrings is true (the default is false), all trailing whitespace is trimmed from the field.
If field is date/time data, the value is formatted in ISO format and enclosed in single quotation marks. If the date/time data is invalid, "NULL" is returned.
If field is bytearray data, and the driver can edit binary fields, the value is formatted as a hexadecimal string.
For any other field type, toString() is called on its value and the result of this is returned.

Цитировать
QString QSqlDriver::sqlStatement ( StatementType type, const QString & tableName, const QSqlRecord & rec, bool preparedStatement ) const   [virtual]
Returns a SQL statement of type type for the table tableName with the values from rec. If preparedStatement is true, the string will contain placeholders instead of values.
This method can be used to manipulate tables without having to worry about database-dependent SQL dialects. For non-prepared statements, the values will be properly escaped.


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 12, 2008, 13:30
Цитировать
QString QSqlDriver::escapeIdentifier ( const QString & identifier, IdentifierType type ) const   [virtual]
Returns the identifier escaped according to the database rules. identifier can either be a table name or field name, dependent on type.

Цитировать
QString QSqlDriver::formatValue ( const QSqlField & field, bool trimStrings = false ) const   [virtual]
Returns a string representation of the field value for the database. This is used, for example, when constructing INSERT and UPDATE statements.
The default implementation returns the value formatted as a string according to the following rules:
If field is character data, the value is returned enclosed in single quotation marks, which is appropriate for many SQL databases. Any embedded single-quote characters are escaped (replaced with two single-quote characters). If trimStrings is true (the default is false), all trailing whitespace is trimmed from the field.
If field is date/time data, the value is formatted in ISO format and enclosed in single quotation marks. If the date/time data is invalid, "NULL" is returned.
If field is bytearray data, and the driver can edit binary fields, the value is formatted as a hexadecimal string.
For any other field type, toString() is called on its value and the result of this is returned.

Цитировать
QString QSqlDriver::sqlStatement ( StatementType type, const QString & tableName, const QSqlRecord & rec, bool preparedStatement ) const   [virtual]
Returns a SQL statement of type type for the table tableName with the values from rec. If preparedStatement is true, the string will contain placeholders instead of values.
This method can be used to manipulate tables without having to worry about database-dependent SQL dialects. For non-prepared statements, the values will be properly escaped.
кхм.. это к чему?


Название: Re: Наследование. Segmentation fault
Отправлено: BRE от Декабрь 12, 2008, 13:39
кхм.. это к чему?
Это к тому, что есть штатные средства, которые формируют строки запросов, причем опираясь на специфику конкретной базы данных (в зависимости от драйвера).
 ;)


Название: Re: Наследование. Segmentation fault
Отправлено: MechanicalBear от Декабрь 15, 2008, 07:38
это не по моей теме