diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/migration/pqxx | |
download | koffice-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/migration/pqxx')
-rw-r--r-- | kexi/migration/pqxx/Makefile.am | 20 | ||||
-rw-r--r-- | kexi/migration/pqxx/keximigrate_pqxx.desktop | 53 | ||||
-rw-r--r-- | kexi/migration/pqxx/pg_type.h | 192 | ||||
-rw-r--r-- | kexi/migration/pqxx/pqxxmigrate.cpp | 660 | ||||
-rw-r--r-- | kexi/migration/pqxx/pqxxmigrate.h | 120 |
5 files changed, 1045 insertions, 0 deletions
diff --git a/kexi/migration/pqxx/Makefile.am b/kexi/migration/pqxx/Makefile.am new file mode 100644 index 00000000..d49027f1 --- /dev/null +++ b/kexi/migration/pqxx/Makefile.am @@ -0,0 +1,20 @@ +include $(top_srcdir)/kexi/Makefile.global + +kde_module_LTLIBRARIES = keximigrate_pqxx.la + +INCLUDES = -I$(srcdir)/../../.. -I$(top_srcdir)/kexi $(all_includes) -I$(PG_INCDIR) -I$(PQXX_INCDIR) + +keximigrate_pqxx_la_METASOURCES = AUTO + +keximigrate_pqxx_la_SOURCES = pqxxmigrate.cpp + +#TODO share -libs with pqxx kexidb drv! +#keximigrate_pqxx_la_LIBADD = $(LIB_KPARTS) $(LIB_QT) -lcom_err -lkrb5 -lssl -lcrypto -lcrypt -lpqxx ../libkeximigrate.la +keximigrate_pqxx_la_LIBADD = $(LIB_KPARTS) $(LIB_QT) -lpqxx ../libkeximigrate.la + +keximigrate_pqxx_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) -L$(PQXX_LIBDIR) -L$(PG_LIBDIR) $(VER_INFO) -no-undefined + +kde_services_DATA = keximigrate_pqxx.desktop + +noinst_HEADERS = pqxxmigrate.h pg_type.h + diff --git a/kexi/migration/pqxx/keximigrate_pqxx.desktop b/kexi/migration/pqxx/keximigrate_pqxx.desktop new file mode 100644 index 00000000..3f88cbef --- /dev/null +++ b/kexi/migration/pqxx/keximigrate_pqxx.desktop @@ -0,0 +1,53 @@ +[Desktop Entry] +Name=PostgreSQL +Name[hi]=पोस्टग्रे-एसक्यूएल +Name[ne]=पोस्ट ग्रे एसक्यूएल +Comment=PostgreSQL Migration Driver for Kexi +Comment[bg]=Драйвер за мигриране от PostgreSQL към Kexi +Comment[ca]=Controlador de migració de PostgreSQL per a Kexi +Comment[cy]=Gyrrydd Mudo PostgreSQL ar gyfer Kexi +Comment[da]=PostgreSQL Migrationsdriver for Kexi +Comment[de]=PostgreSQL-Migrationstreiber für Kexi +Comment[el]=Οδηγός μεταφοράς PostgreSQL του Kexi +Comment[eo]=PostgreSQL-migrada pelilo por Kexi +Comment[es]=Controlador de migración a PostgreSQL para Kexi +Comment[et]=Kexi PostgreSQL migreerumisdraiver +Comment[eu]=Kexi-ren PostgreSQL migraziorako kontrolatzailea +Comment[fa]=گردانندۀ جابهجایی PostgreSQL برای Kexi +Comment[fi]=PostgreSQL yhdistämisajuri Kexille +Comment[fr]=Pilote de migration PostgreSQL pour Kexi +Comment[fy]=PostgreSQL-Migraasjestjoerprogramma foar Kexi +Comment[gl]=Controlador de Migración de PostgreSQL de Kexi +Comment[hr]=PostgreSQL upravljački program migracije podataka za Kexi +Comment[hu]=Kexi PostgreSQL-migrálási meghajtó +Comment[is]=PostgreSQL gagnaflutngingsrekill fyrir Kexi +Comment[it]=Driver di migrazione PostgreSQL per Kexi +Comment[ja]=Kexi PostgreSQL データ移行ドライバ +Comment[km]=កម្មវិធីបញ្ជាសម្រាប់ផ្លាស់ប្ដូរ PostgreSQL សម្រាប់ Kexi +Comment[lv]=PostgreSQL datu migrācijas draiveris priekš Kexi +Comment[nb]=Kexi-programmodul for migrering av MySQL-drivere +Comment[nds]=PostgreSQL-Datenutlagerndriever för Kexi +Comment[ne]=केक्सीका लागि पोस्टग्रेसSQL मापग्रेसन ड्राइभर +Comment[nl]=PostgreSQL-migratiestuurprogramma voor Kexi +Comment[nn]=Kexi-programmodul for migrering av MySQL-drivarar +Comment[pl]=Wtyczka migracji danych z serwera PostgreSQL dla Kexi +Comment[pt]=Controlador de Migração de PostgreSQL do Kexi +Comment[pt_BR]=Driver de Migração do PostgreSQL para o Kexi +Comment[ru]=Драйвер миграции PostrgeSQL для Kexi +Comment[sk]=Ovládač PostgreSQL Migration pre Kexi +Comment[sl]=Gonilnik PostgreSQL za prenos podatkov za Kexi +Comment[sr]=Драјвер Kexi-ја за миграцију са PostgreSQL-а +Comment[sr@Latn]=Drajver Kexi-ja za migraciju sa PostgreSQL-a +Comment[sv]=PostgreSQL-övergångsdrivrutin för Kexi +Comment[uk]=PostgreSQL драйвер міграції даних для Kexi +Comment[uz]=Kexi uchun PostgreSQL migratsiya drayveri +Comment[uz@cyrillic]=Kexi учун PostgreSQL миграция драйвери +Comment[zh_CN]=Kexi PostgreSQL 升迁驱动程序 +Comment[zh_TW]=Kexi 的 PostgreSQL 轉移驅動程式 +X-KDE-Library=keximigrate_pqxx +ServiceTypes=Kexi/MigrationDriver +Type=Service +InitialPreference=8 +X-Kexi-MigrationDriverName=PostgreSQL +X-Kexi-MigrationDriverType=Network +X-Kexi-KexiMigrationVersion=1.1 diff --git a/kexi/migration/pqxx/pg_type.h b/kexi/migration/pqxx/pg_type.h new file mode 100644 index 00000000..e0ead91a --- /dev/null +++ b/kexi/migration/pqxx/pg_type.h @@ -0,0 +1,192 @@ +// +// +// C++ Interface: pg_type +// +// Description: +// +// +// Author: Adam Pigg <adam@piggz.fsnet.co.uk>, (C) 2003 +// +// Copyright: See COPYING file that comes with this distribution +// +// +//boolean, 'true'/'false' +#define BOOLOID 16 + +//Unknown Type +#define UNKNOWNOID 705 + +//Numberic Types +//============== + +//~18 digit integer, 8-byte storage +#define INT8OID 20 + +//-32 thousand to 32 thousand, 2-byte storage +#define INT2OID 21 + +//array of INDEX_MAX_KEYS int2 integers, used in system tables +#define INT2VECTOROID 22 + +//-2 billion to 2 billion integer, 4-byte storage +#define INT4OID 23 + +//single-precision floating point number, 4-byte storage +#define FLOAT4OID 700 + +//double-precision floating point number, 8-byte storage +#define FLOAT8OID 701 + +//monetary amounts, $d,ddd.cc +#define CASHOID 790 + +//numeric(precision, decimal), arbitrary precision number +#define NUMERICOID 1700 + +//================================== + +//Text Types +//========== +//variable-length string, binary values escaped +#define BYTEAOID 17 + +//single character +#define CHAROID 18 + +//variable-length string, no limit specified +#define TEXTOID 25 + +//char(length), blank-padded string, fixed storage length +#define BPCHAROID 1042 + +//varchar(length), non-blank-padded string, variable storage length +#define VARCHAROID 1043 + +//fixed-length bit string +#define BITOID 1560 + +//variable-length bit string +#define VARBITOID 1562 + +//================================== + +//Date Time Types +//=============== +//absolute, limited-range date and time (Unix system time) +#define ABSTIMEOID 702 + +//relative, limited-range time interval (Unix delta time) +#define RELTIMEOID 703 + +//(abstime,abstime), time interval +#define TINTERVALOID 704 + +//ANSI SQL date +#define DATEOID 1082 + +//hh:mm:ss, ANSI SQL time +#define TIMEOID 1083 + +//date and time +#define TIMESTAMPOID 1114 + +//date and time with time zone +#define TIMESTAMPTZOID 1184 + +//@ <number> <units>, time interval +#define INTERVALOID 1186 + +//hh:mm:ss, ANSI SQL time +#define TIMETZOID 1266 + + +//================================== + +//Internal OID Types +//================== +//object identifier(oid), maximum 4 billion +#define OIDOID 26 + +//(Block, offset), physical location of tuple +#define TIDOID 27 + +//transaction id +#define XIDOID 28 + +//command identifier type, sequence in transaction id +#define CIDOID 29 + +//array of INDEX_MAX_KEYS oids, used in system tables +#define OIDVECTOROID 30 + + +//================================== + +//Geometric Types +//=============== +//geometric point '(x, y)' +#define POINTOID 600 + +//geometric line segment '(pt1,pt2)' +#define LSEGOID 601 + +//geometric path '(pt1,...)' +#define PATHOID 602 + +//geometric box '(lower left,upper right)' +#define BOXOID 603 + +//geometric polygon '(pt1,...)' +#define POLYGONOID 604 + +//geometric line (not implemented)' +#define LINEOID 628 + +//geometric circle '(center,radius)' +#define CIRCLEOID 718 + +//================================== + +//Network Types +//============= +//XX:XX:XX:XX:XX:XX, MAC address +#define MACADDROID 829 + +//IP address/netmask, host address, netmask optional +#define INETOID 869 + +//network IP address/netmask, network address +#define CIDROID 650 + +//access control list +#define ACLITEMOID 1033 + + +//================================== + +//Miscellaneous Types +//=================== +//63-character type for storing system identifiers +#define NAMEOID 19 + +//registered procedure +#define REGPROCOID 24 + +//reference cursor (portal name) +#define REFCURSOROID 1790 + +//registered procedure (with args) +#define REGPROCEDUREOID 2202 + +//registered operator +#define REGOPEROID 2203 + +//registered operator (with args) +#define REGOPERATOROID 2204 + +//registered class +#define REGCLASSOID 2205 + +//registered type +#define REGTYPEOID 2206 + diff --git a/kexi/migration/pqxx/pqxxmigrate.cpp b/kexi/migration/pqxx/pqxxmigrate.cpp new file mode 100644 index 00000000..15715897 --- /dev/null +++ b/kexi/migration/pqxx/pqxxmigrate.cpp @@ -0,0 +1,660 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Adam Pigg <adam@piggz.co.uk> + 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. +*/ + +#include "pqxxmigrate.h" +#include "pg_type.h" + +#include <qstring.h> +#include <kdebug.h> +#include <qstringlist.h> + +//I maybe should not use stl? +#include <string> +#include <vector> + +#include <kexidb/cursor.h> +#include <kexidb/utils.h> +#include <kexidb/drivermanager.h> +#include <kexiutils/identifier.h> +#include <kexidb/drivers/pqxx/pqxxcursor.h> //for pgsqlCStrToVariant() + +using namespace KexiDB; +using namespace KexiMigration; + +/* +This is the implementation for the pqxx specific import routines +Thi is currently pre alpha and in no way is it meant +to compile, let alone work. This is meant as an example of +what the system might be and is a work in progress +*/ + +KEXIMIGRATE_DRIVER_INFO( PqxxMigrate, pqxx ) + +//================================================================================== +//Constructor +/*PqxxMigrate::PqxxMigrate() + : KexiMigrate(parent, name, args) +{ + m_res=0; + m_trans=0; + m_conn=0; +}*/ + +PqxxMigrate::PqxxMigrate(QObject *parent, const char *name, const QStringList &args) + : KexiMigrate(parent, name, args) +{ + m_res=0; + m_trans=0; + m_conn=0; + KexiDB::DriverManager manager; + m_kexiDBDriver = manager.driver("pqxx"); +} +//================================================================================== +//Destructor +PqxxMigrate::~PqxxMigrate() +{ + clearResultInfo(); +} + +//================================================================================== +//This is probably going to be quite complex...need to get the types for all columns +//any any other attributes required by kexi +//helped by reading the 'tables' test program +bool PqxxMigrate::drv_readTableSchema( + const QString& originalName, KexiDB::TableSchema& tableSchema) +{ +// m_table = new KexiDB::TableSchema(table); + + //TODO IDEA: ask for user input for captions +//moved m_table->setCaption(table + " table"); + + //Perform a query on the table to get some data + if (query("select * from \"" + originalName + "\" limit 1")) + { + //Loop round the fields + for (uint i = 0; i < (uint)m_res->columns(); i++) + { + QString fldName(m_res->column_name(i)); + KexiDB::Field::Type fldType = type(m_res->column_type(i), fldName); + QString fldID( KexiUtils::string2Identifier(fldName) ); + const pqxx::oid toid = tableOid(originalName); + if (toid==0) + return false; + KexiDB::Field *f = new KexiDB::Field(fldID, fldType); + f->setCaption(fldName); + f->setPrimaryKey(primaryKey(toid, i)); + f->setUniqueKey(uniqueKey(toid, i)); + f->setAutoIncrement(autoInc(toid, i));//This should be safe for all field types + tableSchema.addField(f); + + // Do this for var/char types + //m_f->setLength(m_res->at(0)[i].size()); + + // Do this for numeric type + /*m_f->setScale(0); + m_f->setPrecision(0);*/ + + kdDebug() << "Added field [" << f->name() << "] type [" << f->typeName() + << "]" << endl; + } + return true; + } + else + { + return false; + } +} + +//================================================================================== +//get a list of tables and put into the supplied string list +bool PqxxMigrate::drv_tableNames(QStringList& tableNames) +{ + /* + //pg_ = standard postgresql tables, pga_ = tables added by pgaccess, sql_ = probably information schemas, kexi__ = existing kexi tables + if (query("SELECT relname FROM pg_class WHERE ((relkind = 'r') AND ((relname !~ '^pg_') AND (relname !~ '^pga_') AND (relname !~ '^sql_') AND (relname !~ '^kexi__')))")) + */ + if (query("SELECT relname FROM pg_class WHERE ((relkind = 'r') AND ((relname !~ '^pg_') AND (relname !~ '^pga_') AND (relname !~ '^sql_')))")) + { + for (pqxx::result::const_iterator c = m_res->begin(); c != m_res->end(); ++c) + { + // Copy the result into the return list + tableNames << QString::fromLatin1 (c[0].c_str()); + } + return true; + } + else + { + return false; + } +} + +//================================================================================== +//Convert a postgresql type to a kexi type +KexiDB::Field::Type PqxxMigrate::type(int t, const QString& fname) +{ + switch(t) + { + case UNKNOWNOID: + return KexiDB::Field::InvalidType; + case BOOLOID: + return KexiDB::Field::Boolean; + case INT2OID: + return KexiDB::Field::ShortInteger; + case INT4OID: + return KexiDB::Field::Integer; + case INT8OID: + return KexiDB::Field::BigInteger; + case FLOAT4OID: + return KexiDB::Field::Float; + case FLOAT8OID: + return KexiDB::Field::Double; + case NUMERICOID: + return KexiDB::Field::Double; + case DATEOID: + return KexiDB::Field::Date; + case TIMEOID: + return KexiDB::Field::Time; + case TIMESTAMPOID: + return KexiDB::Field::DateTime; + case BYTEAOID: + return KexiDB::Field::BLOB; + case BPCHAROID: + return KexiDB::Field::Text; + case VARCHAROID: + return KexiDB::Field::Text; + case TEXTOID: + return KexiDB::Field::LongText; + } + + //Ask the user what to do with this field + return userType(fname); +} + +//================================================================================== +//Connect to the db backend +bool PqxxMigrate::drv_connect() +{ + kdDebug() << "drv_connect: " << m_migrateData->sourceName << endl; + + QString conninfo; + QString socket; + + //Setup local/remote connection + if (m_migrateData->source->hostName.isEmpty()) + { + if (m_migrateData->source->fileName().isEmpty()) + { + socket="/tmp/.s.PGSQL.5432"; + } + else + { + socket=m_migrateData->source->fileName(); + } + } + else + { + conninfo = "host='" + m_migrateData->source->hostName + "'"; + } + + //Build up the connection string + if (m_migrateData->source->port == 0) + m_migrateData->source->port = 5432; + + conninfo += QString::fromLatin1(" port='%1'").arg(m_migrateData->source->port); + + conninfo += QString::fromLatin1(" dbname='%1'").arg(m_migrateData->sourceName); + + if (!m_migrateData->source->userName.isNull()) + conninfo += QString::fromLatin1(" user='%1'").arg(m_migrateData->source->userName); + + if (!m_migrateData->source->password.isNull()) + conninfo += QString::fromLatin1(" password='%1'").arg(m_migrateData->source->password); + + try + { + m_conn = new pqxx::connection( conninfo.latin1() ); + return true; + } + catch(const std::exception &e) + { + kdDebug() << "PqxxMigrate::drv_connect:exception - " << e.what() << endl; + } + catch(...) + { + kdDebug() << "PqxxMigrate::drv_connect:exception(...)??" << endl; + } + return false; +} + +//================================================================================== +//Connect to the db backend +bool PqxxMigrate::drv_disconnect() +{ + if (m_conn) + { + m_conn->disconnect(); + delete m_conn; + m_conn = 0; + } + return true; +} +//================================================================================== +//Perform a query on the database and store result in m_res +bool PqxxMigrate::query(const QString& statement) +{ + kdDebug() << "query: " << statement.latin1() << endl; + + Q_ASSERT (m_conn); + + // Clear the last result information... + clearResultInfo (); + + try + { + //Create a transaction + m_trans = new pqxx::nontransaction(*m_conn); + //Create a result opject through the transaction + m_res = new pqxx::result(m_trans->exec(statement.latin1())); + //Commit the transaction + m_trans->commit(); + //If all went well then return true, errors picked up by the catch block + return true; + } + catch (const std::exception &e) + { + //If an error ocurred then put the error description into _dbError + kdDebug() << "pqxxImport::query:exception - " << e.what() << endl; + return false; + } + catch(...) + { + kdDebug() << "PqxxMigrate::query:exception(...)??" << endl; + } + return true; +} + +//========================================================================= +//Clears the current result +void PqxxMigrate::clearResultInfo() +{ + delete m_res; + m_res = 0; + + delete m_trans; + m_trans = 0; +} + +//========================================================================= +//Return the OID for a table +pqxx::oid PqxxMigrate::tableOid(const QString& table) +{ + QString statement; + static QString otable; + static pqxx::oid toid; + + pqxx::nontransaction* tran = 0; + pqxx::result* tmpres = 0; + + //Some simple result caching + if (table == otable) + { + kdDebug() << "Returning table OID from cache..." << endl; + return toid; + } + else + { + otable = table; + } + + try + { + statement = "SELECT relfilenode FROM pg_class WHERE (relname = '"; + statement += table; + statement += "')"; + + tran = new pqxx::nontransaction(*m_conn, "find_t_oid"); + tmpres = new pqxx::result(tran->exec(statement.latin1())); + + tran->commit(); + if (tmpres->size() > 0) + { + //We have a key field for this table, lets check if its this column + tmpres->at(0).at(0).to(toid); + } + else + { + toid = 0; + } + } + catch(const std::exception &e) + { + kdDebug() << "pqxxSqlDB::tableOid:exception - " << e.what() << endl; + kdDebug() << "pqxxSqlDB::tableOid:failed statement - " << statement << endl; + toid = 0; + } + catch(...) + { + kdDebug() << "PqxxMigrate::tableOid:exception(...)??" << endl; + } + delete tmpres; + tmpres = 0; + + delete tran; + tran = 0; + + kdDebug() << "OID for table [" << table << "] is [" << toid << "]" << endl; + return toid; +} + +//========================================================================= +//Return whether or not the curent field is a primary key +//TODO: Add result caching for speed +bool PqxxMigrate::primaryKey(pqxx::oid table_uid, int col) const +{ + QString statement; + bool pkey; + int keyf; + + pqxx::nontransaction* tran = 0; + pqxx::result* tmpres = 0; + + try + { + statement = QString("SELECT indkey FROM pg_index WHERE ((indisprimary = true) AND (indrelid = %1))").arg(table_uid); + + tran = new pqxx::nontransaction(*m_conn, "find_pkey"); + tmpres = new pqxx::result(tran->exec(statement.latin1())); + + tran->commit(); + if (tmpres->size() > 0) + { + //We have a key field for this table, lets check if its this column + tmpres->at(0).at(0).to(keyf); + if (keyf-1 == col) //-1 because pg counts from 1 and we count from 0 + { + pkey = true; + kdDebug() << "Field is pkey" << endl; + } + else + { + pkey = false; + kdDebug() << "Field is NOT pkey" << endl; + } + } + else + { + pkey = false; + kdDebug() << "Field is NOT pkey" << endl; + } + } + catch(const std::exception &e) + { + kdDebug() << "pqxxSqlDB::primaryKey:exception - " << e.what() << endl; + kdDebug() << "pqxxSqlDB::primaryKey:failed statement - " << statement << endl; + pkey = false; + } + delete tmpres; + tmpres = 0; + + delete tran; + tran = 0; + + return pkey; +} + +//========================================================================= +/*! Fetches single string at column \a columnNumber from result obtained + by running \a sqlStatement. + On success the result is stored in \a string and true is returned. + \return cancelled if there are no records available. */ +tristate PqxxMigrate::drv_queryStringListFromSQL( + const QString& sqlStatement, uint columnNumber, QStringList& stringList, int numRecords) +{ + std::string result; + int i = 0; + if (query(sqlStatement)) + { + for (pqxx::result::const_iterator it = m_res->begin(); + it != m_res->end() && (numRecords == -1 || i < numRecords); ++it, i++) + { + if (it.size() > 0 && it.size() > columnNumber) { + it.at(columnNumber).to(result); + stringList.append( QString::fromUtf8(result.c_str()) ); + } + else { + clearResultInfo(); + return cancelled; + } + } + } + else + return false; + clearResultInfo(); +/* delete tmpres; + tmpres = 0; + + delete tran; + tran = 0;*/ + + if (i < numRecords) + return cancelled; + + return true; + /* + if (d->executeSQL(sqlStatement)) { + MYSQL_RES *res = mysql_use_result(d->mysql); + if (res != NULL) { + MYSQL_ROW row = mysql_fetch_row(res); + if (!row) { + tristate r = mysql_errno(d->mysql) ? false : cancelled; + mysql_free_result(res); + return r; + } + uint numFields = mysql_num_fields(res); + if (columnNumber > (numFields-1)) { + kdWarning() << "PqxxMigrate::drv_querySingleStringFromSQL("<<sqlStatement + << "): columnNumber too large (" + << columnNumber << "), expected 0.." << numFields << endl; + mysql_free_result(res); + return false; + } + unsigned long *lengths = mysql_fetch_lengths(res); + if (!lengths) { + mysql_free_result(res); + return false; + } + string = QString::fromLatin1(row[columnNumber], lengths[columnNumber]); + mysql_free_result(res); + } else { + kdDebug() << "PqxxMigrate::drv_querySingleStringFromSQL(): null result" << endl; + } + return true; + } else { + return false; + }*/ +} + +tristate PqxxMigrate::drv_fetchRecordFromSQL(const QString& sqlStatement, + KexiDB::RowData& data, bool &firstRecord) +{ + if (firstRecord || !m_res) { + if (m_res) + clearResultInfo(); + if (!query(sqlStatement)) + return false; + m_fetchRecordFromSQL_iter = m_res->begin(); + firstRecord = false; + } + else + ++m_fetchRecordFromSQL_iter; + + if (m_fetchRecordFromSQL_iter == m_res->end()) { + clearResultInfo(); + return cancelled; + } + + std::string result; + const int numFields = m_fetchRecordFromSQL_iter.size(); + data.resize(numFields); + for (int i=0; i < numFields; i++) + data[i] = KexiDB::pgsqlCStrToVariant(m_fetchRecordFromSQL_iter.at(i)); + return true; +} + +//========================================================================= +/*! Copy PostgreSQL table to KexiDB database */ +bool PqxxMigrate::drv_copyTable(const QString& srcTable, KexiDB::Connection *destConn, + KexiDB::TableSchema* dstTable) +{ + std::vector<std::string> R; + + pqxx::work T(*m_conn, "PqxxMigrate::drv_copyTable"); + + pqxx::tablereader stream(T, (srcTable.latin1())); + + //Loop round each row, reading into a vector of strings + const KexiDB::QueryColumnInfo::Vector fieldsExpanded( dstTable->query()->fieldsExpanded() ); + for (int n=0; (stream >> R); ++n) + { + QValueList<QVariant> vals; + std::vector<std::string>::const_iterator i, end( R.end() ); + int index = 0; + for ( i = R.begin(); i != end; ++i, index++) { + if (fieldsExpanded.at(index)->field->type()==KexiDB::Field::BLOB || fieldsExpanded.at(index)->field->type()==KexiDB::Field::LongText) + vals.append( KexiDB::pgsqlByteaToByteArray((*i).c_str(), (*i).size()) ); + else + vals.append( KexiDB::cstringToVariant((*i).c_str(), + fieldsExpanded.at(index)->field, (*i).size()) ); + } + if (!destConn->insertRecord(*dstTable, vals)) + return false; + updateProgress(); + R.clear(); + } + + //This does not work in <libpqxx 2.2 + //stream.complete(); + + return true; +} + +//========================================================================= +//Return whether or not the curent field is a primary key +//TODO: Add result caching for speed +bool PqxxMigrate::uniqueKey(pqxx::oid table_uid, int col) const +{ + QString statement; + bool ukey; + int keyf; + + pqxx::nontransaction* tran = 0; + pqxx::result* tmpres = 0; + + try + { + statement = QString("SELECT indkey FROM pg_index WHERE ((indisunique = true) AND (indrelid = %1))").arg(table_uid); + + tran = new pqxx::nontransaction(*m_conn, "find_ukey"); + tmpres = new pqxx::result(tran->exec(statement.latin1())); + + tran->commit(); + if (tmpres->size() > 0) + { + //We have a key field for this table, lets check if its this column + tmpres->at(0).at(0).to(keyf); + if (keyf-1 == col) //-1 because pg counts from 1 and we count from 0 + { + ukey = true; + kdDebug() << "Field is unique" << endl; + } + else + { + ukey = false; + kdDebug() << "Field is NOT unique" << endl; + } + } + else + { + ukey = false; + kdDebug() << "Field is NOT unique" << endl; + } + } + catch(const std::exception &e) + { + kdDebug() << "uniqueKey:exception - " << e.what() << endl; + kdDebug() << "uniqueKey:failed statement - " << statement << endl; + ukey = false; + } + + delete tmpres; + tmpres = 0; + + delete tran; + tran = 0; + + return ukey; +} + +//================================================================================== +//TODO::Implement +bool PqxxMigrate::autoInc(pqxx::oid /*table_uid*/, int /*col*/) const +{ + return false; +} + +//================================================================================== +//TODO::Implement +bool PqxxMigrate::notNull(pqxx::oid /*table_uid*/, int /*col*/) const +{ + return false; +} + +//================================================================================== +//TODO::Implement +bool PqxxMigrate::notEmpty(pqxx::oid /*table_uid*/, int /*col*/) const +{ + return false; +} + +//================================================================================== +//Return a list of database names +/*bool PqxxMigrate::drv_getDatabasesList( QStringList &list ) +{ + KexiDBDrvDbg << "pqxxSqlConnection::drv_getDatabaseList" << endl; + + if (executeSQL("SELECT datname FROM pg_database WHERE datallowconn = TRUE")) + { + std::string N; + for (pqxx::result::const_iterator c = m_res->begin(); c != m_res->end(); ++c) + { + // Read value of column 0 into a string N + c[0].to(N); + // Copy the result into the return list + list << QString::fromLatin1 (N.c_str()); + KexiDBDrvDbg << N.c_str() << endl; + } + return true; + } + + return false; +}*/ + + +#include "pqxxmigrate.moc" diff --git a/kexi/migration/pqxx/pqxxmigrate.h b/kexi/migration/pqxx/pqxxmigrate.h new file mode 100644 index 00000000..c09c8a7a --- /dev/null +++ b/kexi/migration/pqxx/pqxxmigrate.h @@ -0,0 +1,120 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Adam Pigg <adam@piggz.co.uk> + 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. +*/ + +#ifndef PQXXIMPORT_H +#define PQXXIMPORT_H + +#include <migration/keximigrate.h> + +//Kexi Includes +#include <kexidb/field.h> +#include <kexidb/connection.h> + +#include <pqxx/pqxx> + +namespace KexiMigration +{ + class PqxxMigrate : public KexiMigrate + { + Q_OBJECT + KEXIMIGRATION_DRIVER + + public: + PqxxMigrate(QObject *parent, const char *name, const QStringList &args = QStringList()); + virtual ~PqxxMigrate(); + + protected: + //Driver specific function to return table names + virtual bool drv_tableNames(QStringList& tablenames); + + //Driver specific implementation to read a table schema + virtual bool drv_readTableSchema( + const QString& originalName, KexiDB::TableSchema& tableSchema); + + //Driver specific connection implementation + virtual bool drv_connect(); + virtual bool drv_disconnect(); + + virtual tristate drv_queryStringListFromSQL( + const QString& sqlStatement, uint columnNumber, QStringList& stringList, + int numRecords = -1); + + /*! Fetches single record from result obtained + by running \a sqlStatement. + \a firstRecord should be first initialized to true, so the method can run + the query at first call and then set it will set \a firstRecord to false, + so subsequent calls will only fetch records. + On success the result is stored in \a data and true is returned, + \a data is resized to appropriate size. cancelled is returned on EOF. */ +//! @todo SQL-dependent! + virtual tristate drv_fetchRecordFromSQL(const QString& sqlStatement, + KexiDB::RowData& data, bool &firstRecord); + + virtual bool drv_copyTable(const QString& srcTable, + KexiDB::Connection *destConn, KexiDB::TableSchema* dstTable); + + private: + //lowlevel functions/objects + //database connection + pqxx::connection* m_conn; + + //transaction + pqxx::nontransaction* m_trans; + + //lowlevel result + pqxx::result* m_res; + + //! Used in drv_fetchRecordFromSQL + pqxx::result::const_iterator m_fetchRecordFromSQL_iter; + + //perform a query on the database + bool query(const QString& statement); + + //Clear the result info + void clearResultInfo (); + + pqxx::oid tableOid(const QString& tablename); + + //Convert the pqxx type to a kexi type + KexiDB::Field::Type type(int t, const QString& fname); + + //Find out the field constraints + //Return whether or not the field is a pkey + bool primaryKey(pqxx::oid table, int col) const; + + //Return whether or not the field is unique + bool uniqueKey(pqxx::oid table, int col) const; + + //Return whether or not the field is a foreign key + bool foreignKey(pqxx::oid table, int col) const; + + //Return whether or not the field is not null + bool notNull(pqxx::oid table, int col) const; + + //Return whether or not the field is not empty + bool notEmpty(pqxx::oid table, int col) const; + + //Return whether or not the field is auto incrementing + bool autoInc(pqxx::oid table, int col) const; + + }; +} + +#endif |