kexi

kexidb/utils.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2004-2007 Jaroslaw Staniek <js@iidea.pl>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "utils.h"
21#include "cursor.h"
22#include "drivermanager.h"
23#include "lookupfieldschema.h"
24
25#include <tqmap.h>
26#include <tqthread.h>
27#include <tqdom.h>
28#include <tqintdict.h>
29#include <tqbuffer.h>
30
31#include <kdebug.h>
32#include <tdelocale.h>
33#include <kstaticdeleter.h>
34#include <tdemessagebox.h>
35#include <tdelocale.h>
36#include <kiconloader.h>
37
38#include "utils_p.h"
39
40using namespace KexiDB;
41
43struct TypeCache
44{
45 TQMap< uint, TypeGroupList > tlist;
46 TQMap< uint, TQStringList > nlist;
47 TQMap< uint, TQStringList > slist;
48 TQMap< uint, Field::Type > def_tlist;
49};
50
51static KStaticDeleter<TypeCache> KexiDB_typeCacheDeleter;
52TypeCache *KexiDB_typeCache = 0;
53
54static void initList()
55{
56 KexiDB_typeCacheDeleter.setObject( KexiDB_typeCache, new TypeCache() );
57
58 for (uint t=0; t<=KexiDB::Field::LastType; t++) {
59 const uint tg = KexiDB::Field::typeGroup( t );
60 TypeGroupList list;
61 TQStringList name_list, str_list;
62 if (KexiDB_typeCache->tlist.find( tg )!=KexiDB_typeCache->tlist.end()) {
63 list = KexiDB_typeCache->tlist[ tg ];
64 name_list = KexiDB_typeCache->nlist[ tg ];
65 str_list = KexiDB_typeCache->slist[ tg ];
66 }
67 list+= t;
68 name_list += KexiDB::Field::typeName( t );
69 str_list += KexiDB::Field::typeString( t );
70 KexiDB_typeCache->tlist[ tg ] = list;
71 KexiDB_typeCache->nlist[ tg ] = name_list;
72 KexiDB_typeCache->slist[ tg ] = str_list;
73 }
74
75 KexiDB_typeCache->def_tlist[ Field::InvalidGroup ] = Field::InvalidType;
76 KexiDB_typeCache->def_tlist[ Field::TextGroup ] = Field::Text;
77 KexiDB_typeCache->def_tlist[ Field::IntegerGroup ] = Field::Integer;
78 KexiDB_typeCache->def_tlist[ Field::FloatGroup ] = Field::Double;
79 KexiDB_typeCache->def_tlist[ Field::BooleanGroup ] = Field::Boolean;
80 KexiDB_typeCache->def_tlist[ Field::DateTimeGroup ] = Field::Date;
81 KexiDB_typeCache->def_tlist[ Field::BLOBGroup ] = Field::BLOB;
82}
83
84const TypeGroupList KexiDB::typesForGroup(KexiDB::Field::TypeGroup typeGroup)
85{
86 if (!KexiDB_typeCache)
87 initList();
88 return KexiDB_typeCache->tlist[ typeGroup ];
89}
90
92{
93 if (!KexiDB_typeCache)
94 initList();
95 return KexiDB_typeCache->nlist[ typeGroup ];
96}
97
99{
100 if (!KexiDB_typeCache)
101 initList();
102 return KexiDB_typeCache->slist[ typeGroup ];
103}
104
106{
107 if (!KexiDB_typeCache)
108 initList();
109 return (typeGroup <= Field::LastTypeGroup) ? KexiDB_typeCache->def_tlist[ typeGroup ] : Field::InvalidType;
110}
111
112void KexiDB::getHTMLErrorMesage(Object* obj, TQString& msg, TQString &details)
113{
114 Connection *conn = 0;
115 if (!obj || !obj->error()) {
116 if (dynamic_cast<Cursor*>(obj)) {
117 conn = dynamic_cast<Cursor*>(obj)->connection();
118 obj = conn;
119 }
120 else {
121 return;
122 }
123 }
124// if (dynamic_cast<Connection*>(obj)) {
125 // conn = dynamic_cast<Connection*>(obj);
126 //}
127 if (!obj || !obj->error())
128 return;
129 //lower level message is added to the details, if there is alread message specified
130 if (!obj->msgTitle().isEmpty())
131 msg += "<p>" + obj->msgTitle();
132
133 if (msg.isEmpty())
134 msg = "<p>" + obj->errorMsg();
135 else
136 details += "<p>" + obj->errorMsg();
137
138 if (!obj->serverErrorMsg().isEmpty())
139 details += "<p><b><nobr>" +i18n("Message from server:") + "</nobr></b><br>" + obj->serverErrorMsg();
140 if (!obj->recentSQLString().isEmpty())
141 details += "<p><b><nobr>" +i18n("SQL statement:") + TQString("</nobr></b><br><tt>%1</tt>").arg(obj->recentSQLString());
142 int serverResult;
143 TQString serverResultName;
144 if (obj->serverResult()!=0) {
145 serverResult = obj->serverResult();
146 serverResultName = obj->serverResultName();
147 }
148 else {
149 serverResult = obj->previousServerResult();
150 serverResultName = obj->previousServerResultName();
151 }
152 if (!serverResultName.isEmpty())
153 details += (TQString("<p><b><nobr>")+i18n("Server result name:")+"</nobr></b><br>"+serverResultName);
154 if (!details.isEmpty()
155 && (!obj->serverErrorMsg().isEmpty() || !obj->recentSQLString().isEmpty() || !serverResultName.isEmpty() || serverResult!=0) )
156 {
157 details += (TQString("<p><b><nobr>")+i18n("Server result number:")+"</nobr></b><br>"+TQString::number(serverResult));
158 }
159
160 if (!details.isEmpty() && !details.startsWith("<qt>")) {
161 if (details.startsWith("<p>"))
162 details = TQString::fromLatin1("<qt>")+details;
163 else
164 details = TQString::fromLatin1("<qt><p>")+details;
165 }
166}
167
168void KexiDB::getHTMLErrorMesage(Object* obj, TQString& msg)
169{
170 getHTMLErrorMesage(obj, msg, msg);
171}
172
174{
175 getHTMLErrorMesage(obj, result->msg, result->desc);
176}
177
178int KexiDB::idForObjectName( Connection &conn, const TQString& objName, int objType )
179{
180 RowData data;
181 if (true!=conn.querySingleRecord(TQString("select o_id from kexi__objects where lower(o_name)='%1' and o_type=%2")
182 .arg(objName.lower()).arg(objType), data))
183 return 0;
184 bool ok;
185 int id = data[0].toInt(&ok);
186 return ok ? id : 0;
187}
188
189//-----------------------------------------
190
192 : m_name(name)
193{
194 m_table = conn->tableSchema(TQString(name));
195 m_query = m_table ? 0 : conn->querySchema(TQString(name));
196 if (!m_table && !m_query)
197 KexiDBWarn << "TableOrQuery(FieldList &tableOrQuery) : "
198 " tableOrQuery is neither table nor query!" << endl;
199}
200
202 : m_name(name)
203 , m_table(table ? conn->tableSchema(TQString(name)) : 0)
204 , m_query(table ? 0 : conn->querySchema(TQString(name)))
205{
206 if (table && !m_table)
207 KexiDBWarn << "TableOrQuery(Connection *conn, const TQCString& name, bool table) : "
208 "no table specified!" << endl;
209 if (!table && !m_query)
210 KexiDBWarn << "TableOrQuery(Connection *conn, const TQCString& name, bool table) : "
211 "no query specified!" << endl;
212}
213
215 : m_table(dynamic_cast<TableSchema*>(&tableOrQuery))
216 , m_query(dynamic_cast<QuerySchema*>(&tableOrQuery))
217{
218 if (!m_table && !m_query)
219 KexiDBWarn << "TableOrQuery(FieldList &tableOrQuery) : "
220 " tableOrQuery is nether table nor query!" << endl;
221}
222
224{
225 m_table = conn->tableSchema(id);
226 m_query = m_table ? 0 : conn->querySchema(id);
227 if (!m_table && !m_query)
228 KexiDBWarn << "TableOrQuery(Connection *conn, int id) : no table or query found for id=="
229 << id << "!" << endl;
230}
231
233 : m_table(table)
234 , m_query(0)
235{
236 if (!m_table)
237 KexiDBWarn << "TableOrQuery(TableSchema* table) : no table specified!" << endl;
238}
239
241 : m_table(0)
242 , m_query(query)
243{
244 if (!m_query)
245 KexiDBWarn << "TableOrQuery(QuerySchema* query) : no query specified!" << endl;
246}
247
249{
250 if (m_table)
251 return m_table->fieldCount();
252 if (m_query)
253 return m_query->fieldsExpanded().size();
254 return 0;
255}
256
257const QueryColumnInfo::Vector TableOrQuerySchema::columns(bool unique)
258{
259 if (m_table)
260 return m_table->query()->fieldsExpanded(unique ? QuerySchema::Unique : QuerySchema::Default);
261
262 if (m_query)
263 return m_query->fieldsExpanded(unique ? QuerySchema::Unique : QuerySchema::Default);
264
265 KexiDBWarn << "TableOrQuerySchema::column() : no query or table specified!" << endl;
266 return QueryColumnInfo::Vector();
267}
268
270{
271 if (m_table)
272 return m_table->name().latin1();
273 if (m_query)
274 return m_query->name().latin1();
275 return m_name;
276}
277
279{
280 SchemaData *sdata = m_table ? static_cast<SchemaData *>(m_table) : static_cast<SchemaData *>(m_query);
281 if (!sdata)
282 return m_name;
283 return sdata->caption().isEmpty() ? sdata->name() : sdata->caption();
284}
285
287{
288 if (m_table)
289 return m_table->field(name);
290 if (m_query)
291 return m_query->field(name);
292
293 return 0;
294}
295
297{
298 if (m_table)
299 return m_table->query()->columnInfo(name);
300
301 if (m_query)
302 return m_query->columnInfo(name);
303
304 return 0;
305}
306
308{
309 if (m_table)
310 return m_table->debugString();
311 else if (m_query)
312 return m_query->debugString();
313 return TQString();
314}
315
317{
318 if (m_table)
319 return m_table->debug();
320 else if (m_query)
321 return m_query->debug();
322}
323
325{
326 if (m_table)
327 return m_table->connection();
328 else if (m_query)
329 return m_query->connection();
330 return 0;
331}
332
333
334//------------------------------------------
335
336class ConnectionTestThread : public TQThread {
337 public:
338 ConnectionTestThread(ConnectionTestDialog *dlg, const KexiDB::ConnectionData& connData);
339 virtual void run();
340 protected:
341 ConnectionTestDialog* m_dlg;
342 KexiDB::ConnectionData m_connData;
343};
344
345ConnectionTestThread::ConnectionTestThread(ConnectionTestDialog* dlg, const KexiDB::ConnectionData& connData)
346 : m_dlg(dlg), m_connData(connData)
347{
348}
349
350void ConnectionTestThread::run()
351{
352 KexiDB::DriverManager manager;
353 KexiDB::Driver* drv = manager.driver(m_connData.driverName);
354// KexiGUIMessageHandler msghdr;
355 if (!drv || manager.error()) {
356//move msghdr.showErrorMessage(&Kexi::driverManager());
357 m_dlg->error(&manager);
358 return;
359 }
360 KexiDB::Connection * conn = drv->createConnection(m_connData);
361 if (!conn || drv->error()) {
362//move msghdr.showErrorMessage(drv);
363 delete conn;
364 m_dlg->error(drv);
365 return;
366 }
367 if (!conn->connect() || conn->error()) {
368//move msghdr.showErrorMessage(conn);
369 m_dlg->error(conn);
370 delete conn;
371 return;
372 }
373 // SQL database backends like PostgreSQL require executing "USE database"
374 // if we really want to know connection to the server succeeded.
375 TQString tmpDbName;
376 if (!conn->useTemporaryDatabaseIfNeeded( tmpDbName )) {
377 m_dlg->error(conn);
378 delete conn;
379 return;
380 }
381 delete conn;
382 m_dlg->error(0);
383}
384
385ConnectionTestDialog::ConnectionTestDialog(TQWidget* parent,
386 const KexiDB::ConnectionData& data,
387 KexiDB::MessageHandler& msgHandler)
388 : KProgressDialog(parent, "testconn_dlg",
389 i18n("Test Connection"), i18n("<qt>Testing connection to <b>%1</b> database server...</qt>")
390 .arg(data.serverInfoString(true)), true /*modal*/)
391 , m_thread(new ConnectionTestThread(this, data))
392 , m_connData(data)
393 , m_msgHandler(&msgHandler)
394 , m_elapsedTime(0)
395 , m_errorObj(0)
396 , m_stopWaiting(false)
397{
398 showCancelButton(true);
399 progressBar()->setPercentageVisible(false);
400 progressBar()->setTotalSteps(0);
401 connect(&m_timer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotTimeout()));
402 adjustSize();
403 resize(250, height());
404}
405
406ConnectionTestDialog::~ConnectionTestDialog()
407{
408 m_wait.wakeAll();
409 m_thread->terminate();
410 delete m_thread;
411}
412
413int ConnectionTestDialog::exec()
414{
415 m_timer.start(20);
416 m_thread->start();
417 const int res = KProgressDialog::exec();
418 m_thread->wait();
419 m_timer.stop();
420 return res;
421}
422
423void ConnectionTestDialog::slotTimeout()
424{
425// KexiDBDbg << "ConnectionTestDialog::slotTimeout() " << m_errorObj << endl;
426 bool notResponding = false;
427 if (m_elapsedTime >= 1000*5) {//5 seconds
428 m_stopWaiting = true;
429 notResponding = true;
430 }
431 if (m_stopWaiting) {
432 m_timer.disconnect(this);
433 m_timer.stop();
434 slotCancel();
435// reject();
436// close();
437 if (m_errorObj) {
438 m_msgHandler->showErrorMessage(m_errorObj);
439 m_errorObj = 0;
440 }
441 else if (notResponding) {
442 KMessageBox::sorry(0,
443 i18n("<qt>Test connection to <b>%1</b> database server failed. The server is not responding.</qt>")
444 .arg(m_connData.serverInfoString(true)),
445 i18n("Test Connection"));
446 }
447 else {
448 KMessageBox::information(0,
449 i18n("<qt>Test connection to <b>%1</b> database server established successfully.</qt>")
450 .arg(m_connData.serverInfoString(true)),
451 i18n("Test Connection"));
452 }
453// slotCancel();
454// reject();
455 m_wait.wakeAll();
456 return;
457 }
458 m_elapsedTime += 20;
459 progressBar()->setProgress( m_elapsedTime );
460}
461
462void ConnectionTestDialog::error(KexiDB::Object *obj)
463{
464 KexiDBDbg << "ConnectionTestDialog::error()" << endl;
465 m_stopWaiting = true;
466 m_errorObj = obj;
467/* reject();
468 m_msgHandler->showErrorMessage(obj);
469 if (obj) {
470 }
471 else {
472 accept();
473 }*/
474 m_wait.wait();
475}
476
477void ConnectionTestDialog::slotCancel()
478{
479// m_wait.wakeAll();
480 m_thread->terminate();
481 m_timer.disconnect(this);
482 m_timer.stop();
483 KProgressDialog::slotCancel();
484}
485
486void KexiDB::connectionTestDialog(TQWidget* parent, const KexiDB::ConnectionData& data,
487 KexiDB::MessageHandler& msgHandler)
488{
489 ConnectionTestDialog dlg(parent, data, msgHandler);
490 dlg.exec();
491}
492
493int KexiDB::rowCount(Connection &conn, const TQString& sql)
494{
495 int count = -1; //will be changed only on success of querySingleNumber()
496 TQString selectSql( TQString::fromLatin1("SELECT COUNT() FROM (") + sql + ")" );
497 conn.querySingleNumber(selectSql, count);
498 return count;
499}
500
502{
504 if (!tableSchema.connection()) {
505 KexiDBWarn << "KexiDB::rowsCount(const KexiDB::TableSchema&): no tableSchema.connection() !" << endl;
506 return -1;
507 }
508 int count = -1; //will be changed only on success of querySingleNumber()
509 tableSchema.connection()->querySingleNumber(
510 TQString::fromLatin1("SELECT COUNT(*) FROM ")
511 + tableSchema.connection()->driver()->escapeIdentifier(tableSchema.name()),
512 count
513 );
514 return count;
515}
516
518{
520 if (!querySchema.connection()) {
521 KexiDBWarn << "KexiDB::rowsCount(const KexiDB::QuerySchema&): no querySchema.connection() !" << endl;
522 return -1;
523 }
524 int count = -1; //will be changed only on success of querySingleNumber()
525 querySchema.connection()->querySingleNumber(
526 TQString::fromLatin1("SELECT COUNT(*) FROM (")
527 + querySchema.connection()->selectStatement(querySchema) + ")",
528 count
529 );
530 return count;
531}
532
534{
535 if (tableOrQuery.table())
536 return rowCount( *tableOrQuery.table() );
537 if (tableOrQuery.query())
538 return rowCount( *tableOrQuery.query() );
539 return -1;
540}
541
543{
544 if (tableOrQuery.table())
545 return tableOrQuery.table()->fieldCount();
546 if (tableOrQuery.query())
547 return tableOrQuery.query()->fieldsExpanded().count();
548 return -1;
549}
550
551TQMap<TQString,TQString> KexiDB::toMap( const ConnectionData& data )
552{
553 TQMap<TQString,TQString> m;
554 m["caption"] = data.caption;
555 m["description"] = data.description;
556 m["driverName"] = data.driverName;
557 m["hostName"] = data.hostName;
558 m["port"] = TQString::number(data.port);
559 m["useLocalSocketFile"] = TQString::number((int)data.useLocalSocketFile);
560 m["localSocketFileName"] = data.localSocketFileName;
561 m["password"] = data.password;
562 m["savePassword"] = TQString::number((int)data.savePassword);
563 m["userName"] = data.userName;
564 m["fileName"] = data.fileName();
565 return m;
566}
567
568void KexiDB::fromMap( const TQMap<TQString,TQString>& map, ConnectionData& data )
569{
570 data.caption = map["caption"];
571 data.description = map["description"];
572 data.driverName = map["driverName"];
573 data.hostName = map["hostName"];
574 data.port = map["port"].toInt();
575 data.useLocalSocketFile = map["useLocalSocketFile"].toInt()==1;
576 data.localSocketFileName = map["localSocketFileName"];
577 data.password = map["password"];
578 data.savePassword = map["savePassword"].toInt()==1;
579 data.userName = map["userName"];
580 data.setFileName(map["fileName"]);
581}
582
583bool KexiDB::splitToTableAndFieldParts(const TQString& string,
584 TQString& tableName, TQString& fieldName,
586{
587 const int id = string.find('.');
588 if (option & SetFieldNameIfNoTableName && id==-1) {
589 tableName = TQString();
590 fieldName = string;
591 return !fieldName.isEmpty();
592 }
593 if (id<=0 || id==int(string.length()-1))
594 return false;
595 tableName = string.left(id);
596 fieldName = string.mid(id+1);
597 return !tableName.isEmpty() && !fieldName.isEmpty();
598}
599
605
606TQString KexiDB::formatNumberForVisibleDecimalPlaces(double value, int decimalPlaces)
607{
609 if (decimalPlaces < 0) {
610 TQString s( TQString::number(value, 'f', 10 /*reasonable precision*/));
611 uint i = s.length()-1;
612 while (i>0 && s[i]=='0')
613 i--;
614 if (s[i]=='.') //remove '.'
615 i--;
616 s = s.left(i+1).replace('.', TDEGlobal::locale()->decimalSymbol());
617 return s;
618 }
619 if (decimalPlaces == 0)
620 return TQString::number((int)value);
621 return TDEGlobal::locale()->formatNumber(value, decimalPlaces);
622}
623
625{
626 if (type<(int)KexiDB::Field::InvalidType || type>(int)KexiDB::Field::LastType) {
627 KexiDBWarn << "KexiDB::intToFieldType(): invalid type " << type << endl;
629 }
630 return (KexiDB::Field::Type)type;
631}
632
633static bool setIntToFieldType( Field& field, const TQVariant& value )
634{
635 bool ok;
636 const int intType = value.toInt(&ok);
637 if (!ok || KexiDB::Field::InvalidType == intToFieldType(intType)) {//for sanity
638 KexiDBWarn << "KexiDB::setFieldProperties(): invalid type" << endl;
639 return false;
640 }
641 field.setType((KexiDB::Field::Type)intType);
642 return true;
643}
644
646static KStaticDeleter< TQAsciiDict<char> > KexiDB_builtinFieldPropertiesDeleter;
648TQAsciiDict<char>* KexiDB_builtinFieldProperties = 0;
649
650bool KexiDB::isBuiltinTableFieldProperty( const TQCString& propertyName )
651{
652 if (!KexiDB_builtinFieldProperties) {
653 KexiDB_builtinFieldPropertiesDeleter.setObject( KexiDB_builtinFieldProperties, new TQAsciiDict<char>(499) );
654#define ADD(name) KexiDB_builtinFieldProperties->insert(name, (char*)1)
655 ADD("type");
656 ADD("primaryKey");
657 ADD("indexed");
658 ADD("autoIncrement");
659 ADD("unique");
660 ADD("notNull");
661 ADD("allowEmpty");
662 ADD("unsigned");
663 ADD("name");
664 ADD("caption");
665 ADD("description");
666 ADD("length");
667 ADD("precision");
668 ADD("defaultValue");
669 ADD("width");
670 ADD("visibleDecimalPlaces");
672#undef ADD
673 }
674 return KexiDB_builtinFieldProperties->find( propertyName );
675}
676
677bool KexiDB::setFieldProperties( Field& field, const TQMap<TQCString, TQVariant>& values )
678{
679 TQMapConstIterator<TQCString, TQVariant> it;
680 if ( (it = values.find("type")) != values.constEnd() ) {
681 if (!setIntToFieldType(field, *it))
682 return false;
683 }
684
685#define SET_BOOLEAN_FLAG(flag, value) { \
686 constraints |= KexiDB::Field::flag; \
687 if (!value) \
688 constraints ^= KexiDB::Field::flag; \
689 }
690
691 uint constraints = field.constraints();
692 bool ok = true;
693 if ( (it = values.find("primaryKey")) != values.constEnd() )
694 SET_BOOLEAN_FLAG(PrimaryKey, (*it).toBool());
695 if ( (it = values.find("indexed")) != values.constEnd() )
696 SET_BOOLEAN_FLAG(Indexed, (*it).toBool());
697 if ( (it = values.find("autoIncrement")) != values.constEnd()
699 SET_BOOLEAN_FLAG(AutoInc, (*it).toBool());
700 if ( (it = values.find("unique")) != values.constEnd() )
701 SET_BOOLEAN_FLAG(Unique, (*it).toBool());
702 if ( (it = values.find("notNull")) != values.constEnd() )
703 SET_BOOLEAN_FLAG(NotNull, (*it).toBool());
704 if ( (it = values.find("allowEmpty")) != values.constEnd() )
705 SET_BOOLEAN_FLAG(NotEmpty, !(*it).toBool());
706 field.setConstraints( constraints );
707
708 uint options = 0;
709 if ( (it = values.find("unsigned")) != values.constEnd()) {
710 options |= KexiDB::Field::Unsigned;
711 if (!(*it).toBool())
712 options ^= KexiDB::Field::Unsigned;
713 }
714 field.setOptions( options );
715
716 if ( (it = values.find("name")) != values.constEnd())
717 field.setName( (*it).toString() );
718 if ( (it = values.find("caption")) != values.constEnd())
719 field.setCaption( (*it).toString() );
720 if ( (it = values.find("description")) != values.constEnd())
721 field.setDescription( (*it).toString() );
722 if ( (it = values.find("length")) != values.constEnd())
723 field.setLength( (*it).isNull() ? 0/*default*/ : (*it).toUInt(&ok) );
724 if (!ok)
725 return false;
726 if ( (it = values.find("precision")) != values.constEnd())
727 field.setPrecision( (*it).isNull() ? 0/*default*/ : (*it).toUInt(&ok) );
728 if (!ok)
729 return false;
730 if ( (it = values.find("defaultValue")) != values.constEnd())
731 field.setDefaultValue( *it );
732 if ( (it = values.find("width")) != values.constEnd())
733 field.setWidth( (*it).isNull() ? 0/*default*/ : (*it).toUInt(&ok) );
734 if (!ok)
735 return false;
736 if ( (it = values.find("visibleDecimalPlaces")) != values.constEnd()
738 field.setVisibleDecimalPlaces( (*it).isNull() ? -1/*default*/ : (*it).toInt(&ok) );
739 if (!ok)
740 return false;
741
742 // set custom properties
743 typedef TQMap<TQCString, TQVariant> PropertiesMap;
744 foreach( PropertiesMap::ConstIterator, it, values ) {
745 if (!isBuiltinTableFieldProperty( it.key() ) && !isExtendedTableFieldProperty( it.key() )) {
746 field.setCustomProperty( it.key(), it.data() );
747 }
748 }
749 return true;
750#undef SET_BOOLEAN_FLAG
751}
752
754static KStaticDeleter< TQAsciiDict<char> > KexiDB_extendedPropertiesDeleter;
756TQAsciiDict<char>* KexiDB_extendedProperties = 0;
757
758bool KexiDB::isExtendedTableFieldProperty( const TQCString& propertyName )
759{
760 if (!KexiDB_extendedProperties) {
761 KexiDB_extendedPropertiesDeleter.setObject( KexiDB_extendedProperties, new TQAsciiDict<char>(499, false) );
762#define ADD(name) KexiDB_extendedProperties->insert(name, (char*)1)
763 ADD("visibleDecimalPlaces");
764 ADD("rowSource");
765 ADD("rowSourceType");
766 ADD("rowSourceValues");
767 ADD("boundColumn");
768 ADD("visibleColumn");
769 ADD("columnWidths");
770 ADD("showColumnHeaders");
771 ADD("listRows");
772 ADD("limitToList");
773 ADD("displayWidget");
774#undef ADD
775 }
776 return KexiDB_extendedProperties->find( propertyName );
777}
778
779bool KexiDB::setFieldProperty( Field& field, const TQCString& propertyName, const TQVariant& value )
780{
781#define SET_BOOLEAN_FLAG(flag, value) { \
782 constraints |= KexiDB::Field::flag; \
783 if (!value) \
784 constraints ^= KexiDB::Field::flag; \
785 field.setConstraints( constraints ); \
786 return true; \
787 }
788#define GET_INT(method) { \
789 const uint ival = value.toUInt(&ok); \
790 if (!ok) \
791 return false; \
792 field.method( ival ); \
793 return true; \
794 }
795
796 if (propertyName.isEmpty())
797 return false;
798
799 bool ok;
800 if (KexiDB::isExtendedTableFieldProperty(propertyName)) {
801 //a little speedup: identify extended property in O(1)
802 if ( "visibleDecimalPlaces" == propertyName
804 {
805 GET_INT( setVisibleDecimalPlaces );
806 }
807 else {
808 if (!field.table()) {
809 KexiDBWarn << TQString("KexiDB::setFieldProperty() Cannot set \"%1\" property - no table assinged for field!")
810 .arg(propertyName.data()) << endl;
811 }
812 else {
813 LookupFieldSchema *lookup = field.table()->lookupFieldSchema(field);
814 const bool hasLookup = lookup != 0;
815 if (!hasLookup)
816 lookup = new LookupFieldSchema();
817 if (LookupFieldSchema::setProperty( *lookup, propertyName, value )) {
818 if (!hasLookup && lookup)
819 field.table()->setLookupFieldSchema( field.name(), lookup );
820 return true;
821 }
822 delete lookup;
823 }
824 }
825 }
826 else {//non-extended
827 if ( "type" == propertyName )
828 return setIntToFieldType(field, value);
829
830 uint constraints = field.constraints();
831 if ( "primaryKey" == propertyName )
832 SET_BOOLEAN_FLAG(PrimaryKey, value.toBool());
833 if ( "indexed" == propertyName )
834 SET_BOOLEAN_FLAG(Indexed, value.toBool());
835 if ( "autoIncrement" == propertyName
837 SET_BOOLEAN_FLAG(AutoInc, value.toBool());
838 if ( "unique" == propertyName )
839 SET_BOOLEAN_FLAG(Unique, value.toBool());
840 if ( "notNull" == propertyName )
841 SET_BOOLEAN_FLAG(NotNull, value.toBool());
842 if ( "allowEmpty" == propertyName )
843 SET_BOOLEAN_FLAG(NotEmpty, !value.toBool());
844
845 uint options = 0;
846 if ( "unsigned" == propertyName ) {
847 options |= KexiDB::Field::Unsigned;
848 if (!value.toBool())
849 options ^= KexiDB::Field::Unsigned;
850 field.setOptions( options );
851 return true;
852 }
853
854 if ( "name" == propertyName ) {
855 if (value.toString().isEmpty())
856 return false;
857 field.setName( value.toString() );
858 return true;
859 }
860 if ( "caption" == propertyName ) {
861 field.setCaption( value.toString() );
862 return true;
863 }
864 if ( "description" == propertyName ) {
865 field.setDescription( value.toString() );
866 return true;
867 }
868 if ( "length" == propertyName )
869 GET_INT( setLength );
870 if ( "precision" == propertyName )
871 GET_INT( setPrecision );
872 if ( "defaultValue" == propertyName ) {
873 field.setDefaultValue( value );
874 return true;
875 }
876 if ( "width" == propertyName )
877 GET_INT( setWidth );
878
879 // last chance that never fails: custom field property
880 field.setCustomProperty(propertyName, value);
881 }
882
883 KexiDBWarn << "KexiDB::setFieldProperty() property \"" << propertyName << "\" not found!" << endl;
884 return false;
885#undef SET_BOOLEAN_FLAG
886#undef GET_INT
887}
888
889int KexiDB::loadIntPropertyValueFromDom( const TQDomNode& node, bool* ok )
890{
891 TQCString valueType = node.nodeName().latin1();
892 if (valueType.isEmpty() || valueType!="number") {
893 if (ok)
894 *ok = false;
895 return 0;
896 }
897 const TQString text( TQDomNode(node).toElement().text() );
898 int val = text.toInt(ok);
899 return val;
900}
901
902TQString KexiDB::loadStringPropertyValueFromDom( const TQDomNode& node, bool* ok )
903{
904 TQCString valueType = node.nodeName().latin1();
905 if (valueType!="string") {
906 if (ok)
907 *ok = false;
908 return 0;
909 }
910 return TQDomNode(node).toElement().text();
911}
912
913TQVariant KexiDB::loadPropertyValueFromDom( const TQDomNode& node )
914{
915 TQCString valueType = node.nodeName().latin1();
916 if (valueType.isEmpty())
917 return TQVariant();
918 const TQString text( TQDomNode(node).toElement().text() );
919 bool ok;
920 if (valueType == "string") {
921 return text;
922 }
923 else if (valueType == "cstring") {
924 return TQCString(text.latin1());
925 }
926 else if (valueType == "number") { // integer or double
927 if (text.find('.')!=-1) {
928 double val = text.toDouble(&ok);
929 if (ok)
930 return val;
931 }
932 else {
933 const int val = text.toInt(&ok);
934 if (ok)
935 return val;
936 const TQ_LLONG valLong = text.toLongLong(&ok);
937 if (ok)
938 return valLong;
939 }
940 }
941 else if (valueType == "bool") {
942 return TQVariant(text.lower()=="true" || text=="1");
943 }
945 KexiDBWarn << "loadPropertyValueFromDom(): unknown type '" << valueType << "'" << endl;
946 return TQVariant();
947}
948
949TQDomElement KexiDB::saveNumberElementToDom(TQDomDocument& doc, TQDomElement& parentEl,
950 const TQString& elementName, int value)
951{
952 TQDomElement el( doc.createElement(elementName) );
953 parentEl.appendChild( el );
954 TQDomElement numberEl( doc.createElement("number") );
955 el.appendChild( numberEl );
956 numberEl.appendChild( doc.createTextNode( TQString::number(value) ) );
957 return el;
958}
959
960TQDomElement KexiDB::saveBooleanElementToDom(TQDomDocument& doc, TQDomElement& parentEl,
961 const TQString& elementName, bool value)
962{
963 TQDomElement el( doc.createElement(elementName) );
964 parentEl.appendChild( el );
965 TQDomElement numberEl( doc.createElement("bool") );
966 el.appendChild( numberEl );
967 numberEl.appendChild( doc.createTextNode(
968 value ? TQString::fromLatin1("true") : TQString::fromLatin1("false") ) );
969 return el;
970}
971
973static KStaticDeleter< TQValueVector<TQVariant> > KexiDB_emptyValueForTypeCacheDeleter;
974TQValueVector<TQVariant> *KexiDB_emptyValueForTypeCache = 0;
975
977{
978 if (!KexiDB_emptyValueForTypeCache) {
979 KexiDB_emptyValueForTypeCacheDeleter.setObject( KexiDB_emptyValueForTypeCache,
980 new TQValueVector<TQVariant>(int(Field::LastType)+1) );
981#define ADD(t, value) (*KexiDB_emptyValueForTypeCache)[t]=value;
982 ADD(Field::Byte, 0);
983 ADD(Field::ShortInteger, 0);
984 ADD(Field::Integer, 0);
985 ADD(Field::BigInteger, 0);
986 ADD(Field::Boolean, TQVariant(false));
987 ADD(Field::Float, 0.0);
988 ADD(Field::Double, 0.0);
990 ADD(Field::Text, TQString(" "));
991 ADD(Field::LongText, TQString(" "));
992 ADD(Field::BLOB, TQByteArray());
993#undef ADD
994 }
995 const TQVariant val( KexiDB_emptyValueForTypeCache->at(
996 (type<=Field::LastType) ? type : Field::InvalidType) );
997 if (!val.isNull())
998 return val;
999 else { //special cases
1000 if (type==Field::Date)
1001 return TQDate::currentDate();
1002 if (type==Field::DateTime)
1003 return TQDateTime::currentDateTime();
1004 if (type==Field::Time)
1005 return TQTime::currentTime();
1006 }
1007 KexiDBWarn << "KexiDB::emptyValueForType() no value for type "
1008 << Field::typeName(type) << endl;
1009 return TQVariant();
1010}
1011
1013static KStaticDeleter< TQValueVector<TQVariant> > KexiDB_notEmptyValueForTypeCacheDeleter;
1014TQValueVector<TQVariant> *KexiDB_notEmptyValueForTypeCache = 0;
1015
1017{
1018 if (!KexiDB_notEmptyValueForTypeCache) {
1019 KexiDB_notEmptyValueForTypeCacheDeleter.setObject( KexiDB_notEmptyValueForTypeCache,
1020 new TQValueVector<TQVariant>(int(Field::LastType)+1) );
1021#define ADD(t, value) (*KexiDB_notEmptyValueForTypeCache)[t]=value;
1022 // copy most of the values
1023 for (int i = int(Field::InvalidType) + 1; i<=Field::LastType; i++) {
1024 if (i==Field::Date || i==Field::DateTime || i==Field::Time)
1025 continue; //'current' value will be returned
1026 if (i==Field::Text || i==Field::LongText) {
1027 ADD(i, TQVariant(TQString("")));
1028 continue;
1029 }
1030 if (i==Field::BLOB) {
1032 TQByteArray ba;
1033 TQBuffer buffer( ba );
1034 buffer.open( IO_WriteOnly );
1035 TQPixmap pm(SmallIcon("document-new"));
1036 pm.save( &buffer, "PNG" );
1037 ADD(i, ba);
1038 continue;
1039 }
1041 }
1042#undef ADD
1043 }
1044 const TQVariant val( KexiDB_notEmptyValueForTypeCache->at(
1045 (type<=Field::LastType) ? type : Field::InvalidType) );
1046 if (!val.isNull())
1047 return val;
1048 else { //special cases
1049 if (type==Field::Date)
1050 return TQDate::currentDate();
1051 if (type==Field::DateTime)
1052 return TQDateTime::currentDateTime();
1053 if (type==Field::Time)
1054 return TQTime::currentTime();
1055 }
1056 KexiDBWarn << "KexiDB::notEmptyValueForType() no value for type "
1057 << Field::typeName(type) << endl;
1058 return TQVariant();
1059}
1060
1061TQString KexiDB::escapeBLOB(const TQByteArray& array, BLOBEscapingType type)
1062{
1063 const int size = array.size();
1064 if (size==0)
1065 return TQString();
1066 int escaped_length = size*2;
1067 if (type == BLOBEscape0xHex || type == BLOBEscapeOctal)
1068 escaped_length += 2/*0x or X'*/;
1069 else if (type == BLOBEscapeXHex)
1070 escaped_length += 3; //X' + '
1071 TQString str;
1072 str.reserve(escaped_length);
1073 if (str.capacity() < (uint)escaped_length) {
1074 KexiDBWarn << "KexiDB::Driver::escapeBLOB(): no enough memory (cannot allocate "<<
1075 escaped_length<<" chars)" << endl;
1076 return TQString();
1077 }
1078 if (type == BLOBEscapeXHex)
1079 str = TQString::fromLatin1("X'");
1080 else if (type == BLOBEscape0xHex)
1081 str = TQString::fromLatin1("0x");
1082 else if (type == BLOBEscapeOctal)
1083 str = TQString::fromLatin1("'");
1084
1085 int new_length = str.length(); //after X' or 0x, etc.
1086 if (type == BLOBEscapeOctal) {
1087 // only escape nonprintable characters as in Table 8-7:
1088 // http://www.postgresql.org/docs/8.1/interactive/datatype-binary.html
1089 // i.e. escape for bytes: < 32, >= 127, 39 ('), 92(\‍).
1090 for (int i = 0; i < size; i++) {
1091 const unsigned char val = array[i];
1092 if (val<32 || val>=127 || val==39 || val==92) {
1093 str[new_length++] = '\\';
1094 str[new_length++] = '\\';
1095 str[new_length++] = '0' + val/64;
1096 str[new_length++] = '0' + (val % 64) / 8;
1097 str[new_length++] = '0' + val % 8;
1098 }
1099 else {
1100 str[new_length++] = val;
1101 }
1102 }
1103 }
1104 else {
1105 for (int i = 0; i < size; i++) {
1106 const unsigned char val = array[i];
1107 str[new_length++] = (val/16) < 10 ? ('0'+(val/16)) : ('A'+(val/16)-10);
1108 str[new_length++] = (val%16) < 10 ? ('0'+(val%16)) : ('A'+(val%16)-10);
1109 }
1110 }
1111 if (type == BLOBEscapeXHex || type == BLOBEscapeOctal)
1112 str[new_length++] = '\'';
1113 return str;
1114}
1115
1116TQByteArray KexiDB::pgsqlByteaToByteArray(const char* data, int length)
1117{
1118 TQByteArray array;
1119 int output=0;
1120 for (int pass=0; pass<2; pass++) {//2 passes to avoid allocating buffer twice:
1121 // 0: count #of chars; 1: copy data
1122 const char* s = data;
1123 const char* end = s + length;
1124 if (pass==1) {
1125 KexiDBDbg << "processBinaryData(): real size == " << output << endl;
1126 array.resize(output);
1127 output=0;
1128 }
1129 for (int input=0; s < end; output++) {
1130 // KexiDBDbg<<(int)s[0]<<" "<<(int)s[1]<<" "<<(int)s[2]<<" "<<(int)s[3]<<" "<<(int)s[4]<<endl;
1131 if (s[0]=='\\' && (s+1)<end) {
1132 //special cases as in http://www.postgresql.org/docs/8.1/interactive/datatype-binary.html
1133 if (s[1]=='\'') {// \'
1134 if (pass==1)
1135 array[output] = '\'';
1136 s+=2;
1137 }
1138 else if (s[1]=='\\') { // 2 backslashes
1139 if (pass==1)
1140 array[output] = '\\';
1141 s+=2;
1142 }
1143 else if ((input+3)<length) {// \\xyz where xyz are 3 octal digits
1144 if (pass==1)
1145 array[output] = char( (int(s[1]-'0')*8+int(s[2]-'0'))*8+int(s[3]-'0') );
1146 s+=4;
1147 }
1148 else {
1149 KexiDBDrvWarn << "processBinaryData(): no octal value after backslash" << endl;
1150 s++;
1151 }
1152 }
1153 else {
1154 if (pass==1)
1155 array[output] = s[0];
1156 s++;
1157 }
1158 // KexiDBDbg<<output<<": "<<(int)array[output]<<endl;
1159 }
1160 }
1161 return array;
1162}
1163
1164TQString KexiDB::variantToString( const TQVariant& v )
1165{
1166 if (v.type()==TQVariant::ByteArray)
1167 return KexiDB::escapeBLOB(v.toByteArray(), KexiDB::BLOBEscapeHex);
1168 return v.toString();
1169}
1170
1171TQVariant KexiDB::stringToVariant( const TQString& s, TQVariant::Type type, bool &ok )
1172{
1173 if (s.isNull()) {
1174 ok = true;
1175 return TQVariant();
1176 }
1177 if (TQVariant::Invalid==type) {
1178 ok = false;
1179 return TQVariant();
1180 }
1181 if (type==TQVariant::ByteArray) {//special case: hex string
1182 const uint len = s.length();
1183 TQByteArray ba(len/2 + len%2);
1184 for (uint i=0; i<(len-1); i+=2) {
1185 int c = s.mid(i,2).toInt(&ok, 16);
1186 if (!ok) {
1187 KexiDBWarn << "KexiDB::stringToVariant(): Error in digit " << i << endl;
1188 return TQVariant();
1189 }
1190 ba[i/2] = (char)c;
1191 }
1192 ok = true;
1193 return ba;
1194 }
1195 TQVariant result(s);
1196 if (!result.cast( type )) {
1197 ok = false;
1198 return TQVariant();
1199 }
1200 ok = true;
1201 return result;
1202}
1203
1205{
1206 return field && !field->isUniqueKey();
1207}
1208
1209void KexiDB::getLimitsForType(Field::Type type, int &minValue, int &maxValue)
1210{
1211 switch (type) {
1212 case Field::Byte:
1214 minValue = 0;
1215 maxValue = 255;
1216 break;
1218 minValue = -32768;
1219 maxValue = 32767;
1220 break;
1221 case Field::Integer:
1222 case Field::BigInteger: //cannot return anything larger
1223 default:
1224 minValue = (int)-0x07FFFFFFF;
1225 maxValue = (int)(0x080000000-1);
1226 }
1227}
1228
1229void KexiDB::debugRowData(const RowData& rowData)
1230{
1231 KexiDBDbg << TQString("ROW DATA (%1 columns):").arg(rowData.count()) << endl;
1232 foreach(RowData::ConstIterator, it, rowData)
1233 KexiDBDbg << "- " << (*it) << endl;
1234}
1235
1237{
1239 return Field::InvalidType;
1240 if (t1==t2)
1241 return t2;
1243 return t1;
1244 if (t1==Field::Integer && t2!=Field::BigInteger)
1245 return t1;
1246 if (t1==Field::BigInteger)
1247 return t1;
1248 return KexiDB::maximumForIntegerTypes(t2, t1); //swap
1249}
1250
1251TQString KexiDB::simplifiedTypeName(const Field& field)
1252{
1253 if (field.isNumericType())
1254 return i18n("Number"); //simplify
1255 else if (field.type() == Field::BLOB)
1257 return i18n("Image"); //simplify
1258
1259 return field.typeGroupName();
1260}
1261
1262#include "utils_p.moc"
bool savePassword
True if password should be saved to a file for the connection.
TQString caption
The caption of the connection.
TQString localSocketFileName
Name of local (named) socket file.
TQString description
The additional description for the connection.
TQString userName
Username used for the connection.
TQString password
Password used for the connection.
TQString driverName
the name of the driver that should be used to create a connection
unsigned short int port
Port used for the remote connection.
TQString hostName
Host name used for the remote connection.
bool useLocalSocketFile
True if local socket file should be used instead of TCP/IP port.
Database specific connection data, e.g. host, port.
void setFileName(const TQString &fn)
Set the filename used by the connection.
TQString fileName() const
Get the filename used by the connection.
Provides database connection, allowing queries and data modification.
Definition connection.h:62
TableSchema * tableSchema(int tableId)
TQString selectStatement(QuerySchema &querySchema, const TQValueList< TQVariant > &params, const SelectStatementOptions &options=SelectStatementOptions()) const
QuerySchema * querySchema(int queryId)
tristate querySingleNumber(const TQString &sql, int &number, uint column=0, bool addLimitTo1=true)
bool useTemporaryDatabaseIfNeeded(TQString &tmpdbName)
Driver * driver() const
Definition connection.h:78
tristate querySingleRecord(const TQString &sql, RowData &data, bool addLimitTo1=true)
bool connect()
Connects to driver with given parameters.
Provides database cursor functionality.
Definition cursor.h:67
Driver * driver(const TQString &name)
TQString escapeIdentifier(const TQString &str, int options=EscapeDriver|EscapeAsNecessary) const
Driver-specific identifier escaping (e.g. for a table name, db name, etc.).
Definition driver.cpp:316
Connection * createConnection(ConnectionData &conn_data, int options=0)
Definition driver.cpp:178
uint fieldCount() const
Definition fieldlist.h:58
Meta-data for a field.
Definition field.h:73
TQString typeName() const
Definition field.h:298
bool isAutoIncrementAllowed() const
Definition field.h:396
@ ShortInteger
Definition field.h:86
@ InvalidType
Definition field.h:84
TQString typeString() const
Definition field.h:308
bool isFPNumericType() const
Definition field.h:266
bool isIntegerType() const
Definition field.h:259
void setType(Type t)
Definition field.cpp:330
TypeGroup typeGroup() const
Definition field.h:301
Provides information about lookup field's setup.
static bool setProperty(LookupFieldSchema &lookup, const TQCString &propertyName, const TQVariant &value)
bool error() const
Definition object.h:38
virtual TQString serverResultName()
Definition object.cpp:154
TQString msgTitle() const
Definition object.h:100
virtual TQString serverErrorMsg()
Definition object.cpp:144
virtual int serverResult()
Definition object.cpp:149
const TQString recentSQLString() const
Definition object.h:105
int previousServerResult() const
Definition object.h:49
const TQString & errorMsg() const
Definition object.h:42
Helper class that assigns additional information for the column in a query.
Definition queryschema.h:49
KexiDB::QuerySchema provides information about database query.
Connection * connection() const
@ Default
All fields are returned even if duplicated.
@ Unique
Unique list of fields is returned.
QueryColumnInfo::Vector fieldsExpanded(FieldsExpandedOptions options=Default)
TQString desc
error message and detailed description, both empty by default
Definition error.h:131
TableSchema * m_table
and we still want name() and acptionOrName() work.
Field * field(const TQString &name)
QueryColumnInfo * columnInfo(const TQString &name)
const QueryColumnInfo::Vector columns(bool unique=false)
QuerySchema * query() const
TableSchema * table() const
Connection * connection() const
TableOrQuerySchema(Connection *conn, const TQCString &name)
TQString captionOrName() const
Connection * connection() const
High-level database connectivity library with database backend drivers.
KEXI_DB_EXPORT TQDomElement saveBooleanElementToDom(TQDomDocument &doc, TQDomElement &parentEl, const TQString &elementName, bool value)
KEXI_DB_EXPORT bool isDefaultValueAllowed(Field *field)
KEXI_DB_EXPORT TQVariant stringToVariant(const TQString &s, TQVariant::Type type, bool &ok)
KEXI_DB_EXPORT void connectionTestDialog(TQWidget *parent, const ConnectionData &data, MessageHandler &msgHandler)
KEXI_DB_EXPORT bool supportsVisibleDecimalPlacesProperty(Field::Type type)
KEXI_DB_EXPORT TQVariant emptyValueForType(Field::Type type)
KEXI_DB_EXPORT TQString simplifiedTypeName(const Field &field)
int rowCount(Connection &conn, const TQString &sql)
KEXI_DB_EXPORT Field::Type maximumForIntegerTypes(Field::Type t1, Field::Type t2)
KEXI_DB_EXPORT TQStringList typeStringsForGroup(Field::TypeGroup typeGroup)
KEXI_DB_EXPORT TQVariant loadPropertyValueFromDom(const TQDomNode &node)
KEXI_DB_EXPORT TQVariant notEmptyValueForType(Field::Type type)
KEXI_DB_EXPORT TQString escapeBLOB(const TQByteArray &array, BLOBEscapingType type)
KEXI_DB_EXPORT bool setFieldProperty(Field &field, const TQCString &propertyName, const TQVariant &value)
KEXI_DB_EXPORT bool isBuiltinTableFieldProperty(const TQCString &propertyName)
KEXI_DB_EXPORT Field::Type intToFieldType(int type)
KEXI_DB_EXPORT void fromMap(const TQMap< TQString, TQString > &map, ConnectionData &data)
KEXI_DB_EXPORT bool isExtendedTableFieldProperty(const TQCString &propertyName)
TQValueVector< TQVariant > RowData
structure for storing single record with type information
Definition connection.h:47
KEXI_DB_EXPORT TQStringList typeNamesForGroup(Field::TypeGroup typeGroup)
KEXI_DB_EXPORT const TypeGroupList typesForGroup(Field::TypeGroup typeGroup)
KEXI_DB_EXPORT bool setFieldProperties(Field &field, const TQMap< TQCString, TQVariant > &values)
KEXI_DB_EXPORT TQString loadStringPropertyValueFromDom(const TQDomNode &node, bool *ok)
KEXI_DB_EXPORT TQMap< TQString, TQString > toMap(const ConnectionData &data)
KEXI_DB_EXPORT int loadIntPropertyValueFromDom(const TQDomNode &node, bool *ok)
KEXI_DB_EXPORT int fieldCount(TableOrQuerySchema &tableOrQuery)
KEXI_DB_EXPORT TQString formatNumberForVisibleDecimalPlaces(double value, int decimalPlaces)
KEXI_DB_EXPORT TQString variantToString(const TQVariant &v)
KEXI_DB_EXPORT TQByteArray pgsqlByteaToByteArray(const char *data, int length)
BLOBEscapingType
Escaping types used in escapeBLOB().
@ BLOBEscapeXHex
escaping like X'1FAD', used by sqlite (hex numbers)
@ BLOBEscapeOctal
@ BLOBEscape0xHex
escaping like 0x1FAD, used by mysql (hex numbers)
@ BLOBEscapeHex
escaping like 1FAD without quotes or prefixes
KEXI_DB_EXPORT bool splitToTableAndFieldParts(const TQString &string, TQString &tableName, TQString &fieldName, SplitToTableAndFieldPartsOptions option=FailIfNoTableOrFieldName)
KEXI_DB_EXPORT void getLimitsForType(Field::Type type, int &minValue, int &maxValue)
KEXI_DB_EXPORT int idForObjectName(Connection &conn, const TQString &objName, int objType)
KEXI_DB_EXPORT void debugRowData(const RowData &rowData)
KEXI_DB_EXPORT TQDomElement saveNumberElementToDom(TQDomDocument &doc, TQDomElement &parentEl, const TQString &elementName, int value)
SplitToTableAndFieldPartsOptions
Used in splitToTableAndFieldParts().
@ SetFieldNameIfNoTableName
see splitToTableAndFieldParts()
KEXI_DB_EXPORT void getHTMLErrorMesage(Object *obj, TQString &msg, TQString &details)
KEXI_DB_EXPORT Field::Type defaultTypeForGroup(Field::TypeGroup typeGroup)