summaryrefslogtreecommitdiffstats
path: root/kexi/kexidb/drivers/sqlite
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/kexidb/drivers/sqlite
downloadkoffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz
koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kexi/kexidb/drivers/sqlite')
-rw-r--r--kexi/kexidb/drivers/sqlite/Makefile.am27
-rw-r--r--kexi/kexidb/drivers/sqlite/driver/sqlite.h687
-rw-r--r--kexi/kexidb/drivers/sqlite/kexidb_sqlite3driver.desktop56
-rw-r--r--kexi/kexidb/drivers/sqlite/sqlite.pro10
-rw-r--r--kexi/kexidb/drivers/sqlite/sqlite_common.pro16
-rw-r--r--kexi/kexidb/drivers/sqlite/sqliteadmin.cpp64
-rw-r--r--kexi/kexidb/drivers/sqlite/sqliteadmin.h36
-rw-r--r--kexi/kexidb/drivers/sqlite/sqlitealter.cpp114
-rw-r--r--kexi/kexidb/drivers/sqlite/sqliteconnection.cpp414
-rw-r--r--kexi/kexidb/drivers/sqlite/sqliteconnection.h125
-rw-r--r--kexi/kexidb/drivers/sqlite/sqliteconnection_p.h73
-rw-r--r--kexi/kexidb/drivers/sqlite/sqlitecursor.cpp567
-rw-r--r--kexi/kexidb/drivers/sqlite/sqlitecursor.h92
-rw-r--r--kexi/kexidb/drivers/sqlite/sqlitedriver.cpp159
-rw-r--r--kexi/kexidb/drivers/sqlite/sqlitedriver.h82
-rw-r--r--kexi/kexidb/drivers/sqlite/sqlitekeywords.cpp39
-rw-r--r--kexi/kexidb/drivers/sqlite/sqlitepreparedstatement.cpp242
-rw-r--r--kexi/kexidb/drivers/sqlite/sqlitepreparedstatement.h50
-rw-r--r--kexi/kexidb/drivers/sqlite/sqlitevacuum.cpp150
-rw-r--r--kexi/kexidb/drivers/sqlite/sqlitevacuum.h70
20 files changed, 3073 insertions, 0 deletions
diff --git a/kexi/kexidb/drivers/sqlite/Makefile.am b/kexi/kexidb/drivers/sqlite/Makefile.am
new file mode 100644
index 00000000..fc0ad677
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/Makefile.am
@@ -0,0 +1,27 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+kde_module_LTLIBRARIES = kexidb_sqlite3driver.la
+
+INCLUDES = -I$(top_srcdir)/kexi/3rdparty/kexisql3/src -I$(srcdir)/../.. \
+ -I$(top_srcdir)/kexi $(all_includes)
+
+kexidb_sqlite3driver_la_METASOURCES = AUTO
+
+kexidb_sqlite3driver_la_SOURCES = sqliteconnection.cpp sqlitedriver.cpp sqlitecursor.cpp \
+sqlitekeywords.cpp sqlitepreparedstatement.cpp sqlitevacuum.cpp sqliteadmin.cpp \
+sqlitealter.cpp
+
+kexidb_sqlite3driver_la_LIBADD = $(LIB_KPARTS) $(LIB_QT) \
+ $(top_builddir)/kexi/3rdparty/kexisql3/src/libkexisql3.la \
+ $(top_builddir)/kexi/kexidb/libkexidb.la \
+ $(top_builddir)/kexi/kexidb/parser/libkexidbparser.la
+
+kexidb_sqlite3driver_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(VER_INFO)
+
+
+kde_services_DATA = kexidb_sqlite3driver.desktop
+
+
+KDE_CXXFLAGS += -DKEXIDB_SQLITE_DRIVER_EXPORT= -D__KEXIDB__= \
+ -include $(top_srcdir)/kexi/kexidb/global.h
+
diff --git a/kexi/kexidb/drivers/sqlite/driver/sqlite.h b/kexi/kexidb/drivers/sqlite/driver/sqlite.h
new file mode 100644
index 00000000..680f81e2
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/driver/sqlite.h
@@ -0,0 +1,687 @@
+/*
+** 2001 September 15
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This header file defines the interface that the SQLite library
+** presents to client programs.
+**
+** @(#) $Id: sqlite.h 614463 2006-12-17 21:08:15Z staniek $
+*/
+#ifndef _SQLITE_H_
+#define _SQLITE_H_
+#include <stdarg.h> /* Needed for the definition of va_list */
+
+/*
+** Make sure we can call this stuff from C++.
+*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** The version of the SQLite library.
+*/
+#define SQLITE_VERSION "2.8.2"
+
+/*
+** The version string is also compiled into the library so that a program
+** can check to make sure that the lib*.a file and the *.h file are from
+** the same version.
+*/
+extern const char sqlite_version[];
+
+/*
+** The SQLITE_UTF8 macro is defined if the library expects to see
+** UTF-8 encoded data. The SQLITE_ISO8859 macro is defined if the
+** iso8859 encoded should be used.
+*/
+#define SQLITE_ISO8859 1
+
+/*
+** The following constant holds one of two strings, "UTF-8" or "iso8859",
+** depending on which character encoding the SQLite library expects to
+** see. The character encoding makes a difference for the LIKE and GLOB
+** operators and for the LENGTH() and SUBSTR() functions.
+*/
+extern const char sqlite_encoding[];
+
+/*
+** Each open sqlite database is represented by an instance of the
+** following opaque structure.
+*/
+typedef struct sqlite sqlite;
+
+/*
+** A function to open a new sqlite database.
+**
+** If the database does not exist and mode indicates write
+** permission, then a new database is created. If the database
+** does not exist and mode does not indicate write permission,
+** then the open fails, an error message generated (if errmsg!=0)
+** and the function returns 0.
+**
+** If mode does not indicates user write permission, then the
+** database is opened read-only.
+**
+** The Truth: As currently implemented, all databases are opened
+** for writing all the time. Maybe someday we will provide the
+** ability to open a database readonly. The mode parameters is
+** provided in anticipation of that enhancement.
+*/
+sqlite *sqlite_open(const char *filename, int mode, char **errmsg);
+
+/*
+** A function to close the database.
+**
+** Call this function with a pointer to a structure that was previously
+** returned from sqlite_open() and the corresponding database will by closed.
+*/
+void sqlite_close(sqlite *);
+
+/*
+** The type for a callback function.
+*/
+typedef int (*sqlite_callback)(void*,int,char**, char**);
+
+/*
+** A function to executes one or more statements of SQL.
+**
+** If one or more of the SQL statements are queries, then
+** the callback function specified by the 3rd parameter is
+** invoked once for each row of the query result. This callback
+** should normally return 0. If the callback returns a non-zero
+** value then the query is aborted, all subsequent SQL statements
+** are skipped and the sqlite_exec() function returns the SQLITE_ABORT.
+**
+** The 4th parameter is an arbitrary pointer that is passed
+** to the callback function as its first parameter.
+**
+** The 2nd parameter to the callback function is the number of
+** columns in the query result. The 3rd parameter to the callback
+** is an array of strings holding the values for each column.
+** The 4th parameter to the callback is an array of strings holding
+** the names of each column.
+**
+** The callback function may be NULL, even for queries. A NULL
+** callback is not an error. It just means that no callback
+** will be invoked.
+**
+** If an error occurs while parsing or evaluating the SQL (but
+** not while executing the callback) then an appropriate error
+** message is written into memory obtained from malloc() and
+** *errmsg is made to point to that message. The calling function
+** is responsible for freeing the memory that holds the error
+** message. Use sqlite_freemem() for this. If errmsg==NULL,
+** then no error message is ever written.
+**
+** The return value is is SQLITE_OK if there are no errors and
+** some other return code if there is an error. The particular
+** return value depends on the type of error.
+**
+** If the query could not be executed because a database file is
+** locked or busy, then this function returns SQLITE_BUSY. (This
+** behavior can be modified somewhat using the sqlite_busy_handler()
+** and sqlite_busy_timeout() functions below.)
+*/
+int sqlite_exec(
+ sqlite*, /* An open database */
+ const char *sql, /* SQL to be executed */
+ sqlite_callback, /* Callback function */
+ void *, /* 1st argument to callback function */
+ char **errmsg /* Error msg written here */
+);
+
+/*
+** Return values for sqlite_exec() and sqlite_step()
+*/
+#define SQLITE_OK 0 /* Successful result */
+#define SQLITE_ERROR 1 /* SQL error or missing database */
+#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */
+#define SQLITE_PERM 3 /* Access permission denied */
+#define SQLITE_ABORT 4 /* Callback routine requested an abort */
+#define SQLITE_BUSY 5 /* The database file is locked */
+#define SQLITE_LOCKED 6 /* A table in the database is locked */
+#define SQLITE_NOMEM 7 /* A malloc() failed */
+#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
+#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt() */
+#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
+#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
+#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */
+#define SQLITE_FULL 13 /* Insertion failed because database is full */
+#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
+#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
+#define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */
+#define SQLITE_SCHEMA 17 /* The database schema changed */
+#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */
+#define SQLITE_CONSTRAINT 19 /* Abort due to contraint violation */
+#define SQLITE_MISMATCH 20 /* Data type mismatch */
+#define SQLITE_MISUSE 21 /* Library used incorrectly */
+#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
+#define SQLITE_AUTH 23 /* Authorization denied */
+#define SQLITE_FORMAT 24 /* Auxiliary database format error */
+#define SQLITE_ROW 100 /* sqlite_step() has another row ready */
+#define SQLITE_DONE 101 /* sqlite_step() has finished executing */
+
+/*
+** Each entry in an SQLite table has a unique integer key. (The key is
+** the value of the INTEGER PRIMARY KEY column if there is such a column,
+** otherwise the key is generated at random. The unique key is always
+** available as the ROWID, OID, or _ROWID_ column.) The following routine
+** returns the integer key of the most recent insert in the database.
+**
+** This function is similar to the mysql_insert_id() function from MySQL.
+*/
+int sqlite_last_insert_rowid(sqlite*);
+
+/*
+** This function returns the number of database rows that were changed
+** (or inserted or deleted) by the most recent called sqlite_exec().
+**
+** All changes are counted, even if they were later undone by a
+** ROLLBACK or ABORT. Except, changes associated with creating and
+** dropping tables are not counted.
+**
+** If a callback invokes sqlite_exec() recursively, then the changes
+** in the inner, recursive call are counted together with the changes
+** in the outer call.
+**
+** SQLite implements the command "DELETE FROM table" without a WHERE clause
+** by dropping and recreating the table. (This is much faster than going
+** through and deleting individual elements form the table.) Because of
+** this optimization, the change count for "DELETE FROM table" will be
+** zero regardless of the number of elements that were originally in the
+** table. To get an accurate count of the number of rows deleted, use
+** "DELETE FROM table WHERE 1" instead.
+*/
+int sqlite_changes(sqlite*);
+
+/* If the parameter to this routine is one of the return value constants
+** defined above, then this routine returns a constant text string which
+** descripts (in English) the meaning of the return value.
+*/
+const char *sqlite_error_string(int);
+#define sqliteErrStr sqlite_error_string /* Legacy. Do not use in new code. */
+
+/* This function causes any pending database operation to abort and
+** return at its earliest opportunity. This routine is typically
+** called in response to a user action such as pressing "Cancel"
+** or Ctrl-C where the user wants a long query operation to halt
+** immediately.
+*/
+void sqlite_interrupt(sqlite*);
+
+
+/* This function returns true if the given input string comprises
+** one or more complete SQL statements.
+**
+** The algorithm is simple. If the last token other than spaces
+** and comments is a semicolon, then return true. otherwise return
+** false.
+*/
+int sqlite_complete(const char *sql);
+
+/*
+** This routine identifies a callback function that is invoked
+** whenever an attempt is made to open a database table that is
+** currently locked by another process or thread. If the busy callback
+** is NULL, then sqlite_exec() returns SQLITE_BUSY immediately if
+** it finds a locked table. If the busy callback is not NULL, then
+** sqlite_exec() invokes the callback with three arguments. The
+** second argument is the name of the locked table and the third
+** argument is the number of times the table has been busy. If the
+** busy callback returns 0, then sqlite_exec() immediately returns
+** SQLITE_BUSY. If the callback returns non-zero, then sqlite_exec()
+** tries to open the table again and the cycle repeats.
+**
+** The default busy callback is NULL.
+**
+** Sqlite is re-entrant, so the busy handler may start a new query.
+** (It is not clear why anyone would every want to do this, but it
+** is allowed, in theory.) But the busy handler may not close the
+** database. Closing the database from a busy handler will delete
+** data structures out from under the executing query and will
+** probably result in a coredump.
+*/
+void sqlite_busy_handler(sqlite*, int(*)(void*,const char*,int), void*);
+
+/*
+** This routine sets a busy handler that sleeps for a while when a
+** table is locked. The handler will sleep multiple times until
+** at least "ms" milleseconds of sleeping have been done. After
+** "ms" milleseconds of sleeping, the handler returns 0 which
+** causes sqlite_exec() to return SQLITE_BUSY.
+**
+** Calling this routine with an argument less than or equal to zero
+** turns off all busy handlers.
+*/
+void sqlite_busy_timeout(sqlite*, int ms);
+
+/*
+** This next routine is really just a wrapper around sqlite_exec().
+** Instead of invoking a user-supplied callback for each row of the
+** result, this routine remembers each row of the result in memory
+** obtained from malloc(), then returns all of the result after the
+** query has finished.
+**
+** As an example, suppose the query result where this table:
+**
+** Name | Age
+** -----------------------
+** Alice | 43
+** Bob | 28
+** Cindy | 21
+**
+** If the 3rd argument were &azResult then after the function returns
+** azResult will contain the following data:
+**
+** azResult[0] = "Name";
+** azResult[1] = "Age";
+** azResult[2] = "Alice";
+** azResult[3] = "43";
+** azResult[4] = "Bob";
+** azResult[5] = "28";
+** azResult[6] = "Cindy";
+** azResult[7] = "21";
+**
+** Notice that there is an extra row of data containing the column
+** headers. But the *nrow return value is still 3. *ncolumn is
+** set to 2. In general, the number of values inserted into azResult
+** will be ((*nrow) + 1)*(*ncolumn).
+**
+** After the calling function has finished using the result, it should
+** pass the result data pointer to sqlite_free_table() in order to
+** release the memory that was malloc-ed. Because of the way the
+** malloc() happens, the calling function must not try to call
+** malloc() directly. Only sqlite_free_table() is able to release
+** the memory properly and safely.
+**
+** The return value of this routine is the same as from sqlite_exec().
+*/
+int sqlite_get_table(
+ sqlite*, /* An open database */
+ const char *sql, /* SQL to be executed */
+ char ***resultp, /* Result written to a char *[] that this points to */
+ int *nrow, /* Number of result rows written here */
+ int *ncolumn, /* Number of result columns written here */
+ char **errmsg /* Error msg written here */
+);
+
+/*
+** Call this routine to free the memory that sqlite_get_table() allocated.
+*/
+void sqlite_free_table(char **result);
+
+/*
+** The following routines are wrappers around sqlite_exec() and
+** sqlite_get_table(). The only difference between the routines that
+** follow and the originals is that the second argument to the
+** routines that follow is really a printf()-style format
+** string describing the SQL to be executed. Arguments to the format
+** string appear at the end of the argument list.
+**
+** All of the usual printf formatting options apply. In addition, there
+** is a "%q" option. %q works like %s in that it substitutes a null-terminated
+** string from the argument list. But %q also doubles every '\'' character.
+** %q is designed for use inside a string literal. By doubling each '\''
+** character it escapes that character and allows it to be inserted into
+** the string.
+**
+** For example, so some string variable contains text as follows:
+**
+** char *zText = "It's a happy day!";
+**
+** We can use this text in an SQL statement as follows:
+**
+** sqlite_exec_printf(db, "INSERT INTO table VALUES('%q')",
+** callback1, 0, 0, zText);
+**
+** Because the %q format string is used, the '\'' character in zText
+** is escaped and the SQL generated is as follows:
+**
+** INSERT INTO table1 VALUES('It''s a happy day!')
+**
+** This is correct. Had we used %s instead of %q, the generated SQL
+** would have looked like this:
+**
+** INSERT INTO table1 VALUES('It's a happy day!');
+**
+** This second example is an SQL syntax error. As a general rule you
+** should always use %q instead of %s when inserting text into a string
+** literal.
+*/
+int sqlite_exec_printf(
+ sqlite*, /* An open database */
+ const char *sqlFormat, /* printf-style format string for the SQL */
+ sqlite_callback, /* Callback function */
+ void *, /* 1st argument to callback function */
+ char **errmsg, /* Error msg written here */
+ ... /* Arguments to the format string. */
+);
+int sqlite_exec_vprintf(
+ sqlite*, /* An open database */
+ const char *sqlFormat, /* printf-style format string for the SQL */
+ sqlite_callback, /* Callback function */
+ void *, /* 1st argument to callback function */
+ char **errmsg, /* Error msg written here */
+ va_list ap /* Arguments to the format string. */
+);
+int sqlite_get_table_printf(
+ sqlite*, /* An open database */
+ const char *sqlFormat, /* printf-style format string for the SQL */
+ char ***resultp, /* Result written to a char *[] that this points to */
+ int *nrow, /* Number of result rows written here */
+ int *ncolumn, /* Number of result columns written here */
+ char **errmsg, /* Error msg written here */
+ ... /* Arguments to the format string */
+);
+int sqlite_get_table_vprintf(
+ sqlite*, /* An open database */
+ const char *sqlFormat, /* printf-style format string for the SQL */
+ char ***resultp, /* Result written to a char *[] that this points to */
+ int *nrow, /* Number of result rows written here */
+ int *ncolumn, /* Number of result columns written here */
+ char **errmsg, /* Error msg written here */
+ va_list ap /* Arguments to the format string */
+);
+char *sqlite_mprintf(const char*,...);
+
+/*
+** Windows systems should call this routine to free memory that
+** is returned in the in the errmsg parameter of sqlite_open() when
+** SQLite is a DLL. For some reason, it does not work to call free()
+** directly.
+*/
+void sqlite_freemem(void *p);
+
+/*
+** Windows systems need functions to call to return the sqlite_version
+** and sqlite_encoding strings.
+*/
+const char *sqlite_libversion(void);
+const char *sqlite_libencoding(void);
+
+/*
+** A pointer to the following structure is used to communicate with
+** the implementations of user-defined functions.
+*/
+typedef struct sqlite_func sqlite_func;
+
+/*
+** Use the following routines to create new user-defined functions. See
+** the documentation for details.
+*/
+int sqlite_create_function(
+ sqlite*, /* Database where the new function is registered */
+ const char *zName, /* Name of the new function */
+ int nArg, /* Number of arguments. -1 means any number */
+ void (*xFunc)(sqlite_func*,int,const char**), /* C code to implement */
+ void *pUserData /* Available via the sqlite_user_data() call */
+);
+int sqlite_create_aggregate(
+ sqlite*, /* Database where the new function is registered */
+ const char *zName, /* Name of the function */
+ int nArg, /* Number of arguments */
+ void (*xStep)(sqlite_func*,int,const char**), /* Called for each row */
+ void (*xFinalize)(sqlite_func*), /* Called once to get final result */
+ void *pUserData /* Available via the sqlite_user_data() call */
+);
+
+/*
+** Use the following routine to define the datatype returned by a
+** user-defined function. The second argument can be one of the
+** constants SQLITE_NUMERIC, SQLITE_TEXT, or SQLITE_ARGS or it
+** can be an integer greater than or equal to zero. The datatype
+** will be numeric or text (the only two types supported) if the
+** argument is SQLITE_NUMERIC or SQLITE_TEXT. If the argument is
+** SQLITE_ARGS, then the datatype is numeric if any argument to the
+** function is numeric and is text otherwise. If the second argument
+** is an integer, then the datatype of the result is the same as the
+** parameter to the function that corresponds to that integer.
+*/
+int sqlite_function_type(
+ sqlite *db, /* The database there the function is registered */
+ const char *zName, /* Name of the function */
+ int datatype /* The datatype for this function */
+);
+#define SQLITE_NUMERIC (-1)
+#define SQLITE_TEXT (-2)
+#define SQLITE_ARGS (-3)
+
+/*
+** The user function implementations call one of the following four routines
+** in order to return their results. The first parameter to each of these
+** routines is a copy of the first argument to xFunc() or xFinialize().
+** The second parameter to these routines is the result to be returned.
+** A NULL can be passed as the second parameter to sqlite_set_result_string()
+** in order to return a NULL result.
+**
+** The 3rd argument to _string and _error is the number of characters to
+** take from the string. If this argument is negative, then all characters
+** up to and including the first '\000' are used.
+**
+** The sqlite_set_result_string() function allocates a buffer to hold the
+** result and returns a pointer to this buffer. The calling routine
+** (that is, the implementation of a user function) can alter the content
+** of this buffer if desired.
+*/
+char *sqlite_set_result_string(sqlite_func*,const char*,int);
+void sqlite_set_result_int(sqlite_func*,int);
+void sqlite_set_result_double(sqlite_func*,double);
+void sqlite_set_result_error(sqlite_func*,const char*,int);
+
+/*
+** The pUserData parameter to the sqlite_create_function() and
+** sqlite_create_aggregate() routines used to register user functions
+** is available to the implementation of the function using this
+** call.
+*/
+void *sqlite_user_data(sqlite_func*);
+
+/*
+** Aggregate functions use the following routine to allocate
+** a structure for storing their state. The first time this routine
+** is called for a particular aggregate, a new structure of size nBytes
+** is allocated, zeroed, and returned. On subsequent calls (for the
+** same aggregate instance) the same buffer is returned. The implementation
+** of the aggregate can use the returned buffer to accumulate data.
+**
+** The buffer allocated is freed automatically be SQLite.
+*/
+void *sqlite_aggregate_context(sqlite_func*, int nBytes);
+
+/*
+** The next routine returns the number of calls to xStep for a particular
+** aggregate function instance. The current call to xStep counts so this
+** routine always returns at least 1.
+*/
+int sqlite_aggregate_count(sqlite_func*);
+
+/*
+** This routine registers a callback with the SQLite library. The
+** callback is invoked (at compile-time, not at run-time) for each
+** attempt to access a column of a table in the database. The callback
+** returns SQLITE_OK if access is allowed, SQLITE_DENY if the entire
+** SQL statement should be aborted with an error and SQLITE_IGNORE
+** if the column should be treated as a NULL value.
+*/
+int sqlite_set_authorizer(
+ sqlite*,
+ int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
+ void *pUserData
+);
+
+/*
+** The second parameter to the access authorization function above will
+** be one of the values below. These values signify what kind of operation
+** is to be authorized. The 3rd and 4th parameters to the authorization
+** function will be parameters or NULL depending on which of the following
+** codes is used as the second parameter. The 5th parameter is the name
+** of the database ("main", "temp", etc.) if applicable. The 6th parameter
+** is the name of the inner-most trigger or view that is responsible for
+** the access attempt or NULL if this access attempt is directly from
+** input SQL code.
+**
+** Arg-3 Arg-4
+*/
+#define SQLITE_COPY 0 /* Table Name File Name */
+#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */
+#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */
+#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */
+#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */
+#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */
+#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */
+#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */
+#define SQLITE_CREATE_VIEW 8 /* View Name NULL */
+#define SQLITE_DELETE 9 /* Table Name NULL */
+#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */
+#define SQLITE_DROP_TABLE 11 /* Table Name NULL */
+#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */
+#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */
+#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */
+#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */
+#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */
+#define SQLITE_DROP_VIEW 17 /* View Name NULL */
+#define SQLITE_INSERT 18 /* Table Name NULL */
+#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */
+#define SQLITE_READ 20 /* Table Name Column Name */
+#define SQLITE_SELECT 21 /* NULL NULL */
+#define SQLITE_TRANSACTION 22 /* NULL NULL */
+#define SQLITE_UPDATE 23 /* Table Name Column Name */
+
+/*
+** The return value of the authorization function should be one of the
+** following constants:
+*/
+/* #define SQLITE_OK 0 // Allow access (This is actually defined above) */
+#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
+#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
+
+/*
+** Register a function that is called at every invocation of sqlite_exec()
+** or sqlite_compile(). This function can be used (for example) to generate
+** a log file of all SQL executed against a database.
+*/
+void *sqlite_trace(sqlite*, void(*xTrace)(void*,const char*), void*);
+
+/*** The Callback-Free API
+**
+** The following routines implement a new way to access SQLite that does not
+** involve the use of callbacks.
+**
+** An sqlite_vm is an opaque object that represents a single SQL statement
+** that is ready to be executed.
+*/
+typedef struct sqlite_vm sqlite_vm;
+
+/*
+** To execute an SQLite query without the use of callbacks, you first have
+** to compile the SQL using this routine. The 1st parameter "db" is a pointer
+** to an sqlite object obtained from sqlite_open(). The 2nd parameter
+** "zSql" is the text of the SQL to be compiled. The remaining parameters
+** are all outputs.
+**
+** *pzTail is made to point to the first character past the end of the first
+** SQL statement in zSql. This routine only compiles the first statement
+** in zSql, so *pzTail is left pointing to what remains uncompiled.
+**
+** *ppVm is left pointing to a "virtual machine" that can be used to execute
+** the compiled statement. Or if there is an error, *ppVm may be set to NULL.
+** If the input text contained no SQL (if the input is and empty string or
+** a comment) then *ppVm is set to NULL.
+**
+** If any errors are detected during compilation, an error message is written
+** into space obtained from malloc() and *pzErrMsg is made to point to that
+** error message. The calling routine is responsible for freeing the text
+** of this message when it has finished with it. Use sqlite_freemem() to
+** free the message. pzErrMsg may be NULL in which case no error message
+** will be generated.
+**
+** On success, SQLITE_OK is returned. Otherwise and error code is returned.
+*/
+int sqlite_compile(
+ sqlite *db, /* The open database */
+ const char *zSql, /* SQL statement to be compiled */
+ const char **pzTail, /* OUT: uncompiled tail of zSql */
+ sqlite_vm **ppVm, /* OUT: the virtual machine to execute zSql */
+ char **pzErrmsg /* OUT: Error message. */
+);
+
+/*
+** After an SQL statement has been compiled, it is handed to this routine
+** to be executed. This routine executes the statement as far as it can
+** go then returns. The return value will be one of SQLITE_DONE,
+** SQLITE_ERROR, SQLITE_BUSY, SQLITE_ROW, or SQLITE_MISUSE.
+**
+** SQLITE_DONE means that the execute of the SQL statement is complete
+** an no errors have occurred. sqlite_step() should not be called again
+** for the same virtual machine. *pN is set to the number of columns in
+** the result set and *pazColName is set to an array of strings that
+** describe the column names and datatypes. The name of the i-th column
+** is (*pazColName)[i] and the datatype of the i-th column is
+** (*pazColName)[i+*pN]. *pazValue is set to NULL.
+**
+** SQLITE_ERROR means that the virtual machine encountered a run-time
+** error. sqlite_step() should not be called again for the same
+** virtual machine. *pN is set to 0 and *pazColName and *pazValue are set
+** to NULL. Use sqlite_finalize() to obtain the specific error code
+** and the error message text for the error.
+**
+** SQLITE_BUSY means that an attempt to open the database failed because
+** another thread or process is holding a lock. The calling routine
+** can try again to open the database by calling sqlite_step() again.
+** The return code will only be SQLITE_BUSY if no busy handler is registered
+** using the sqlite_busy_handler() or sqlite_busy_timeout() routines. If
+** a busy handler callback has been registered but returns 0, then this
+** routine will return SQLITE_ERROR and sqltie_finalize() will return
+** SQLITE_BUSY when it is called.
+**
+** SQLITE_ROW means that a single row of the result is now available.
+** The data is contained in *pazValue. The value of the i-th column is
+** (*azValue)[i]. *pN and *pazColName are set as described in SQLITE_DONE.
+** Invoke sqlite_step() again to advance to the next row.
+**
+** SQLITE_MISUSE is returned if sqlite_step() is called incorrectly.
+** For example, if you call sqlite_step() after the virtual machine
+** has halted (after a prior call to sqlite_step() has returned SQLITE_DONE)
+** or if you call sqlite_step() with an incorrectly initialized virtual
+** machine or a virtual machine that has been deleted or that is associated
+** with an sqlite structure that has been closed.
+*/
+int sqlite_step(
+ sqlite_vm *pVm, /* The virtual machine to execute */
+ int *pN, /* OUT: Number of columns in result */
+ const char ***pazValue, /* OUT: Column data */
+ const char ***pazColName /* OUT: Column names and datatypes */
+);
+
+/*
+** This routine is called to delete a virtual machine after it has finished
+** executing. The return value is the result code. SQLITE_OK is returned
+** if the statement executed successfully and some other value is returned if
+** there was any kind of error. If an error occurred and pzErrMsg is not
+** NULL, then an error message is written into memory obtained from malloc()
+** and *pzErrMsg is made to point to that error message. The calling routine
+** should use sqlite_freemem() to delete this message when it has finished
+** with it.
+**
+** This routine can be called at any point during the execution of the
+** virtual machine. If the virtual machine has not completed execution
+** when this routine is called, that is like encountering an error or
+** an interrupt. (See sqlite_interrupt().) Incomplete updates may be
+** rolled back and transactions cancelled, depending on the circumstances,
+** and the result code returned will be SQLITE_ABORT.
+*/
+int sqlite_finalize(sqlite_vm*, char **pzErrMsg);
+
+#ifdef __cplusplus
+} /* End of the 'extern "C"' block */
+#endif
+
+#endif /* _SQLITE_H_ */
diff --git a/kexi/kexidb/drivers/sqlite/kexidb_sqlite3driver.desktop b/kexi/kexidb/drivers/sqlite/kexidb_sqlite3driver.desktop
new file mode 100644
index 00000000..92e59931
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/kexidb_sqlite3driver.desktop
@@ -0,0 +1,56 @@
+[Desktop Entry]
+Name=SQLite3
+Name[sv]=Sqlite 3
+Comment=SQLite is default Kexi embedded SQL engine
+Comment[bg]=SQLite е СУБД по подразбиране в Kexi , с вградено SQL ядро
+Comment[ca]=SQLite és el motor SQL encastat i per defecte de Kexi
+Comment[cy]=Y peiriant SQL mewnadeiledig rhagosod Kexi yw SQLite
+Comment[da]=SQLite er en standard Kexi-indlejret SQL-motor
+Comment[de]=SQLite ist der standardmäßig in Kexi eingebettete SQL-Treiber
+Comment[el]=Η SQLite είναι η προκαθορισμένη ενσωματωμένη μηχανή SQL του Kexi
+Comment[es]=SQLite es el motor SQL incrustado en Kexi de forma predefinida
+Comment[et]=SQLite on Kexi vaikimisi kasutatav SQL mootor
+Comment[eu]=SQLite Kexi-ren kapsultatutako SQL motore lehenetsia da
+Comment[fa]=SQLite، پیش‌فرض موتور SQL نهفتۀ Kexi است
+Comment[fi]=SQLite on Kexin käyttämä sisäänrakennetti SQL-moottori.
+Comment[fr]=SQLite est le moteur SQL par défaut intégré à Kexi
+Comment[fy]=SQLite is de standert SQL-databank foar Kexi
+Comment[gl]=SQLite é o motor embebido de SQL de Kexi
+Comment[he]=SQLite הוא מנוע ה־SQL המוטבע של Kexi המשמש כברירת מחדל
+Comment[hi]=केएक्साई एम्बेडेड एसक्यूएल इंजिन के लिए एसक्यूएललाइट डिफ़ॉल्ट है
+Comment[hr]=SQLite je zadani Kexi ugrađeni pogon SQL pogona
+Comment[hu]=Az SQLite a Kexi alapértelmezett, beépített SQL-motorja
+Comment[is]=SQLite er sjálfgefna Kexi SQL vélin
+Comment[it]=SQLite è il motore predefinito integrato in Kexi
+Comment[ja]=SQLite は Kexi の標準埋め込み SQL エンジンです。
+Comment[km]=SQLite គឺ​ជា​ម៉ាស៊ីន SQL ដែល​បាន​បង្កប់​ក្នុង Kexi តាម​លំនាំដើម
+Comment[lv]=SQLite ir Kexi noklusējuma SQL dzinējs
+Comment[ms]=SQLite adalah KeXi piawai yang dipasang dalam enjin SQL
+Comment[nb]=SQLite er den innebygde SQL-motoren i Kexi
+Comment[nds]=SQLite is de standardinbett SQL-Driever för Kexi
+Comment[ne]=SQLite पूर्वनिर्धारित केक्सी सम्मिलित SQL इन्जिन हो
+Comment[nl]=SQLite is de standaard SQL-database voor Kexi
+Comment[nn]=SQLite er den innebygde SQL-motoren i Kexi
+Comment[pl]=SQLite jest domyślnym wbudowanym silnikiem SQL dla Kexi
+Comment[pt]=SQLite é o motor embebido de SQL do Kexi
+Comment[pt_BR]=SQLite é o mecanismo SQL embutido padrão do Kexi
+Comment[ru]=SQLite -- движок встроенного SQL по умолчанию в Kexi
+Comment[se]=SQLite lea Kexi:a sisahuksejuvvon SQL-mohtor
+Comment[sk]=SQLite je štandardný Kexi embedded SQL systém
+Comment[sl]=SQLite je privzet vključen pogon SQL za Kexi
+Comment[sr]=SQLite је подразумевани Kexi-јев уграђен SQL мотор
+Comment[sr@Latn]=SQLite je podrazumevani Kexi-jev ugrađen SQL motor
+Comment[sv]=Sqlite är inbyggd SQL-standarddatabas i Kexi
+Comment[tg]=SQLite -- движоки SQL, ки дар дар дохили Kexi бо пешфарз сохта шудааст
+Comment[tr]=SQlite Kexi'ye gömülü varsayılan SQL motorudur
+Comment[uk]=SQLite - це типовий рушій SQL вбудований в Kexi
+Comment[zh_CN]=SQLite 是嵌入 Kexi 的默认 SQL 引擎
+Comment[zh_TW]=SQLite 是 Kexi 預設內建的 SQL 引擎
+X-KDE-Library=kexidb_sqlite3driver
+ServiceTypes=Kexi/DBDriver
+Type=Service
+InitialPreference=8
+X-Kexi-DriverName=SQLite3
+X-Kexi-DriverType=File
+X-Kexi-FileDBDriverMimeList=application/x-sqlite3,application/x-kexiproject-sqlite3,application/x-hk_classes-sqlite3
+X-Kexi-KexiDBVersion=1.8
diff --git a/kexi/kexidb/drivers/sqlite/sqlite.pro b/kexi/kexidb/drivers/sqlite/sqlite.pro
new file mode 100644
index 00000000..7fde2926
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqlite.pro
@@ -0,0 +1,10 @@
+include( sqlite_common.pro )
+
+win32:LIBS += $$KDELIBDESTDIR/kexisql3$$KDELIBDEBUGLIB
+
+INCLUDEPATH += $(KEXI)/3rdparty/kexisql3/src
+
+TARGET = kexidb_sqlite3driver$$KDELIBDEBUG
+
+SOURCES += sqlitekeywords.cpp \
+sqlitevacuum.cpp
diff --git a/kexi/kexidb/drivers/sqlite/sqlite_common.pro b/kexi/kexidb/drivers/sqlite/sqlite_common.pro
new file mode 100644
index 00000000..81fb85b3
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqlite_common.pro
@@ -0,0 +1,16 @@
+include( ../common.pro )
+
+DEFINES += MAKE_KEXIDB_SQLITE_DRIVER_LIB
+
+system( bash kmoc )
+
+SOURCES = \
+sqliteconnection.cpp \
+sqlitedriver.cpp \
+sqliteadmin.cpp \
+sqlitecursor.cpp \
+sqlitepreparedstatement.cpp \
+sqlitealter.cpp
+
+HEADERS =
+
diff --git a/kexi/kexidb/drivers/sqlite/sqliteadmin.cpp b/kexi/kexidb/drivers/sqlite/sqliteadmin.cpp
new file mode 100644
index 00000000..8bd8085a
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqliteadmin.cpp
@@ -0,0 +1,64 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qdir.h>
+
+#include "sqliteadmin.h"
+#include <kexidb/drivermanager.h>
+#include <kexidb/driver_p.h>
+
+#ifndef SQLITE2
+# include "sqlitevacuum.h"
+#endif
+
+SQLiteAdminTools::SQLiteAdminTools()
+ : KexiDB::AdminTools()
+{
+}
+
+SQLiteAdminTools::~SQLiteAdminTools()
+{
+}
+
+bool SQLiteAdminTools::vacuum(const KexiDB::ConnectionData& data, const QString& databaseName)
+{
+ clearError();
+#ifdef SQLITE2
+ Q_UNUSED(data);
+ Q_UNUSED(databaseName);
+ return false;
+#else
+ KexiDB::DriverManager manager;
+ KexiDB::Driver *drv = manager.driver(data.driverName);
+ QString title( i18n("Could not compact database \"%1\".").arg(QDir::convertSeparators(databaseName)) );
+ if (!drv) {
+ setError(&manager, title);
+ return false;
+ }
+ SQLiteVacuum vacuum(data.dbPath()+QDir::separator()+databaseName);
+ tristate result = vacuum.run();
+ if (!result) {
+ setError(title);
+ return false;
+ }
+ else //success or cancelled
+ return true;
+#endif
+}
+
diff --git a/kexi/kexidb/drivers/sqlite/sqliteadmin.h b/kexi/kexidb/drivers/sqlite/sqliteadmin.h
new file mode 100644
index 00000000..d9f8a6b6
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqliteadmin.h
@@ -0,0 +1,36 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXIDB_SQLITEADMIN_H
+#define KEXIDB_SQLITEADMIN_H
+
+#include <kexidb/admin.h>
+
+//! @short An interface containing a set of tools for SQLite database administration.
+class SQLiteAdminTools : public KexiDB::AdminTools
+{
+ public:
+ SQLiteAdminTools();
+ virtual ~SQLiteAdminTools();
+
+ /*! Performs vacuum (compacting) for connection \a conn. */
+ virtual bool vacuum(const KexiDB::ConnectionData& data, const QString& databaseName);
+};
+
+#endif
diff --git a/kexi/kexidb/drivers/sqlite/sqlitealter.cpp b/kexi/kexidb/drivers/sqlite/sqlitealter.cpp
new file mode 100644
index 00000000..cc72e48a
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqlitealter.cpp
@@ -0,0 +1,114 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+// ** bits of SQLiteConnection related to table altering **
+
+#include "sqliteconnection.h"
+#include <kexidb/utils.h>
+
+#include <kstaticdeleter.h>
+
+#include <qmap.h>
+
+using namespace KexiDB;
+
+enum SQLiteTypeAffinity { //as defined here: 2.1 Determination Of Column Affinity (http://sqlite.org/datatype3.html)
+ NoAffinity = 0, IntAffinity = 1, TextAffinity = 2, BLOBAffinity = 3
+};
+
+//! helper for affinityForType()
+static KStaticDeleter< QMap<int,int> > KexiDB_SQLite_affinityForType_deleter;
+QMap<int,int> *KexiDB_SQLite_affinityForType = 0;
+
+//! \return SQLite type affinity for \a type
+//! See doc/dev/alter_table_type_conversions.ods, page 2 for more info
+static SQLiteTypeAffinity affinityForType(Field::Type type)
+{
+ if (!KexiDB_SQLite_affinityForType) {
+ KexiDB_SQLite_affinityForType_deleter.setObject( KexiDB_SQLite_affinityForType, new QMap<int,int>() );
+ KexiDB_SQLite_affinityForType->insert(Field::Byte, IntAffinity);
+ KexiDB_SQLite_affinityForType->insert(Field::ShortInteger, IntAffinity);
+ KexiDB_SQLite_affinityForType->insert(Field::Integer, IntAffinity);
+ KexiDB_SQLite_affinityForType->insert(Field::BigInteger, IntAffinity);
+ KexiDB_SQLite_affinityForType->insert(Field::Boolean, IntAffinity);
+ KexiDB_SQLite_affinityForType->insert(Field::Date, TextAffinity);
+ KexiDB_SQLite_affinityForType->insert(Field::DateTime, TextAffinity);
+ KexiDB_SQLite_affinityForType->insert(Field::Time, TextAffinity);
+ KexiDB_SQLite_affinityForType->insert(Field::Float, IntAffinity);
+ KexiDB_SQLite_affinityForType->insert(Field::Double, IntAffinity);
+ KexiDB_SQLite_affinityForType->insert(Field::Text, TextAffinity);
+ KexiDB_SQLite_affinityForType->insert(Field::LongText, TextAffinity);
+ KexiDB_SQLite_affinityForType->insert(Field::BLOB, BLOBAffinity);
+ }
+ return static_cast<SQLiteTypeAffinity>((*KexiDB_SQLite_affinityForType)[(int)type]);
+}
+
+tristate SQLiteConnection::drv_changeFieldProperty(TableSchema &table, Field& field,
+ const QString& propertyName, const QVariant& value)
+{
+/* if (propertyName=="name") {
+
+ }*/
+ if (propertyName=="type") {
+ bool ok;
+ Field::Type type = KexiDB::intToFieldType( value.toUInt(&ok) );
+ if (!ok || Field::InvalidType == type) {
+ //! @todo msg
+ return false;
+ }
+ return changeFieldType(table, field, type);
+ }
+ // not found
+ return cancelled;
+}
+
+/*!
+ From http://sqlite.org/datatype3.html :
+ Version 3 enhances provides the ability to store integer and real numbers in a more compact
+ format and the capability to store BLOB data.
+
+ Each value stored in an SQLite database (or manipulated by the database engine) has one
+ of the following storage classes:
+ * NULL. The value is a NULL value.
+ * INTEGER. The value is a signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes depending
+ on the magnitude of the value.
+ * REAL. The value is a floating point value, stored as an 8-byte IEEE floating point number.
+ * TEXT. The value is a text string, stored using the database encoding (UTF-8, UTF-16BE or UTF-16-LE).
+ * BLOB. The value is a blob of data, stored exactly as it was input.
+
+ Column Affinity
+ In SQLite version 3, the type of a value is associated with the value itself,
+ not with the column or variable in which the value is stored.
+.The type affinity of a column is the recommended type for data stored in that column.
+
+ See alter_table_type_conversions.ods for details.
+*/
+tristate SQLiteConnection::changeFieldType(TableSchema &table, Field& field,
+ Field::Type type)
+{
+ Q_UNUSED(table);
+ const Field::Type oldType = field.type();
+ const SQLiteTypeAffinity oldAffinity = affinityForType(oldType);
+ const SQLiteTypeAffinity newAffinity = affinityForType(type);
+ if (oldAffinity!=newAffinity) {
+ //type affinity will be changed
+ }
+
+ return cancelled;
+}
diff --git a/kexi/kexidb/drivers/sqlite/sqliteconnection.cpp b/kexi/kexidb/drivers/sqlite/sqliteconnection.cpp
new file mode 100644
index 00000000..6de41c59
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqliteconnection.cpp
@@ -0,0 +1,414 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "sqliteconnection.h"
+#include "sqliteconnection_p.h"
+#include "sqlitecursor.h"
+#include "sqlitepreparedstatement.h"
+
+#include "sqlite.h"
+
+#ifndef SQLITE2
+# include "kexisql.h" //for isReadOnly()
+#endif
+
+#include <kexidb/driver.h>
+#include <kexidb/cursor.h>
+#include <kexidb/error.h>
+#include <kexiutils/utils.h>
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qregexp.h>
+
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+//remove debug
+#undef KexiDBDrvDbg
+#define KexiDBDrvDbg if (0) kdDebug()
+
+using namespace KexiDB;
+
+SQLiteConnectionInternal::SQLiteConnectionInternal(Connection *connection)
+ : ConnectionInternal(connection)
+ , data(0)
+ , data_owned(true)
+ , errmsg_p(0)
+ , res(SQLITE_OK)
+ , temp_st(0x10000)
+#ifdef SQLITE3
+ , result_name(0)
+#endif
+{
+}
+
+SQLiteConnectionInternal::~SQLiteConnectionInternal()
+{
+ if (data_owned && data) {
+ free( data );
+ data = 0;
+ }
+//sqlite_freemem does this if (errmsg) {
+// free( errmsg );
+// errmsg = 0;
+// }
+}
+
+void SQLiteConnectionInternal::storeResult()
+{
+ if (errmsg_p) {
+ errmsg = errmsg_p;
+ sqlite_free(errmsg_p);
+ errmsg_p = 0;
+ }
+#ifdef SQLITE3
+ errmsg = (data && res!=SQLITE_OK) ? sqlite3_errmsg(data) : 0;
+#endif
+}
+
+/*! Used by driver */
+SQLiteConnection::SQLiteConnection( Driver *driver, ConnectionData &conn_data )
+ : Connection( driver, conn_data )
+ ,d(new SQLiteConnectionInternal(this))
+{
+}
+
+SQLiteConnection::~SQLiteConnection()
+{
+ KexiDBDrvDbg << "SQLiteConnection::~SQLiteConnection()" << endl;
+ //disconnect if was connected
+// disconnect();
+ destroy();
+ delete d;
+ KexiDBDrvDbg << "SQLiteConnection::~SQLiteConnection() ok" << endl;
+}
+
+bool SQLiteConnection::drv_connect(KexiDB::ServerVersionInfo& version)
+{
+ KexiDBDrvDbg << "SQLiteConnection::connect()" << endl;
+ version.string = QString(SQLITE_VERSION); //defined in sqlite3.h
+ QRegExp re("(\\d+)\\.(\\d+)\\.(\\d+)");
+ if (re.exactMatch(version.string)) {
+ version.major = re.cap(1).toUInt();
+ version.minor = re.cap(2).toUInt();
+ version.release = re.cap(3).toUInt();
+ }
+ return true;
+}
+
+bool SQLiteConnection::drv_disconnect()
+{
+ KexiDBDrvDbg << "SQLiteConnection::disconnect()" << endl;
+ return true;
+}
+
+bool SQLiteConnection::drv_getDatabasesList( QStringList &list )
+{
+ //this is one-db-per-file database
+ list.append( data()->fileName() ); //more consistent than dbFileName() ?
+ return true;
+}
+
+bool SQLiteConnection::drv_containsTable( const QString &tableName )
+{
+ bool success;
+ return resultExists(QString("select name from sqlite_master where type='table' and name LIKE %1")
+ .arg(driver()->escapeString(tableName)), success) && success;
+}
+
+bool SQLiteConnection::drv_getTablesList( QStringList &list )
+{
+ KexiDB::Cursor *cursor;
+ m_sql = "select lower(name) from sqlite_master where type='table'";
+ if (!(cursor = executeQuery( m_sql ))) {
+ KexiDBWarn << "Connection::drv_getTablesList(): !executeQuery()" << endl;
+ return false;
+ }
+ list.clear();
+ cursor->moveFirst();
+ while (!cursor->eof() && !cursor->error()) {
+ list += cursor->value(0).toString();
+ cursor->moveNext();
+ }
+ if (cursor->error()) {
+ deleteCursor(cursor);
+ return false;
+ }
+ return deleteCursor(cursor);
+}
+
+bool SQLiteConnection::drv_createDatabase( const QString &dbName )
+{
+ // SQLite creates a new db is it does not exist
+ return drv_useDatabase(dbName);
+#if 0
+ d->data = sqlite_open( QFile::encodeName( data()->fileName() ), 0/*mode: unused*/,
+ &d->errmsg_p );
+ d->storeResult();
+ return d->data != 0;
+#endif
+}
+
+bool SQLiteConnection::drv_useDatabase( const QString &dbName, bool *cancelled,
+ MessageHandler* msgHandler )
+{
+ Q_UNUSED(dbName);
+// KexiDBDrvDbg << "drv_useDatabase(): " << data()->fileName() << endl;
+#ifdef SQLITE2
+ Q_UNUSED(cancelled);
+ Q_UNUSED(msgHandler);
+ d->data = sqlite_open( QFile::encodeName( data()->fileName() ), 0/*mode: unused*/,
+ &d->errmsg_p );
+ d->storeResult();
+ return d->data != 0;
+#else //SQLITE3
+ //TODO: perhaps allow to use sqlite3_open16() as well for SQLite ~ 3.3 ?
+//! @todo add option (command line or in kexirc?)
+ int exclusiveFlag = Connection::isReadOnly() ? SQLITE_OPEN_READONLY : SQLITE_OPEN_WRITE_LOCKED; // <-- shared read + (if !r/o): exclusive write
+//! @todo add option
+ int allowReadonly = 1;
+ const bool wasReadOnly = Connection::isReadOnly();
+
+ d->res = sqlite3_open(
+ //QFile::encodeName( data()->fileName() ),
+ data()->fileName().utf8(), /* unicode expected since SQLite 3.1 */
+ &d->data,
+ exclusiveFlag,
+ allowReadonly /* If 1 and locking fails, try opening in read-only mode */
+ );
+ d->storeResult();
+
+ if (d->res == SQLITE_OK && cancelled && !wasReadOnly && allowReadonly && isReadOnly()) {
+ //opened as read only, ask
+ if (KMessageBox::Continue !=
+ askQuestion(
+ i18n("Do you want to open file \"%1\" as read-only?")
+ .arg(QDir::convertSeparators(data()->fileName()))
+ + "\n\n"
+ + i18n("The file is probably already open on this or another computer.") + " "
+ + i18n("Could not gain exclusive access for writing the file."),
+ KMessageBox::WarningContinueCancel, KMessageBox::Continue,
+ KGuiItem(i18n("Open As Read-Only"), "fileopen"), KStdGuiItem::cancel(),
+ "askBeforeOpeningFileReadOnly", KMessageBox::Notify, msgHandler ))
+ {
+ clearError();
+ if (!drv_closeDatabase())
+ return false;
+ *cancelled = true;
+ return false;
+ }
+ }
+
+ if (d->res == SQLITE_CANTOPEN_WITH_LOCKED_READWRITE) {
+ setError(ERR_ACCESS_RIGHTS,
+ i18n("The file is probably already open on this or another computer.")+"\n\n"
+ + i18n("Could not gain exclusive access for reading and writing the file.") + " "
+ + i18n("Check the file's permissions and whether it is already opened and locked by another application."));
+ }
+ else if (d->res == SQLITE_CANTOPEN_WITH_LOCKED_WRITE) {
+ setError(ERR_ACCESS_RIGHTS,
+ i18n("The file is probably already open on this or another computer.")+"\n\n"
+ + i18n("Could not gain exclusive access for writing the file.") + " "
+ + i18n("Check the file's permissions and whether it is already opened and locked by another application."));
+ }
+ return d->res == SQLITE_OK;
+#endif
+}
+
+bool SQLiteConnection::drv_closeDatabase()
+{
+ if (!d->data)
+ return false;
+
+#ifdef SQLITE2
+ sqlite_close(d->data);
+ d->data = 0;
+ return true;
+#else
+ const int res = sqlite_close(d->data);
+ if (SQLITE_OK == res) {
+ d->data = 0;
+ return true;
+ }
+ if (SQLITE_BUSY==res) {
+#if 0 //this is ANNOYING, needs fixing (by closing cursors or waiting)
+ setError(ERR_CLOSE_FAILED, i18n("Could not close busy database."));
+#else
+ return true;
+#endif
+ }
+ return false;
+#endif
+}
+
+bool SQLiteConnection::drv_dropDatabase( const QString &dbName )
+{
+ Q_UNUSED(dbName); // Each database is one single SQLite file.
+ const QString filename = data()->fileName();
+ if (QFile(filename).exists() && !QDir().remove(filename)) {
+ setError(ERR_ACCESS_RIGHTS, i18n("Could not remove file \"%1\".")
+ .arg(QDir::convertSeparators(filename)) + " "
+ + i18n("Check the file's permissions and whether it is already opened and locked by another application."));
+ return false;
+ }
+ return true;
+}
+
+//CursorData* SQLiteConnection::drv_createCursor( const QString& statement )
+Cursor* SQLiteConnection::prepareQuery( const QString& statement, uint cursor_options )
+{
+ return new SQLiteCursor( this, statement, cursor_options );
+}
+
+Cursor* SQLiteConnection::prepareQuery( QuerySchema& query, uint cursor_options )
+{
+ return new SQLiteCursor( this, query, cursor_options );
+}
+
+bool SQLiteConnection::drv_executeSQL( const QString& statement )
+{
+// KexiDBDrvDbg << "SQLiteConnection::drv_executeSQL(" << statement << ")" <<endl;
+// QCString st(statement.length()*2);
+// st = escapeString( statement.local8Bit() ); //?
+#ifdef SQLITE_UTF8
+ d->temp_st = statement.utf8();
+#else
+ d->temp_st = statement.local8Bit(); //latin1 only
+#endif
+
+#ifdef KEXI_DEBUG_GUI
+ KexiUtils::addKexiDBDebug(QString("ExecuteSQL (SQLite): ")+statement);
+#endif
+
+ d->res = sqlite_exec(
+ d->data,
+ (const char*)d->temp_st,
+ 0/*callback*/,
+ 0,
+ &d->errmsg_p );
+ d->storeResult();
+#ifdef KEXI_DEBUG_GUI
+ KexiUtils::addKexiDBDebug(d->res==SQLITE_OK ? " Success" : " Failure");
+#endif
+ return d->res==SQLITE_OK;
+}
+
+Q_ULLONG SQLiteConnection::drv_lastInsertRowID()
+{
+ return (Q_ULLONG)sqlite_last_insert_rowid(d->data);
+}
+
+int SQLiteConnection::serverResult()
+{
+ return d->res==0 ? Connection::serverResult() : d->res;
+}
+
+QString SQLiteConnection::serverResultName()
+{
+ QString r =
+#ifdef SQLITE2
+ QString::fromLatin1( sqlite_error_string(d->res) );
+#else //SQLITE3
+ QString::null; //fromLatin1( d->result_name );
+#endif
+ return r.isEmpty() ? Connection::serverResultName() : r;
+}
+
+void SQLiteConnection::drv_clearServerResult()
+{
+ if (!d)
+ return;
+ d->res = SQLITE_OK;
+#ifdef SQLITE2
+ d->errmsg_p = 0;
+#else
+// d->result_name = 0;
+#endif
+}
+
+QString SQLiteConnection::serverErrorMsg()
+{
+ return d->errmsg.isEmpty() ? Connection::serverErrorMsg() : d->errmsg;
+}
+
+PreparedStatement::Ptr SQLiteConnection::prepareStatement(PreparedStatement::StatementType type,
+ FieldList& fields)
+{
+//#ifndef SQLITE2 //TEMP IFDEF!
+ return new SQLitePreparedStatement(type, *d, fields);
+//#endif
+}
+
+bool SQLiteConnection::isReadOnly() const
+{
+#ifdef SQLITE2
+ return Connection::isReadOnly();
+#else
+ return d->data ? sqlite3_is_readonly(d->data) : false;
+#endif
+}
+
+#ifdef SQLITE2
+bool SQLiteConnection::drv_alterTableName(TableSchema& tableSchema, const QString& newName, bool replace)
+{
+ const QString oldTableName = tableSchema.name();
+ const bool destTableExists = this->tableSchema( newName ) != 0;
+
+ //1. drop the table
+ if (destTableExists) {
+ if (!replace)
+ return false;
+ if (!drv_dropTable( newName ))
+ return false;
+ }
+
+ //2. create a copy of the table
+//TODO: move this code to drv_copyTable()
+ tableSchema.setName(newName);
+
+//helper:
+#define drv_alterTableName_ERR \
+ tableSchema.setName(oldTableName) //restore old name
+
+ if (!drv_createTable( tableSchema )) {
+ drv_alterTableName_ERR;
+ return false;
+ }
+
+//TODO indices, etc.???
+
+ // 3. copy all rows to the new table
+ if (!executeSQL(QString::fromLatin1("INSERT INTO %1 SELECT * FROM %2")
+ .arg(escapeIdentifier(tableSchema.name())).arg(escapeIdentifier(oldTableName))))
+ {
+ drv_alterTableName_ERR;
+ return false;
+ }
+
+ // 4. drop old table.
+ if (!drv_dropTable( oldTableName )) {
+ drv_alterTableName_ERR;
+ return false;
+ }
+ return true;
+}
+#endif
+
+#include "sqliteconnection.moc"
diff --git a/kexi/kexidb/drivers/sqlite/sqliteconnection.h b/kexi/kexidb/drivers/sqlite/sqliteconnection.h
new file mode 100644
index 00000000..ba0d3b5a
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqliteconnection.h
@@ -0,0 +1,125 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXIDB_CONN_SQLITE_H
+#define KEXIDB_CONN_SQLITE_H
+
+#include <qstringlist.h>
+
+#include <kexidb/connection.h>
+
+/*!
+ */
+
+namespace KexiDB
+{
+
+class SQLiteConnectionInternal;
+class Driver;
+
+//! sqlite-specific connection
+class SQLiteConnection : public Connection
+{
+ Q_OBJECT
+
+ public:
+ virtual ~SQLiteConnection();
+
+ virtual Cursor* prepareQuery( const QString& statement, uint cursor_options = 0 );
+ virtual Cursor* prepareQuery( QuerySchema& query, uint cursor_options = 0 );
+
+//#ifndef SQLITE2 //TEMP IFDEF!
+ virtual PreparedStatement::Ptr prepareStatement(PreparedStatement::StatementType type,
+ FieldList& fields);
+//#endif
+ /*! Reimplemented to provide real read-only flag of the connection */
+ virtual bool isReadOnly() const;
+
+ protected:
+ /*! Used by driver */
+ SQLiteConnection( Driver *driver, ConnectionData &conn_data );
+
+ virtual bool drv_connect(KexiDB::ServerVersionInfo& version);
+ virtual bool drv_disconnect();
+ virtual bool drv_getDatabasesList( QStringList &list );
+
+//TODO: move this somewhere to low level class (MIGRATION?)
+ virtual bool drv_getTablesList( QStringList &list );
+
+//TODO: move this somewhere to low level class (MIGRATION?)
+ virtual bool drv_containsTable( const QString &tableName );
+
+ /*! Creates new database using connection. Note: Do not pass \a dbName
+ arg because for file-based engine (that has one database per connection)
+ it is defined during connection. */
+ virtual bool drv_createDatabase( const QString &dbName = QString::null );
+
+ /*! Opens existing database using connection. Do not pass \a dbName
+ arg because for file-based engine (that has one database per connection)
+ it is defined during connection. If you pass it,
+ database file name will be changed. */
+ virtual bool drv_useDatabase( const QString &dbName = QString::null, bool *cancelled = 0,
+ MessageHandler* msgHandler = 0 );
+
+ virtual bool drv_closeDatabase();
+
+ /*! Drops database from the server using connection.
+ After drop, database shouldn't be accessible
+ anymore, so database file is just removed. See note from drv_useDatabase(). */
+ virtual bool drv_dropDatabase( const QString &dbName = QString::null );
+
+ //virtual bool drv_createTable( const KexiDB::Table& table );
+
+ virtual bool drv_executeSQL( const QString& statement );
+// virtual bool drv_executeQuery( const QString& statement );
+
+ virtual Q_ULLONG drv_lastInsertRowID();
+
+ virtual int serverResult();
+ virtual QString serverResultName();
+ virtual QString serverErrorMsg();
+ virtual void drv_clearServerResult();
+ virtual tristate drv_changeFieldProperty(TableSchema &table, Field& field,
+ const QString& propertyName, const QVariant& value);
+
+#ifdef SQLITE2
+ /*! Alters table's described \a tableSchema name to \a newName.
+ This implementation is ineffective but works.
+ - creates a copy of the table
+ - copies all rows
+ - drops old table.
+ All the above should be performed within single transaction.
+ \return true on success.
+ More advanced server backends implement this using "ALTER TABLE .. RENAME TO".
+ */
+ virtual bool drv_alterTableName(TableSchema& tableSchema, const QString& newName, bool replace = false);
+#endif
+
+ //! for drv_changeFieldProperty()
+ tristate changeFieldType(TableSchema &table, Field& field, Field::Type type);
+
+ SQLiteConnectionInternal* d;
+
+ friend class SQLiteDriver;
+ friend class SQLiteCursor;
+};
+
+}
+
+#endif
diff --git a/kexi/kexidb/drivers/sqlite/sqliteconnection_p.h b/kexi/kexidb/drivers/sqlite/sqliteconnection_p.h
new file mode 100644
index 00000000..f295573d
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqliteconnection_p.h
@@ -0,0 +1,73 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXIDB_SQLITECONN_P_H
+#define KEXIDB_SQLITECONN_P_H
+
+#include <kexidb/connection_p.h>
+
+#include "sqlite.h"
+
+//for compatibility
+#ifdef _SQLITE3_H_
+# define SQLITE3
+ typedef sqlite3 sqlite_struct;
+# define sqlite_free sqlite3_free
+# define sqlite_close sqlite3_close
+# define sqlite_exec sqlite3_exec
+# define sqlite_last_insert_rowid sqlite3_last_insert_rowid
+# define sqlite_error_string sqlite3_last_insert_row_id
+# define sqlite_libversion sqlite3_libversion
+# define sqlite_libencoding sqlite3_libencoding
+#else
+# ifndef SQLITE2
+# define SQLITE2
+# endif
+ typedef struct sqlite sqlite_struct;
+# define sqlite_free sqlite_freemem
+#endif
+
+namespace KexiDB
+{
+
+/*! Internal SQLite connection data. Also used inside SQLiteCursor. */
+class SQLiteConnectionInternal : public ConnectionInternal
+{
+ public:
+ SQLiteConnectionInternal(Connection* connection);
+ virtual ~SQLiteConnectionInternal();
+
+ //! stores last result's message
+ virtual void storeResult();
+
+ sqlite_struct *data;
+ bool data_owned; //!< true if data pointer should be freed on destruction
+ QString errmsg; //<! server-specific message of last operation
+ char *errmsg_p; //<! temporary: server-specific message of last operation
+ int res; //<! result code of last operation on server
+
+ QCString temp_st;
+#ifdef SQLITE3
+ const char *result_name;
+#endif
+};
+
+}
+
+#endif
diff --git a/kexi/kexidb/drivers/sqlite/sqlitecursor.cpp b/kexi/kexidb/drivers/sqlite/sqlitecursor.cpp
new file mode 100644
index 00000000..4b18b437
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqlitecursor.cpp
@@ -0,0 +1,567 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "sqlitecursor.h"
+
+#include "sqliteconnection.h"
+#include "sqliteconnection_p.h"
+
+#include <kexidb/error.h>
+#include <kexidb/driver.h>
+#include <kexiutils/utils.h>
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <qptrvector.h>
+#include <qdatetime.h>
+
+using namespace KexiDB;
+
+//! safer interpretations of boolean values for SQLite
+static bool sqliteStringToBool(const QString& s)
+{
+ return s.lower()=="yes" || (s.lower()!="no" && s!="0");
+}
+
+//----------------------------------------------------
+
+class KexiDB::SQLiteCursorData : public SQLiteConnectionInternal
+{
+ public:
+ SQLiteCursorData(Connection* conn)
+ :
+ SQLiteConnectionInternal(conn)
+// : curr_cols(0)
+// errmsg_p(0)
+// , res(SQLITE_OK)
+ , curr_coldata(0)
+ , curr_colname(0)
+ , cols_pointers_mem_size(0)
+// , rec_stored(false)
+/* MOVED TO Cursor:
+ , cols_pointers_mem_size(0)
+ , records_in_buf(0)
+ , buffering_completed(false)
+ , at_buffer(false)*/
+//#ifdef SQLITE3
+// , rowDataReadyToFetch(false)
+//#endif
+ {
+ data_owned = false;
+ }
+
+/*#ifdef SQLITE3
+ void fetchRowDataIfNeeded()
+ {
+ if (!rowDataReadyToFetch)
+ return true;
+ rowDataReadyToFetch = false;
+ m_fieldCount = sqlite3_data_count(data);
+ for (int i=0; i<m_fieldCount; i++) {
+
+ }
+ }
+#endif*/
+
+ QCString st;
+ //for sqlite:
+// sqlite_struct *data; //! taken from SQLiteConnection
+#ifdef SQLITE2
+ sqlite_vm *prepared_st_handle; //vm
+#else //SQLITE3
+ sqlite3_stmt *prepared_st_handle;
+#endif
+
+ char *utail;
+
+// QString errmsg; //<! server-specific message of last operation
+// char *errmsg_p; //<! temporary: server-specific message of last operation
+// int res; //<! result code of last operation on server
+
+// int curr_cols;
+ const char **curr_coldata;
+ const char **curr_colname;
+
+ int next_cols;
+// const char **next_coldata;
+// const char **next_colname;
+// bool rec_stored : 1; //! true, current record is stored in next_coldata
+
+/* MOVED TO Cursor:
+ uint cols_pointers_mem_size; //! size of record's array of pointers to values
+ int records_in_buf; //! number of records currently stored in the buffer
+ bool buffering_completed; //! true if we have already all records stored in the buffer
+ QPtrVector<const char*> records; //buffer data
+ bool at_buffer; //! true if we already point to the buffer with curr_coldata
+*/
+
+/* int prev_cols;
+ const char **prev_coldata;
+ const char **prev_colname;*/
+
+ uint cols_pointers_mem_size; //! size of record's array of pointers to values
+ QPtrVector<const char*> records;//! buffer data
+//#ifdef SQLITE3
+// bool rowDataReadyToFetch : 1;
+//#endif
+
+#ifdef SQLITE3
+ inline QVariant getValue(Field *f, int i)
+ {
+ int type = sqlite3_column_type(prepared_st_handle, i);
+ if (type==SQLITE_NULL) {
+ return QVariant();
+ }
+ else if (!f || type==SQLITE_TEXT) {
+//TODO: support for UTF-16
+#define GET_sqlite3_column_text QString::fromUtf8( (const char*)sqlite3_column_text(prepared_st_handle, i) )
+ if (!f || f->isTextType())
+ return GET_sqlite3_column_text;
+ else {
+ switch (f->type()) {
+ case Field::Date:
+ return QDate::fromString( GET_sqlite3_column_text, Qt::ISODate );
+ case Field::Time:
+ //QDateTime - a hack needed because QVariant(QTime) has broken isNull()
+ return KexiUtils::stringToHackedQTime(GET_sqlite3_column_text);
+ case Field::DateTime: {
+ QString tmp( GET_sqlite3_column_text );
+ tmp[10] = 'T'; //for ISODate compatibility
+ return QDateTime::fromString( tmp, Qt::ISODate );
+ }
+ case Field::Boolean:
+ return QVariant(sqliteStringToBool(GET_sqlite3_column_text), 1);
+ default:
+ return QVariant(); //TODO
+ }
+ }
+ }
+ else if (type==SQLITE_INTEGER) {
+ switch (f->type()) {
+ case Field::Byte:
+ case Field::ShortInteger:
+ case Field::Integer:
+ return QVariant( sqlite3_column_int(prepared_st_handle, i) );
+ case Field::BigInteger:
+ return QVariant( (Q_LLONG)sqlite3_column_int64(prepared_st_handle, i) );
+ case Field::Boolean:
+ return QVariant( sqlite3_column_int(prepared_st_handle, i)!=0, 1 );
+ default:;
+ }
+ if (f->isFPNumericType()) //WEIRD, YEAH?
+ return QVariant( (double)sqlite3_column_int(prepared_st_handle, i) );
+ else
+ return QVariant(); //TODO
+ }
+ else if (type==SQLITE_FLOAT) {
+ if (f && f->isFPNumericType())
+ return QVariant( sqlite3_column_double(prepared_st_handle, i) );
+ else if (!f || f->isIntegerType())
+ return QVariant( (double)sqlite3_column_double(prepared_st_handle, i) );
+ else
+ return QVariant(); //TODO
+ }
+ else if (type==SQLITE_BLOB) {
+ if (f && f->type()==Field::BLOB) {
+ QByteArray ba;
+//! @todo efficient enough?
+ ba.duplicate((const char*)sqlite3_column_blob(prepared_st_handle, i),
+ sqlite3_column_bytes(prepared_st_handle, i));
+ return ba;
+ } else
+ return QVariant(); //TODO
+ }
+ return QVariant();
+ }
+#endif //SQLITE3
+};
+
+SQLiteCursor::SQLiteCursor(Connection* conn, const QString& statement, uint options)
+ : Cursor( conn, statement, options )
+ , d( new SQLiteCursorData(conn) )
+{
+ d->data = static_cast<SQLiteConnection*>(conn)->d->data;
+}
+
+SQLiteCursor::SQLiteCursor(Connection* conn, QuerySchema& query, uint options )
+ : Cursor( conn, query, options )
+ , d( new SQLiteCursorData(conn) )
+{
+ d->data = static_cast<SQLiteConnection*>(conn)->d->data;
+}
+
+SQLiteCursor::~SQLiteCursor()
+{
+ close();
+ delete d;
+}
+
+bool SQLiteCursor::drv_open()
+{
+// d->st.resize(statement.length()*2);
+ //TODO: decode
+// d->st = statement.local8Bit();
+// d->st = m_conn->driver()->escapeString( statement.local8Bit() );
+
+ if(! d->data) {
+ // this may as example be the case if SQLiteConnection::drv_useDatabase()
+ // wasn't called before. Normaly sqlite_compile/sqlite3_prepare
+ // should handle it, but it crashes in in sqlite3SafetyOn at util.c:786
+ kdWarning() << "SQLiteCursor::drv_open(): Database handle undefined." << endl;
+ return false;
+ }
+
+#ifdef SQLITE2
+ d->st = m_sql.local8Bit();
+ d->res = sqlite_compile(
+ d->data,
+ d->st.data(),
+ (const char**)&d->utail,
+ &d->prepared_st_handle,
+ &d->errmsg_p );
+#else //SQLITE3
+ d->st = m_sql.utf8();
+ d->res = sqlite3_prepare(
+ d->data, /* Database handle */
+ d->st.data(), /* SQL statement, UTF-8 encoded */
+ d->st.length(), /* Length of zSql in bytes. */
+ &d->prepared_st_handle, /* OUT: Statement handle */
+ 0/*const char **pzTail*/ /* OUT: Pointer to unused portion of zSql */
+ );
+#endif
+ if (d->res!=SQLITE_OK) {
+ d->storeResult();
+ return false;
+ }
+//cursor is automatically @ first record
+// m_beforeFirst = true;
+
+ if (isBuffered()) {
+ d->records.resize(128); //TODO: manage size dynamically
+ }
+
+ return true;
+}
+
+/*bool SQLiteCursor::drv_getFirstRecord()
+{
+ bool ok = drv_getNextRecord();*/
+/* if ((m_options & Buffered) && ok) { //1st record is there:
+ //compute parameters for cursor's buffer:
+ //-size of record's array of pointer to values
+ d->cols_pointers_mem_size = d->curr_cols * sizeof(char*);
+ d->records_in_buf = 1;
+ }*/
+ /*return ok;
+}*/
+
+bool SQLiteCursor::drv_close()
+{
+#ifdef SQLITE2
+ d->res = sqlite_finalize( d->prepared_st_handle, &d->errmsg_p );
+#else //SQLITE3
+ d->res = sqlite3_finalize( d->prepared_st_handle );
+#endif
+ if (d->res!=SQLITE_OK) {
+ d->storeResult();
+ return false;
+ }
+ return true;
+}
+
+void SQLiteCursor::drv_getNextRecord()
+{
+#ifdef SQLITE2
+ static int _fieldCount;
+ d->res = sqlite_step(
+ d->prepared_st_handle,
+ &_fieldCount,
+ &d->curr_coldata,
+ &d->curr_colname);
+#else //SQLITE3
+ d->res = sqlite3_step( d->prepared_st_handle );
+#endif
+ if (d->res == SQLITE_ROW) {
+ m_result = FetchOK;
+#ifdef SQLITE2
+ m_fieldCount = (uint)_fieldCount;
+#else
+ m_fieldCount = sqlite3_data_count(d->prepared_st_handle);
+//#else //for SQLITE3 data fetching is delayed. Now we even do not take field count information
+// // -- just set a flag that we've a data not fetched but available
+// d->rowDataReadyToFetch = true;
+#endif
+ //(m_logicalFieldCount introduced) m_fieldCount -= (m_containsROWIDInfo ? 1 : 0);
+ } else {
+//#ifdef SQLITE3
+// d->rowDataReadyToFetch = false;
+//#endif
+ if (d->res==SQLITE_DONE)
+ m_result = FetchEnd;
+ else
+ m_result = FetchError;
+ }
+
+ //debug
+/*
+ if (m_result == FetchOK && d->curr_coldata) {
+ for (uint i=0;i<m_fieldCount;i++) {
+ KexiDBDrvDbg<<"col."<< i<<": "<< d->curr_colname[i]<<" "<< d->curr_colname[m_fieldCount+i]
+ << " = " << (d->curr_coldata[i] ? QString::fromLocal8Bit(d->curr_coldata[i]) : "(NULL)") <<endl;
+ }
+// KexiDBDrvDbg << "SQLiteCursor::drv_getNextRecord(): "<<m_fieldCount<<" col(s) fetched"<<endl;
+ }*/
+}
+
+void SQLiteCursor::drv_appendCurrentRecordToBuffer()
+{
+// KexiDBDrvDbg << "SQLiteCursor::drv_appendCurrentRecordToBuffer():" <<endl;
+ if (!d->cols_pointers_mem_size)
+ d->cols_pointers_mem_size = m_fieldCount * sizeof(char*);
+ const char **record = (const char**)malloc(d->cols_pointers_mem_size);
+ const char **src_col = d->curr_coldata;
+ const char **dest_col = record;
+ for (uint i=0; i<m_fieldCount; i++,src_col++,dest_col++) {
+// KexiDBDrvDbg << i <<": '" << *src_col << "'" <<endl;
+// KexiDBDrvDbg << "src_col: " << src_col << endl;
+ *dest_col = *src_col ? strdup(*src_col) : 0;
+ }
+ d->records.insert(m_records_in_buf,record);
+// KexiDBDrvDbg << "SQLiteCursor::drv_appendCurrentRecordToBuffer() ok." <<endl;
+}
+
+void SQLiteCursor::drv_bufferMovePointerNext()
+{
+ d->curr_coldata++; //move to next record in the buffer
+}
+
+void SQLiteCursor::drv_bufferMovePointerPrev()
+{
+ d->curr_coldata--; //move to prev record in the buffer
+}
+
+//compute a place in the buffer that contain next record's data
+//and move internal buffer pointer to that place
+void SQLiteCursor::drv_bufferMovePointerTo(Q_LLONG at)
+{
+ d->curr_coldata = d->records.at(at);
+}
+
+void SQLiteCursor::drv_clearBuffer()
+{
+ if (d->cols_pointers_mem_size>0) {
+ const uint records_in_buf = m_records_in_buf;
+ const char ***r_ptr = d->records.data();
+ for (uint i=0; i<records_in_buf; i++, r_ptr++) {
+ // const char **record = m_records.at(i);
+ const char **field_data = *r_ptr;
+ // for (int col=0; col<d->curr_cols; col++, field_data++) {
+ for (uint col=0; col<m_fieldCount; col++, field_data++) {
+ free((void*)*field_data); //free field memory
+ }
+ free(*r_ptr); //free pointers to fields array
+ }
+ }
+// d->curr_cols=0;
+// m_fieldCount=0;
+ m_records_in_buf=0;
+ d->cols_pointers_mem_size=0;
+// m_at_buffer=false;
+ d->records.clear();
+}
+
+/*
+void SQLiteCursor::drv_storeCurrentRecord()
+{
+#if 0
+ assert(!m_data->rec_stored);
+ m_data->rec_stored = true;
+ m_data->next_cols = m_data->curr_cols;
+ for (int i=0;i<m_data->curr_cols;i++) {
+ KexiDBDrvDbg<<"[COPY] "<<i<<": "<< m_data->curr_coldata[i]<<endl;
+ if (m_data->curr_coldata[i])
+ m_data->next_coldata[i] = strdup( m_data->curr_coldata[i] );
+ else
+ m_data->next_coldata[i] = 0;
+ }
+#endif
+}
+*/
+
+/*TODO
+const char *** SQLiteCursor::bufferData()
+{
+ if (!isBuffered())
+ return 0;
+ return m_records.data();
+}*/
+
+const char ** SQLiteCursor::rowData() const
+{
+ return d->curr_coldata;
+}
+
+void SQLiteCursor::storeCurrentRow(RowData &data) const
+{
+#ifdef SQLITE2
+ const char **col = d->curr_coldata;
+#endif
+ //const uint realCount = m_fieldCount + (m_containsROWIDInfo ? 1 : 0);
+ data.resize(m_fieldCount);
+ if (!m_fieldsExpanded) {//simple version: without types
+ for( uint i=0; i<m_fieldCount; i++ ) {
+#ifdef SQLITE2
+ data[i] = QVariant( *col );
+ col++;
+#else //SQLITE3
+ data[i] = QString::fromUtf8( (const char*)sqlite3_column_text(d->prepared_st_handle, i) );
+#endif
+ }
+ return;
+ }
+
+ //const uint fieldsExpandedCount = m_fieldsExpanded->count();
+ const uint maxCount = QMIN(m_fieldCount, m_fieldsExpanded->count());
+ // i - visible field's index, j - physical index
+ for( uint i=0, j=0; i<m_fieldCount; i++, j++ ) {
+// while (j < m_detailedVisibility.count() && !m_detailedVisibility[j]) //!m_query->isColumnVisible(j))
+// j++;
+ while (j < maxCount && !m_fieldsExpanded->at(j)->visible)
+ j++;
+ if (j >= (maxCount /*+(m_containsROWIDInfo ? 1 : 0)*/)) {
+ //ERR!
+ break;
+ }
+ //(m_logicalFieldCount introduced) Field *f = (m_containsROWIDInfo && i>=m_fieldCount) ? 0 : m_fieldsExpanded->at(j)->field;
+ Field *f = (i>=m_fieldCount) ? 0 : m_fieldsExpanded->at(j)->field;
+// KexiDBDrvDbg << "SQLiteCursor::storeCurrentRow(): col=" << (col ? *col : 0) << endl;
+
+#ifdef SQLITE2
+ if (!*col)
+ data[i] = QVariant();
+ else if (f && f->isTextType())
+# ifdef SQLITE_UTF8
+ data[i] = QString::fromUtf8( *col );
+# else
+ data[i] = QVariant( *col ); //only latin1
+# endif
+ else if (f && f->isFPNumericType())
+ data[i] = QVariant( QCString(*col).toDouble() );
+ else {
+ switch (f ? f->type() : Field::Integer/*ROWINFO*/) {
+//todo: use short, etc.
+ case Field::Byte:
+ case Field::ShortInteger:
+ case Field::Integer:
+ data[i] = QVariant( QCString(*col).toInt() );
+ case Field::BigInteger:
+ data[i] = QVariant( QString::fromLatin1(*col).toLongLong() );
+ case Field::Boolean:
+ data[i] = QVariant( sqliteStringToBool(QString::fromLatin1(*col)), 1 );
+ break;
+ case Field::Date:
+ data[i] = QDate::fromString( QString::fromLatin1(*col), Qt::ISODate );
+ break;
+ case Field::Time:
+ //QDateTime - a hack needed because QVariant(QTime) has broken isNull()
+ data[i] = KexiUtils::stringToHackedQTime(QString::fromLatin1(*col));
+ break;
+ case Field::DateTime: {
+ QString tmp( QString::fromLatin1(*col) );
+ tmp[10] = 'T';
+ data[i] = QDateTime::fromString( tmp, Qt::ISODate );
+ break;
+ }
+ default:
+ data[i] = QVariant( *col );
+ }
+ }
+
+ col++;
+#else //SQLITE3
+ data[i] = d->getValue(f, i); //, !f /*!f means ROWID*/);
+#endif
+ }
+}
+
+QVariant SQLiteCursor::value(uint i)
+{
+// if (i > (m_fieldCount-1+(m_containsROWIDInfo?1:0))) //range checking
+ if (i > (m_fieldCount-1)) //range checking
+ return QVariant();
+//TODO: allow disable range checking! - performance reasons
+// const KexiDB::Field *f = m_query ? m_query->field(i) : 0;
+ KexiDB::Field *f = (m_fieldsExpanded && i<m_fieldsExpanded->count())
+ ? m_fieldsExpanded->at(i)->field : 0;
+#ifdef SQLITE2
+ //from most to least frequently used types:
+//(m_logicalFieldCount introduced) if (i==m_fieldCount || f && f->isIntegerType())
+ if (!f || f->isIntegerType())
+ return QVariant( QCString(d->curr_coldata[i]).toInt() );
+ else if (!f || f->isTextType())
+ return QVariant( d->curr_coldata[i] );
+ else if (f->isFPNumericType())
+ return QVariant( QCString(d->curr_coldata[i]).toDouble() );
+
+ return QVariant( d->curr_coldata[i] ); //default
+#else
+ return d->getValue(f, i); //, i==m_logicalFieldCount/*ROWID*/);
+#endif
+}
+
+/*! Stores string value taken from field number \a i to \a str.
+ \return false when range checking failed.
+bool SQLiteCursor::storeStringValue(uint i, QString &str)
+{
+ if (i > (m_fieldCount-1)) //range checking
+ return false;
+ str = d->curr_coldata[i];
+ return true;
+}*/
+
+int SQLiteCursor::serverResult()
+{
+ return d->res;
+}
+
+QString SQLiteCursor::serverResultName()
+{
+#ifdef SQLITE2
+ return QString::fromLatin1( sqlite_error_string(d->res) );
+#else //SQLITE3
+ return QString::fromLatin1( d->result_name );
+#endif
+}
+
+QString SQLiteCursor::serverErrorMsg()
+{
+ return d->errmsg;
+}
+
+void SQLiteCursor::drv_clearServerResult()
+{
+ d->res = SQLITE_OK;
+ d->errmsg_p = 0;
+}
+
diff --git a/kexi/kexidb/drivers/sqlite/sqlitecursor.h b/kexi/kexidb/drivers/sqlite/sqlitecursor.h
new file mode 100644
index 00000000..b7170f67
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqlitecursor.h
@@ -0,0 +1,92 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXIDB_SQLITECURSOR_H
+#define KEXIDB_SQLITECURSOR_H
+
+#include <qstring.h>
+
+#include <kexidb/cursor.h>
+#include "connection.h"
+
+namespace KexiDB {
+
+class SQLiteCursorData;
+
+/*!
+
+*/
+class SQLiteCursor : public Cursor
+{
+ public:
+ virtual ~SQLiteCursor();
+ virtual QVariant value(uint i);
+
+ /*! [PROTOTYPE] \return internal buffer data. */
+//TODO virtual const char *** bufferData()
+ /*! [PROTOTYPE] \return current record data or NULL if there is no current records. */
+ virtual const char ** rowData() const;
+
+ virtual void storeCurrentRow(RowData &data) const;
+
+// virtual bool save(RowData& data, RowEditBuffer& buf);
+
+ virtual int serverResult();
+ virtual QString serverResultName();
+ virtual QString serverErrorMsg();
+
+ protected:
+ /*! Cursor will operate on \a conn, raw \a statement will be used to execute query. */
+ SQLiteCursor(Connection* conn, const QString& statement, uint options = NoOptions );
+
+ /*! Cursor will operate on \a conn, \a query schema will be used to execute query. */
+ SQLiteCursor(Connection* conn, QuerySchema& query,
+ uint options = NoOptions );
+
+ virtual bool drv_open();
+
+ virtual bool drv_close();
+// virtual bool drv_moveFirst();
+ virtual void drv_getNextRecord();
+//unused virtual bool drv_getPrevRecord();
+
+ virtual void drv_appendCurrentRecordToBuffer();
+ virtual void drv_bufferMovePointerNext();
+ virtual void drv_bufferMovePointerPrev();
+ virtual void drv_bufferMovePointerTo(Q_LLONG at);
+
+//TODO virtual void drv_storeCurrentRecord();
+
+ //PROTOTYPE:
+ /*! Method called when cursor's buffer need to be cleared
+ (only for buffered cursor type), eg. in close(). */
+ virtual void drv_clearBuffer();
+
+ virtual void drv_clearServerResult();
+
+ SQLiteCursorData *d;
+
+ friend class SQLiteConnection;
+};
+
+} //namespace KexiDB
+
+#endif
+
+
diff --git a/kexi/kexidb/drivers/sqlite/sqlitedriver.cpp b/kexi/kexidb/drivers/sqlite/sqlitedriver.cpp
new file mode 100644
index 00000000..e2abc246
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqlitedriver.cpp
@@ -0,0 +1,159 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <kexidb/connection.h>
+#include <kexidb/drivermanager.h>
+#include <kexidb/driver_p.h>
+#include <kexidb/utils.h>
+
+#include "sqlite.h"
+#include "sqlitedriver.h"
+#include "sqliteconnection.h"
+#include "sqliteconnection_p.h"
+#include "sqliteadmin.h"
+
+#include <kdebug.h>
+
+using namespace KexiDB;
+
+#ifdef SQLITE2
+KEXIDB_DRIVER_INFO( SQLiteDriver, sqlite2 )
+#else
+KEXIDB_DRIVER_INFO( SQLiteDriver, sqlite3 )
+#endif
+
+//! driver specific private data
+//! @internal
+class KexiDB::SQLiteDriverPrivate
+{
+ public:
+ SQLiteDriverPrivate()
+ {
+ }
+};
+
+//PgSqlDB::PgSqlDB(QObject *parent, const char *name, const QStringList &)
+SQLiteDriver::SQLiteDriver( QObject *parent, const char *name, const QStringList &args )
+ : Driver( parent, name, args )
+ ,dp( new SQLiteDriverPrivate() )
+{
+ d->isFileDriver = true;
+ d->isDBOpenedAfterCreate = true;
+ d->features = SingleTransactions | CursorForward
+#ifndef SQLITE2
+ | CompactingDatabaseSupported;
+#endif
+ ;
+
+ //special method for autoincrement definition
+ beh->SPECIAL_AUTO_INCREMENT_DEF = true;
+ beh->AUTO_INCREMENT_FIELD_OPTION = ""; //not available
+ beh->AUTO_INCREMENT_TYPE = "INTEGER";
+ beh->AUTO_INCREMENT_PK_FIELD_OPTION = "PRIMARY KEY";
+ beh->AUTO_INCREMENT_REQUIRES_PK = true;
+ beh->ROW_ID_FIELD_NAME = "OID";
+ beh->_1ST_ROW_READ_AHEAD_REQUIRED_TO_KNOW_IF_THE_RESULT_IS_EMPTY=true;
+ beh->QUOTATION_MARKS_FOR_IDENTIFIER='"';
+ beh->SELECT_1_SUBQUERY_SUPPORTED = true;
+ beh->SQL_KEYWORDS = keywords;
+ initSQLKeywords(29);
+
+ //predefined properties
+ d->properties["client_library_version"] = sqlite_libversion();
+ d->properties["default_server_encoding"] =
+#ifdef SQLITE2
+ sqlite_libencoding();
+#else //SQLITE3
+ "UTF8"; //OK?
+#endif
+
+ d->typeNames[Field::Byte]="Byte";
+ d->typeNames[Field::ShortInteger]="ShortInteger";
+ d->typeNames[Field::Integer]="Integer";
+ d->typeNames[Field::BigInteger]="BigInteger";
+ d->typeNames[Field::Boolean]="Boolean";
+ d->typeNames[Field::Date]="Date"; // In fact date/time types could be declared as datetext etc.
+ d->typeNames[Field::DateTime]="DateTime"; // to force text affinity..., see http://sqlite.org/datatype3.html
+ d->typeNames[Field::Time]="Time"; //
+ d->typeNames[Field::Float]="Float";
+ d->typeNames[Field::Double]="Double";
+ d->typeNames[Field::Text]="Text";
+ d->typeNames[Field::LongText]="CLOB";
+ d->typeNames[Field::BLOB]="BLOB";
+}
+
+SQLiteDriver::~SQLiteDriver()
+{
+ delete dp;
+}
+
+
+KexiDB::Connection*
+SQLiteDriver::drv_createConnection( ConnectionData &conn_data )
+{
+ return new SQLiteConnection( this, conn_data );
+}
+
+bool SQLiteDriver::isSystemObjectName( const QString& n ) const
+{
+ return Driver::isSystemObjectName(n) || n.lower().startsWith("sqlite_");
+}
+
+bool SQLiteDriver::drv_isSystemFieldName( const QString& n ) const
+{
+ return n.lower()=="_rowid_"
+ || n.lower()=="rowid"
+ || n.lower()=="oid";
+}
+
+QString SQLiteDriver::escapeString(const QString& str) const
+{
+ return QString("'")+QString(str).replace( '\'', "''" ) + "'";
+}
+
+QCString SQLiteDriver::escapeString(const QCString& str) const
+{
+ return QCString("'")+QCString(str).replace( '\'', "''" )+"'";
+}
+
+QString SQLiteDriver::escapeBLOB(const QByteArray& array) const
+{
+ return KexiDB::escapeBLOB(array, KexiDB::BLOBEscapeXHex);
+}
+
+QString SQLiteDriver::drv_escapeIdentifier( const QString& str) const
+{
+ return QString(str).replace( '"', "\"\"" );
+}
+
+QCString SQLiteDriver::drv_escapeIdentifier( const QCString& str) const
+{
+ return QCString(str).replace( '"', "\"\"" );
+}
+
+AdminTools* SQLiteDriver::drv_createAdminTools() const
+{
+#ifdef SQLITE2
+ return new AdminTools(); //empty impl.
+#else
+ return new SQLiteAdminTools();
+#endif
+}
+
+#include "sqlitedriver.moc"
diff --git a/kexi/kexidb/drivers/sqlite/sqlitedriver.h b/kexi/kexidb/drivers/sqlite/sqlitedriver.h
new file mode 100644
index 00000000..66d4d4d2
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqlitedriver.h
@@ -0,0 +1,82 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXIDB_DRIVER_SQLITE_H
+#define KEXIDB_DRIVER_SQLITE_H
+
+#include <qstringlist.h>
+
+#include <kexidb/driver.h>
+
+namespace KexiDB
+{
+
+class Connection;
+class DriverManager;
+class SQLiteDriverPrivate;
+
+//! SQLite database driver.
+class SQLiteDriver : public Driver
+{
+ Q_OBJECT
+ KEXIDB_DRIVER
+
+ public:
+ SQLiteDriver( QObject *parent, const char *name, const QStringList &args = QStringList() );
+ virtual ~SQLiteDriver();
+
+ /*! \return true if \a n is a system object name;
+ for this driver any object with name prefixed with "sqlite_"
+ is considered as system object.
+ */
+ virtual bool isSystemObjectName( const QString& n ) const;
+
+ /*! \return false for this driver. */
+ virtual bool isSystemDatabaseName( const QString& ) const { return false; }
+
+ //! Escape a string for use as a value
+ virtual QString escapeString(const QString& str) const;
+ virtual QCString escapeString(const QCString& str) const;
+
+ //! Escape BLOB value \a array
+ virtual QString escapeBLOB(const QByteArray& array) const;
+
+ protected:
+ virtual QString drv_escapeIdentifier( const QString& str) const;
+ virtual QCString drv_escapeIdentifier( const QCString& str) const;
+ virtual Connection *drv_createConnection( ConnectionData &conn_data );
+ virtual AdminTools* drv_createAdminTools() const;
+
+ /*! \return true if \a n is a system field name;
+ for this driver fields with name equal "_ROWID_"
+ is considered as system field.
+ */
+ virtual bool drv_isSystemFieldName( const QString& n ) const;
+
+ SQLiteDriverPrivate *dp;
+
+ private:
+ static const char *keywords[];
+
+};
+
+}
+
+#endif
+
diff --git a/kexi/kexidb/drivers/sqlite/sqlitekeywords.cpp b/kexi/kexidb/drivers/sqlite/sqlitekeywords.cpp
new file mode 100644
index 00000000..a3d6095b
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqlitekeywords.cpp
@@ -0,0 +1,39 @@
+ /*
+ * This file has been automatically generated from
+ * koffice/kexi/tools/sql_keywords/sql_keywords.sh and
+ * ../../3rdparty/kexisql3/src/tokenize.c.
+ *
+ * Please edit the sql_keywords.sh, not this file!
+ */
+#include <sqlitedriver.h>
+
+namespace KexiDB {
+ const char* SQLiteDriver::keywords[] = {
+ "ABORT",
+ "ATTACH",
+ "CLUSTER",
+ "CONFLICT",
+ "DEFERRED",
+ "DEFERRABLE",
+ "DETACH",
+ "EACH",
+ "EXCEPT",
+ "FAIL",
+ "GLOB",
+ "IMMEDIATE",
+ "INITIALLY",
+ "INSTEAD",
+ "INTERSECT",
+ "ISNULL",
+ "NOTNULL",
+ "OF",
+ "PRAGMA",
+ "RAISE",
+ "STATEMENT",
+ "TEMP",
+ "TRIGGER",
+ "VACUUM",
+ "VIEW",
+ 0
+ };
+}
diff --git a/kexi/kexidb/drivers/sqlite/sqlitepreparedstatement.cpp b/kexi/kexidb/drivers/sqlite/sqlitepreparedstatement.cpp
new file mode 100644
index 00000000..9103b131
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqlitepreparedstatement.cpp
@@ -0,0 +1,242 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "sqlitepreparedstatement.h"
+
+#include <kdebug.h>
+#include <assert.h>
+
+using namespace KexiDB;
+
+SQLitePreparedStatement::SQLitePreparedStatement(StatementType type, ConnectionInternal& conn,
+ FieldList& fields)
+ : KexiDB::PreparedStatement(type, conn, fields)
+ , SQLiteConnectionInternal(conn.connection)
+ , prepared_st_handle(0)
+ , m_resetRequired(false)
+{
+ data_owned = false;
+ data = dynamic_cast<KexiDB::SQLiteConnectionInternal&>(conn).data; //copy
+
+ temp_st = generateStatementString();
+#ifdef SQLITE2
+ //! @todo
+#else
+ if (!temp_st.isEmpty()) {
+ res = sqlite3_prepare(
+ data, /* Database handle */
+ temp_st, //const char *zSql, /* SQL statement, UTF-8 encoded */
+ temp_st.length(), //int nBytes, /* Length of zSql in bytes. */
+ &prepared_st_handle, //sqlite3_stmt **ppStmt, /* OUT: Statement handle */
+ 0 //const char **pzTail /* OUT: Pointer to unused portion of zSql */
+ );
+ if (SQLITE_OK != res) {
+//! @todo copy error msg
+ }
+ }
+#endif
+}
+
+SQLitePreparedStatement::~SQLitePreparedStatement()
+{
+#ifdef SQLITE2
+//! @todo
+#else
+ sqlite3_finalize(prepared_st_handle);
+ prepared_st_handle = 0;
+#endif
+}
+
+bool SQLitePreparedStatement::execute()
+{
+#ifdef SQLITE2
+//! @todo
+#else
+ if (!prepared_st_handle)
+ return false;
+ if (m_resetRequired) {
+ res = sqlite3_reset(prepared_st_handle);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ m_resetRequired = false;
+ }
+
+ int arg=1; //arg index counted from 1
+ KexiDB::Field *field;
+
+ Field::List _dummy;
+ Field::ListIterator itFields(_dummy);
+ //for INSERT, we're iterating over inserting values
+ //for SELECT, we're iterating over WHERE conditions
+ if (m_type == SelectStatement)
+ itFields = *m_whereFields;
+ else if (m_type == InsertStatement)
+ itFields = m_fields->fieldsIterator();
+ else
+ assert(0); //impl. error
+
+ for (QValueListConstIterator<QVariant> it = m_args.constBegin();
+ (field = itFields.current()); ++it, ++itFields, arg++)
+ {
+ if (it==m_args.constEnd() || (*it).isNull()) {//no value to bind or the value is null: bind NULL
+ res = sqlite3_bind_null(prepared_st_handle, arg);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ continue;
+ }
+ if (field->isTextType()) {
+ //! @todo optimize: make a static copy so SQLITE_STATIC can be used
+ QCString utf8String((*it).toString().utf8());
+ res = sqlite3_bind_text(prepared_st_handle, arg,
+ (const char*)utf8String, utf8String.length(), SQLITE_TRANSIENT /*??*/);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ }
+ else switch (field->type()) {
+ case KexiDB::Field::Byte:
+ case KexiDB::Field::ShortInteger:
+ case KexiDB::Field::Integer:
+ {
+//! @todo what about unsigned > INT_MAX ?
+ bool ok;
+ const int value = (*it).toInt(&ok);
+ if (ok) {
+ res = sqlite3_bind_int(prepared_st_handle, arg, value);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ }
+ else {
+ res = sqlite3_bind_null(prepared_st_handle, arg);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ }
+ break;
+ }
+ case KexiDB::Field::Float:
+ case KexiDB::Field::Double:
+ res = sqlite3_bind_double(prepared_st_handle, arg, (*it).toDouble());
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ break;
+ case KexiDB::Field::BigInteger:
+ {
+//! @todo what about unsigned > LLONG_MAX ?
+ bool ok;
+ Q_LLONG value = (*it).toLongLong(&ok);
+ if (ok) {
+ res = sqlite3_bind_int64(prepared_st_handle, arg, value);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ }
+ else {
+ res = sqlite3_bind_null(prepared_st_handle, arg);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ }
+ break;
+ }
+ case KexiDB::Field::Boolean:
+ res = sqlite3_bind_text(prepared_st_handle, arg,
+ QString::number((*it).toBool() ? 1 : 0).latin1(),
+ 1, SQLITE_TRANSIENT /*??*/);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ break;
+ case KexiDB::Field::Time:
+ res = sqlite3_bind_text(prepared_st_handle, arg,
+ (*it).toTime().toString(Qt::ISODate).latin1(),
+ sizeof("HH:MM:SS"), SQLITE_TRANSIENT /*??*/);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ break;
+ case KexiDB::Field::Date:
+ res = sqlite3_bind_text(prepared_st_handle, arg,
+ (*it).toDate().toString(Qt::ISODate).latin1(),
+ sizeof("YYYY-MM-DD"), SQLITE_TRANSIENT /*??*/);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ break;
+ case KexiDB::Field::DateTime:
+ res = sqlite3_bind_text(prepared_st_handle, arg,
+ (*it).toDateTime().toString(Qt::ISODate).latin1(),
+ sizeof("YYYY-MM-DDTHH:MM:SS"), SQLITE_TRANSIENT /*??*/);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ break;
+ case KexiDB::Field::BLOB:
+ {
+ const QByteArray byteArray((*it).toByteArray());
+ res = sqlite3_bind_blob(prepared_st_handle, arg,
+ (const char*)byteArray, byteArray.size(), SQLITE_TRANSIENT /*??*/);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ break;
+ }
+ default:
+ KexiDBWarn << "PreparedStatement::execute(): unsupported field type: "
+ << field->type() << " - NULL value bound to column #" << arg << endl;
+ res = sqlite3_bind_null(prepared_st_handle, arg);
+ if (SQLITE_OK != res) {
+ //! @todo msg?
+ return false;
+ }
+ } //switch
+ }
+
+ //real execution
+ res = sqlite3_step(prepared_st_handle);
+ m_resetRequired = true;
+ if (m_type == InsertStatement && res == SQLITE_DONE) {
+ return true;
+ }
+ if (m_type == SelectStatement) {
+ //fetch result
+
+ //todo
+ }
+#endif
+ return false;
+}
+
diff --git a/kexi/kexidb/drivers/sqlite/sqlitepreparedstatement.h b/kexi/kexidb/drivers/sqlite/sqlitepreparedstatement.h
new file mode 100644
index 00000000..b8b9c376
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqlitepreparedstatement.h
@@ -0,0 +1,50 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXIDB_SQLITEPREPAREDSTATEMENT_H
+//&& !defined SQLITE2
+#define KEXIDB_SQLITEPREPAREDSTATEMENT_H
+
+#include <kexidb/preparedstatement.h>
+#include "sqliteconnection_p.h"
+
+namespace KexiDB {
+
+/*! Implementation of prepared statements for SQLite driver. */
+class SQLitePreparedStatement : public PreparedStatement, SQLiteConnectionInternal
+{
+ public:
+ SQLitePreparedStatement(StatementType type, ConnectionInternal& conn,
+ FieldList& fields);
+
+ virtual ~SQLitePreparedStatement();
+
+ virtual bool execute();
+
+#ifdef SQLITE2
+ sqlite_vm *prepared_st_handle;
+#else //SQLITE3
+ sqlite3_stmt *prepared_st_handle;
+#endif
+ bool m_resetRequired : 1;
+};
+
+}
+
+#endif
diff --git a/kexi/kexidb/drivers/sqlite/sqlitevacuum.cpp b/kexi/kexidb/drivers/sqlite/sqlitevacuum.cpp
new file mode 100644
index 00000000..adf8709a
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqlitevacuum.cpp
@@ -0,0 +1,150 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <kexidb/global.h>
+#include "sqlitevacuum.h"
+
+#include <kstandarddirs.h>
+#include <kprogress.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <ktempfile.h>
+#include <kmessagebox.h>
+#include <kio/global.h>
+
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qapplication.h>
+#include <qprocess.h>
+#include <qcursor.h>
+
+#include <unistd.h>
+
+SQLiteVacuum::SQLiteVacuum(const QString& filePath)
+: m_filePath(filePath)
+{
+ m_process = 0;
+ m_percent = 0;
+ m_dlg = 0;
+ m_result = true;
+}
+
+SQLiteVacuum::~SQLiteVacuum()
+{
+ delete m_process;
+ if (m_dlg)
+ m_dlg->close();
+ delete m_dlg;
+}
+
+tristate SQLiteVacuum::run()
+{
+ const QString ksqlite_app = KStandardDirs::findExe( "ksqlite" );
+ if (ksqlite_app.isEmpty()) {
+ m_result = false;
+ return m_result;
+ }
+ QFileInfo fi(m_filePath);
+ if (!fi.isReadable()) {
+ KexiDBDrvWarn << "SQLiteVacuum::run(): No such file" << m_filePath << endl;
+ return false;
+ }
+ const uint origSize = fi.size();
+
+ QStringList args;
+ args << ksqlite_app << "-verbose-vacuum" << m_filePath << "vacuum";
+ m_process = new QProcess(args, this, "process");
+ m_process->setWorkingDirectory( QFileInfo(m_filePath).dir(true) );
+ connect( m_process, SIGNAL(readyReadStdout()), this, SLOT(readFromStdout()) );
+ connect( m_process, SIGNAL(processExited()), this, SLOT(processExited()) );
+ if (!m_process->start()) {
+ m_result = false;
+ return m_result;
+ }
+ m_dlg = new KProgressDialog(0, 0, i18n("Compacting database"),
+ "<qt>"+i18n("Compacting database \"%1\"...")
+ .arg("<nobr>"+QDir::convertSeparators(QFileInfo(m_filePath).fileName())+"</nobr>")
+ );
+ m_dlg->adjustSize();
+ m_dlg->resize(300, m_dlg->height());
+ connect(m_dlg, SIGNAL(cancelClicked()), this, SLOT(cancelClicked()));
+ m_dlg->setMinimumDuration(1000);
+ m_dlg->setAutoClose(true);
+ m_dlg->progressBar()->setTotalSteps(100);
+ m_dlg->exec();
+ while (m_process->isRunning()) {
+ readFromStdout();
+ usleep(50000);
+ }
+ delete m_process;
+ m_process = 0;
+ if (m_result == true) {
+ const uint newSize = QFileInfo(m_filePath).size();
+ const uint decrease = 100-100*newSize/origSize;
+ KMessageBox::information(0, i18n("The database has been compacted. Current size decreased by %1% to %2.")
+ .arg(decrease).arg(KIO::convertSize(newSize)));
+ }
+ return m_result;
+}
+
+void SQLiteVacuum::readFromStdout()
+{
+ while (true) {
+ QString s( m_process->readLineStdout() ); //readStdout();
+ if (s.isEmpty())
+ break;
+ m_dlg->progressBar()->setProgress(m_percent);
+// KexiDBDrvDbg << m_percent << " " << s << endl;
+ if (s.startsWith("VACUUM: ")) {
+ //set previously known progress
+ m_dlg->progressBar()->setProgress(m_percent);
+ //update progress info
+ if (s.mid(8,4)=="100%") {
+ m_percent = 100;
+ m_dlg->setAllowCancel(false);
+ m_dlg->setCursor(QCursor(Qt::WaitCursor));
+ }
+ else if (s.mid(9,1)=="%") {
+ m_percent = s.mid(8,1).toInt();
+ }
+ else if (s.mid(10,1)=="%") {
+ m_percent = s.mid(8,2).toInt();
+ }
+ m_process->writeToStdin(" ");
+ }
+ }
+}
+
+void SQLiteVacuum::processExited()
+{
+// KexiDBDrvDbg << sender()->name() << " EXIT" << endl;
+ m_dlg->close();
+ delete m_dlg;
+ m_dlg = 0;
+}
+
+void SQLiteVacuum::cancelClicked()
+{
+ if (!m_process->normalExit()) {
+ m_process->writeToStdin("q"); //quit
+ m_result = cancelled;
+ }
+}
+
+#include "sqlitevacuum.moc"
diff --git a/kexi/kexidb/drivers/sqlite/sqlitevacuum.h b/kexi/kexidb/drivers/sqlite/sqlitevacuum.h
new file mode 100644
index 00000000..4424b7fc
--- /dev/null
+++ b/kexi/kexidb/drivers/sqlite/sqlitevacuum.h
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SQLITE_VACUUM_H
+#define SQLITE_VACUUM_H
+
+#include <qobject.h>
+#include <qstring.h>
+
+#include <kexiutils/tristate.h>
+
+class QProcess;
+class KTempFile;
+class KProgressDialog;
+
+//! @short Helper class performing interactive compacting (VACUUM) of the SQLite database
+/*! Proved SQLite database filename in the constructor.
+ Then execute run() should be executed.
+
+ KProgressDialog will be displayed. Its progress bar will be updated whenever another
+ table's data compacting is performed. User can click "Cancel" button in any time
+ (except the final committing) to cancel the operation. In this case,
+ it's guaranteed that the original file remains unchanged.
+
+ This is possible because we rely on SQLite's VACUUM SQL command, which itself temporarily
+ creates a copy of the original database file, and replaces the orginal with the new only
+ on success.
+*/
+class SQLiteVacuum : public QObject
+{
+ Q_OBJECT
+ public:
+ SQLiteVacuum(const QString& filePath);
+ ~SQLiteVacuum();
+
+ /*! Performs compacting procedure.
+ \return true on success, false on failure and cancelled if user
+ clicked "Cancel" button in the progress dialog. */
+ tristate run();
+
+ public slots:
+ void readFromStdout();
+ void processExited();
+ void cancelClicked();
+
+ protected:
+ QString m_filePath;
+ QProcess *m_process;
+ KProgressDialog* m_dlg;
+ int m_percent;
+ tristate m_result;
+};
+
+#endif