kexi

driver.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
3
4 This program 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 program 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 program; see the file COPYING. 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 <kexidb/driver.h>
21#include <kexidb/driver_p.h>
22#include <kexidb/drivermanager.h>
23#include <kexidb/drivermanager_p.h>
24#include "error.h"
25#include "drivermanager.h"
26#include "connection.h"
27#include "connectiondata.h"
28#include "admin.h"
29
30#include <tqfileinfo.h>
31
32#include <tdelocale.h>
33#include <kdebug.h>
34
35#include <assert.h>
36
37using namespace KexiDB;
38
41TQValueVector<TQString> dflt_typeNames;
42
43
44//---------------------------------------------
45
46
47DriverBehaviour::DriverBehaviour()
48 : UNSIGNED_TYPE_KEYWORD("UNSIGNED")
49 , AUTO_INCREMENT_FIELD_OPTION("AUTO_INCREMENT")
50 , AUTO_INCREMENT_PK_FIELD_OPTION("AUTO_INCREMENT PRIMARY KEY")
51 , SPECIAL_AUTO_INCREMENT_DEF(false)
52 , AUTO_INCREMENT_REQUIRES_PK(false)
53 , ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE(false)
54 , QUOTATION_MARKS_FOR_IDENTIFIER('"')
55 , USING_DATABASE_REQUIRED_TO_CONNECT(true)
56 , _1ST_ROW_READ_AHEAD_REQUIRED_TO_KNOW_IF_THE_RESULT_IS_EMPTY(false)
57 , SELECT_1_SUBQUERY_SUPPORTED(false)
58 , SQL_KEYWORDS(0)
59{
60}
61
62//---------------------------------------------
63
64Driver::Info::Info()
65 : fileBased(false)
66 , allowImportingTo(true)
67{
68}
69
70//---------------------------------------------
71
72Driver::Driver( TQObject *parent, const char *name, const TQStringList & )
73 : TQObject( parent, name )
74 , Object()
75 , beh( new DriverBehaviour() )
76 , d( new DriverPrivate() )
77{
78 d->connections.setAutoDelete(false);
79 //TODO: reasonable size
80 d->connections.resize(101);
81 d->typeNames.resize(Field::LastType + 1);
82
83 d->initKexiKeywords();
84}
85
86
87Driver::~Driver()
88{
89 DriverManagerInternal::self()->aboutDelete( this );
90// KexiDBDbg << "Driver::~Driver()" << endl;
91 TQPtrDictIterator<Connection> it( d->connections );
92 Connection *conn;
93 while ( (conn = it.toFirst()) ) {
94 delete conn;
95 }
96 delete beh;
97 delete d;
98// KexiDBDbg << "Driver::~Driver() ok" << endl;
99}
100
101bool Driver::isValid()
102{
103 clearError();
104 if (KexiDB::version().major != version().major
105 || KexiDB::version().minor != version().minor)
106 {
107 setError(ERR_INCOMPAT_DRIVER_VERSION,
108 i18n("Incompatible database driver's \"%1\" version: found version %2, expected version %3.")
109 .arg(name())
110 .arg(TQString("%1.%2").arg(version().major).arg(version().minor))
111 .arg(TQString("%1.%2").arg(KexiDB::version().major).arg(KexiDB::version().minor)));
112 return false;
113 }
114
115 TQString inv_impl = i18n("Invalid database driver's \"%1\" implementation:\n").arg(name());
116 TQString not_init = i18n("Value of \"%1\" is not initialized for the driver.");
117 if (beh->ROW_ID_FIELD_NAME.isEmpty()) {
118 setError(ERR_INVALID_DRIVER_IMPL, inv_impl + not_init.arg("DriverBehaviour::ROW_ID_FIELD_NAME"));
119 return false;
120 }
121
122 return true;
123}
124
125const TQPtrList<Connection> Driver::connectionsList() const
126{
127 TQPtrList<Connection> clist;
128 TQPtrDictIterator<Connection> it( d->connections );
129 for( ; it.current(); ++it )
130 clist.append( &(*it) );
131 return clist;
132}
133
135{ return d->fileDBDriverMimeType; }
136
138{ return TQString::fromLatin1("application/x-kexiproject-sqlite3"); }
139
145
146const KService* Driver::service() const
147{ return d->service; }
148
150{ return d->isFileDriver; }
151
153{ return d->features; }
154
156{ return d->features & (SingleTransactions | MultipleTransactions); }
157
159{
160 if (!d->adminTools)
161 d->adminTools = drv_createAdminTools();
162 return *d->adminTools;
163}
164
165AdminTools* Driver::drv_createAdminTools() const
166{
167 return new AdminTools(); //empty impl.
168}
169
170TQString Driver::sqlTypeName(int id_t, int /*p*/) const
171{
172 if (id_t > Field::InvalidType && id_t <= Field::LastType)
173 return d->typeNames[(id_t>0 && id_t<=Field::LastType) ? id_t : Field::InvalidType /*sanity*/];
174
175 return d->typeNames[Field::InvalidType];
176}
177
179{
180 clearError();
181 if (!isValid())
182 return 0;
183
184 if (d->isFileDriver) {
185 if (conn_data.fileName().isEmpty()) {
186 setError(ERR_MISSING_DB_LOCATION, i18n("File name expected for file-based database driver.") );
187 return 0;
188 }
189 }
190// Connection *conn = new Connection( this, conn_data );
191 Connection *conn = drv_createConnection( conn_data );
192
193 conn->setReadOnly(options & ReadOnlyConnection);
194
195 conn_data.driverName = name();
196 d->connections.insert( conn, conn );
197 return conn;
198}
199
201{
202 clearError();
203 return d->connections.take( conn );
204}
205
207{
208 if (id_t>=Field::Null)
209 return "Null";
210 if (dflt_typeNames.isEmpty()) {
211 dflt_typeNames.resize(Field::LastType + 1);
212 dflt_typeNames[Field::InvalidType]="InvalidType";
213 dflt_typeNames[Field::Byte]="Byte";
214 dflt_typeNames[Field::ShortInteger]="ShortInteger";
215 dflt_typeNames[Field::Integer]="Integer";
216 dflt_typeNames[Field::BigInteger]="BigInteger";
217 dflt_typeNames[Field::Boolean]="Boolean";
218 dflt_typeNames[Field::Date]="Date";
219 dflt_typeNames[Field::DateTime]="DateTime";
220 dflt_typeNames[Field::Time]="Time";
221 dflt_typeNames[Field::Float]="Float";
222 dflt_typeNames[Field::Double]="Double";
223 dflt_typeNames[Field::Text]="Text";
224 dflt_typeNames[Field::LongText]="LongText";
225 dflt_typeNames[Field::BLOB]="BLOB";
226 }
227 return dflt_typeNames[id_t];
228}
229
230bool Driver::isSystemObjectName( const TQString& n ) const
231{
233}
234
235bool Driver::isKexiDBSystemObjectName( const TQString& n )
236{
237 if (!n.lower().startsWith("kexi__"))
238 return false;
239 const TQStringList list( Connection::kexiDBSystemTableNames() );
240 return list.find(n.lower())!=list.constEnd();
241}
242
243bool Driver::isSystemFieldName( const TQString& n ) const
244{
245 if (!beh->ROW_ID_FIELD_NAME.isEmpty() && n.lower()==beh->ROW_ID_FIELD_NAME.lower())
246 return true;
247 return drv_isSystemFieldName(n);
248}
249
250TQString Driver::valueToSQL( uint ftype, const TQVariant& v ) const
251{
252 if (v.isNull())
253 return "NULL";
254 switch (ftype) {
255 case Field::Text:
256 case Field::LongText: {
257 TQString s = v.toString();
258 return escapeString(s); //TQString("'")+s.replace( '"', "\\\"" ) + "'";
259 }
260 case Field::Byte:
262 case Field::Integer:
264 return v.toString();
265 case Field::Float:
266 case Field::Double: {
267 if (v.type()==TQVariant::String) {
268 //workaround for values stored as string that should be casted to floating-point
269 TQString s(v.toString());
270 return s.replace(',', ".");
271 }
272 return v.toString();
273 }
274//TODO: here special encoding method needed
275 case Field::Boolean:
276 return TQString::number(v.toInt()?1:0); //0 or 1
277 case Field::Time:
278 return TQString("\'")+v.toTime().toString(TQt::ISODate)+"\'";
279 case Field::Date:
280 return TQString("\'")+v.toDate().toString(TQt::ISODate)+"\'";
281 case Field::DateTime:
282 return dateTimeToSQL( v.toDateTime() );
283 case Field::BLOB: {
284 if (v.toByteArray().isEmpty())
285 return TQString::fromLatin1("NULL");
286 if (v.type()==TQVariant::String)
287 return escapeBLOB(v.toString().utf8());
288 return escapeBLOB(v.toByteArray());
289 }
291 return "!INVALIDTYPE!";
292 default:
293 KexiDBDbg << "Driver::valueToSQL(): UNKNOWN!" << endl;
294 return TQString();
295 }
296 return TQString();
297}
298
299TQVariant Driver::propertyValue( const TQCString& propName ) const
300{
301 return d->properties[propName.lower()];
302}
303
304TQString Driver::propertyCaption( const TQCString& propName ) const
305{
306 return d->propertyCaptions[propName.lower()];
307}
308
309TQValueList<TQCString> Driver::propertyNames() const
310{
311 TQValueList<TQCString> names = d->properties.keys();
312 qHeapSort(names);
313 return names;
314}
315
316TQString Driver::escapeIdentifier(const TQString& str, int options) const
317{
318 TQCString cstr = str.latin1();
319 return TQString(escapeIdentifier(cstr, options));
320}
321
322TQCString Driver::escapeIdentifier(const TQCString& str, int options) const
323{
324 bool needOuterQuotes = false;
325
326// Need to use quotes if ...
327// ... we have been told to, or ...
328 if(options & EscapeAlways)
329 needOuterQuotes = true;
330
331// ... or if the driver does not have a list of keywords,
332 else if(!d->driverSQLDict)
333 needOuterQuotes = true;
334
335// ... or if it's a keyword in Kexi's SQL dialect,
336 else if(d->kexiSQLDict->find(str))
337 needOuterQuotes = true;
338
339// ... or if it's a keyword in the backends SQL dialect,
340// (have already checked !d->driverSQLDict)
341 else if((options & EscapeDriver) && d->driverSQLDict->find(str))
342 needOuterQuotes = true;
343
344// ... or if the identifier has a space in it...
345 else if(str.find(' ') != -1)
346 needOuterQuotes = true;
347
348 if(needOuterQuotes && (options & EscapeKexi)) {
349 const char quote = '"';
350 return quote + TQCString(str).replace( quote, "\"\"" ) + quote;
351 }
352 else if (needOuterQuotes) {
353 const char quote = beh->QUOTATION_MARKS_FOR_IDENTIFIER.latin1();
354 return quote + drv_escapeIdentifier(str) + quote;
355 } else {
356 return drv_escapeIdentifier(str);
357 }
358}
359
360void Driver::initSQLKeywords(int hashSize) {
361
362 if(!d->driverSQLDict && beh->SQL_KEYWORDS != 0) {
363 d->initDriverKeywords(beh->SQL_KEYWORDS, hashSize);
364 }
365}
366
367#include "driver.moc"
An interface containing a set of tools for database administration.
Definition admin.h:34
TQString driverName
the name of the driver that should be used to create a connection
Database specific connection data, e.g. host, port.
TQString fileName() const
Get the filename used by the connection.
Provides database connection, allowing queries and data modification.
Definition connection.h:62
static const TQStringList & kexiDBSystemTableNames()
Database driver management, e.g. finding and loading drivers.
TQString lookupByMime(const TQString &mimeType)
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
const TQPtrList< Connection > connectionsList() const
Definition driver.cpp:125
virtual TQString dateTimeToSQL(const TQDateTime &v) const
Definition driver.h:237
bool transactionsSupported() const
Definition driver.cpp:155
virtual TQString valueToSQL(uint ftype, const TQVariant &v) const
Definition driver.cpp:250
TQString fileDBDriverMimeType() const
Definition driver.cpp:134
@ SingleTransactions
single trasactions are only supported
Definition driver.h:90
@ MultipleTransactions
multiple concurrent trasactions are supported (this implies !SingleTransactions)
Definition driver.h:93
static TQString defaultFileBasedDriverName()
Definition driver.cpp:140
TQValueList< TQCString > propertyNames() const
Definition driver.cpp:309
TQString propertyCaption(const TQCString &propName) const
Definition driver.cpp:304
int features() const
Definition driver.cpp:152
virtual TQString escapeString(const TQString &str) const =0
virtual bool isValid()
virtual DatabaseVersionInfo version() const =0
static TQString defaultFileBasedDriverMimeType()
Definition driver.cpp:137
AdminTools & adminTools() const
Definition driver.cpp:158
virtual TQString escapeBLOB(const TQByteArray &array) const =0
TQVariant propertyValue(const TQCString &propName) const
Definition driver.cpp:299
virtual bool drv_isSystemFieldName(const TQString &n) const =0
static TQString defaultSQLTypeName(int id_t)
Definition driver.cpp:206
const KService * service() const
Definition driver.cpp:146
bool isFileDriver() const
Definition driver.cpp:149
Connection * createConnection(ConnectionData &conn_data, int options=0)
Definition driver.cpp:178
bool isSystemFieldName(const TQString &n) const
Definition driver.cpp:243
virtual bool isSystemObjectName(const TQString &n) const
Definition driver.cpp:230
Connection * removeConnection(Connection *conn)
Definition driver.cpp:200
virtual TQString drv_escapeIdentifier(const TQString &str) const =0
void initSQLKeywords(int hashSize=17)
Definition driver.cpp:360
virtual TQString sqlTypeName(int id_t, int p=0) const
Definition driver.cpp:170
Driver(TQObject *parent, const char *name, const TQStringList &args=TQStringList())
virtual Connection * drv_createConnection(ConnectionData &conn_data)=0
@ ReadOnlyConnection
set to perform read only connection
Definition driver.h:116
static bool isKexiDBSystemObjectName(const TQString &n)
Definition driver.cpp:235
@ ShortInteger
Definition field.h:86
@ InvalidType
Definition field.h:84
virtual void clearError()
Definition object.cpp:131
virtual void setError(int code=ERR_OTHER, const TQString &msg=TQString())
Definition object.cpp:53
High-level database connectivity library with database backend drivers.
KEXI_DB_EXPORT DatabaseVersionInfo version()
Definition global.cpp:55