summaryrefslogtreecommitdiffstats
path: root/kexi/migration/pqxx
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/migration/pqxx
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/migration/pqxx')
-rw-r--r--kexi/migration/pqxx/Makefile.am20
-rw-r--r--kexi/migration/pqxx/keximigrate_pqxx.desktop53
-rw-r--r--kexi/migration/pqxx/pg_type.h192
-rw-r--r--kexi/migration/pqxx/pqxxmigrate.cpp660
-rw-r--r--kexi/migration/pqxx/pqxxmigrate.h120
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