[QGIS Commit] r8213 - in trunk/qgis/src: app core providers/postgres
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Wed Mar 12 17:02:40 EDT 2008
Author: jef
Date: 2008-03-12 17:02:40 -0400 (Wed, 12 Mar 2008)
New Revision: 8213
Modified:
trunk/qgis/src/app/qgsdbsourceselect.cpp
trunk/qgis/src/app/qgsnewconnection.cpp
trunk/qgis/src/app/qgspgquerybuilder.cpp
trunk/qgis/src/core/qgsdatasourceuri.cpp
trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp
trunk/qgis/src/providers/postgres/qgspostgresprovider.h
Log:
- applied patch from Steven Mizuno from #964. Nice work. Thank you very much.
- better privilege handling (fixes #955)
- better postgis i18n (unicode handling, identifier quotation)
- password saving fixed
- support for int8 type added
- let provider capabilities follow table privileges (fixes #976)
- use prepared statements for adding features (fixed #977)
- remove connection pooling (fixes cursor problem)
- clear attribute list on loadFields (fixes #984)
- ignore bytea fields
- handle transactions/error reporting better
- some cleanups
Modified: trunk/qgis/src/app/qgsdbsourceselect.cpp
===================================================================
--- trunk/qgis/src/app/qgsdbsourceselect.cpp 2008-03-12 20:44:31 UTC (rev 8212)
+++ trunk/qgis/src/app/qgsdbsourceselect.cpp 2008-03-12 21:02:40 UTC (rev 8213)
@@ -181,7 +181,7 @@
" when geometrytype(%1) IN ('LINESTRING','MULTILINESTRING') THEN 'LINESTRING'"
" when geometrytype(%1) IN ('POLYGON','MULTIPOLYGON') THEN 'POLYGON'"
" end "
- "from \"%2\".\"%3\"").arg(column).arg(schema).arg(table);
+ "from \"%2\".\"%3\"").arg("\""+column+"\"").arg(schema).arg(table);
}
QgsDbSourceSelect::~QgsDbSourceSelect()
@@ -361,11 +361,11 @@
QString username = settings.readEntry(key + "/username");
QString password = settings.readEntry(key + "/password");
- if (password == QString::null)
+ if ( password.isEmpty() )
{
// get password from user
makeConnection = false;
- QString password = QInputDialog::getText(tr("Password for ") + username,
+ password = QInputDialog::getText(tr("Password for ") + username,
tr("Please enter your password:"),
QLineEdit::Password, QString::null, &makeConnection, this);
// allow null password entry in case its valid for the database
@@ -393,13 +393,13 @@
if (pd != 0)
PQfinish(pd);
- pd = PQconnectdb(m_connInfo.toLocal8Bit().data());
+ pd = PQconnectdb(m_connInfo.toLocal8Bit()); // use what is set based on locale; after connecting, use Utf8
// std::cout << pd->ErrorMessage();
if (PQstatus(pd) == CONNECTION_OK)
{
//qDebug("Connection succeeded");
// tell the DB that we want text encoded in UTF8
- PQsetClientEncoding(pd, "UNICODE");
+ PQsetClientEncoding(pd, QString("UNICODE").toLocal8Bit());
// get the list of suitable tables and columns and populate the UI
geomCol details;
@@ -434,7 +434,7 @@
QMessageBox::warning(this, tr("Connection failed"),
tr
("Connection to %1 on %2 failed. Either the database is down or your settings are incorrect.%3Check your username and password and try again.%4The database said:%5%6").
- arg(settings.readEntry(key + "/database")).arg(settings.readEntry(key + "/host")).arg("\n\n").arg("\n\n").arg("\n").arg(PQerrorMessage(pd)));
+ arg(settings.readEntry(key + "/database")).arg(settings.readEntry(key + "/host")).arg("\n\n").arg("\n\n").arg("\n").arg(QString::fromLocal8Bit(PQerrorMessage(pd))));
}
}
@@ -526,43 +526,33 @@
bool ok = false;
QApplication::setOverrideCursor(Qt::waitCursor);
- QString sql = "select * from geometry_columns";
- sql += " order by f_table_schema,f_table_name";
+ // The following query returns only tables that exist and the user has SELECT privilege on.
+ // Can't use regclass here because table must exist, else error occurs.
+ QString sql = "select * from geometry_columns,pg_class,pg_namespace "
+ "where relname=f_table_name and f_table_schema=nspname "
+ "and pg_namespace.oid = pg_class.relnamespace "
+ "and has_table_privilege('\"'||pg_namespace.nspname||'\".\"'||pg_class.relname||'\"','select')" // user has select privilege
+ "order by f_table_schema,f_table_name";
- PGresult *result = PQexec(pg, sql.toLocal8Bit().data());
+ PGresult *result = PQexec(pg, sql.toUtf8());
if (result)
{
for (int idx = 0; idx < PQntuples(result); idx++)
{
- // Be a bit paranoid and check that the table actually
- // exists. This is not done as a subquery in the query above
- // because I can't get it to work correctly when there are tables
- // with capital letters in the name.
+ QString tableName = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, QString("f_table_name").toUtf8())));
+ QString schemaName = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, QString("f_table_schema").toUtf8())));
- // Take care to deal with tables with the same name but in different schema.
- QString tableName = PQgetvalue(result, idx, PQfnumber(result, "f_table_name"));
- QString schemaName = PQgetvalue(result, idx, PQfnumber(result, "f_table_schema"));
- sql = "select oid from pg_class where relname = '" + tableName + "'";
- if (schemaName.length() > 0)
- sql +=" and relnamespace = (select oid from pg_namespace where nspname = '" +
- schemaName + "')";
+ QString column = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, QString("f_geometry_column").toUtf8())));
+ QString type = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, QString("type").toUtf8())));
- PGresult* exists = PQexec(pg, sql.toLocal8Bit().data());
- if (PQntuples(exists) == 1)
+ QString as = "";
+ if(type=="GEOMETRY" && !searchGeometryColumnsOnly)
{
- QString column = PQgetvalue(result, idx, PQfnumber(result, "f_geometry_column"));
- QString type = PQgetvalue(result, idx, PQfnumber(result, "type"));
-
- QString as = "";
- if(type=="GEOMETRY" && !searchGeometryColumnsOnly)
- {
- addSearchGeometryColumn(schemaName, tableName, column);
- as=type="WAITING";
- }
-
- mTableModel.addTableEntry(type, schemaName, tableName, column, "");
+ addSearchGeometryColumn(schemaName, tableName, column);
+ as=type="WAITING";
}
- PQclear(exists);
+
+ mTableModel.addTableEntry(type, schemaName, tableName, column, "");
}
ok = true;
}
@@ -581,20 +571,21 @@
// geometry_columns table. This code is specific to postgresql,
// but an equivalent query should be possible in other
// databases.
- sql = "select pg_class.relname, pg_namespace.nspname, pg_attribute.attname, "
- "pg_class.relkind from "
- "pg_attribute, pg_class, pg_type, pg_namespace where pg_type.typname = 'geometry' and "
- "pg_attribute.atttypid = pg_type.oid and pg_attribute.attrelid = pg_class.oid ";
-
+ sql = "select pg_class.relname, pg_namespace.nspname, pg_attribute.attname, pg_class.relkind "
+ "from pg_attribute, pg_class, pg_namespace "
+ "where pg_namespace.oid = pg_class.relnamespace "
+ "and pg_attribute.atttypid = regtype('geometry') "
+ "and pg_attribute.attrelid = pg_class.oid "
+ "and has_table_privilege('\"'||pg_namespace.nspname||'\".\"'||pg_class.relname||'\"','select') ";
+ // user has select privilege
if (searchPublicOnly)
sql += "and pg_namespace.nspname = 'public' ";
- sql += "and cast(pg_class.relname as character varying) not in "
- "(select f_table_name from geometry_columns) "
- "and pg_namespace.oid = pg_class.relnamespace "
+ sql += "and pg_namespace.nspname||'.'||pg_class.relname not in " // needs to be table and schema
+ "(select f_table_schema||'.'||f_table_name from geometry_columns) "
"and pg_class.relkind in ('v', 'r')"; // only from views and relations (tables)
- result = PQexec(pg, sql.toLocal8Bit().data());
+ result = PQexec(pg, sql.toUtf8());
for (int i = 0; i < PQntuples(result); i++)
{
@@ -605,10 +596,10 @@
// Make the assumption that the geometry type for the first
// row is the same as for all other rows.
- QString table = PQgetvalue(result, i, 0); // relname
- QString schema = PQgetvalue(result, i, 1); // nspname
- QString column = PQgetvalue(result, i, 2); // attname
- QString relkind = PQgetvalue(result, i, 3); // relation kind
+ QString table = QString::fromUtf8(PQgetvalue(result, i, 0)); // relname
+ QString schema = QString::fromUtf8(PQgetvalue(result, i, 1)); // nspname
+ QString column = QString::fromUtf8(PQgetvalue(result, i, 2)); // attname
+ QString relkind = QString::fromUtf8(PQgetvalue(result, i, 3)); // relation kind
addSearchGeometryColumn(schema, table, column);
//details.push_back(geomPair(fullDescription(schema, table, column, "WAITING"), "WAITING"));
@@ -620,6 +611,7 @@
return ok;
}
+#if 0 // this function is never called - smizuno
bool QgsDbSourceSelect::getGeometryColumnInfo(PGconn *pg,
geomCol& details, bool searchGeometryColumnsOnly,
bool searchPublicOnly)
@@ -632,7 +624,7 @@
// where f_table_schema ='" + settings.readEntry(key + "/database") + "'";
sql += " order by f_table_schema,f_table_name";
//qDebug("Fetching tables using: " + sql);
- PGresult *result = PQexec(pg, sql.toLocal8Bit().data());
+ PGresult *result = PQexec(pg, sql.toUtf8());
if (result)
{
QString msg;
@@ -646,18 +638,18 @@
// with capital letters in the name.
// Take care to deal with tables with the same name but in different schema.
- QString tableName = PQgetvalue(result, idx, PQfnumber(result, "f_table_name"));
- QString schemaName = PQgetvalue(result, idx, PQfnumber(result, "f_table_schema"));
+ QString tableName = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, "f_table_name")));
+ QString schemaName = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, "f_table_schema")));
sql = "select oid from pg_class where relname = '" + tableName + "'";
if (schemaName.length() > 0)
sql +=" and relnamespace = (select oid from pg_namespace where nspname = '" +
schemaName + "')";
- PGresult* exists = PQexec(pg, sql.toLocal8Bit().data());
+ PGresult* exists = PQexec(pg, sql.toUtf8());
if (PQntuples(exists) == 1)
{
- QString column = PQgetvalue(result, idx, PQfnumber(result, "f_geometry_column"));
- QString type = PQgetvalue(result, idx, PQfnumber(result, "type"));
+ QString column = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, "f_geometry_column")));
+ QString type = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, "type")));
QString as = "";
if(type=="GEOMETRY" && !searchGeometryColumnsOnly) {
@@ -695,7 +687,7 @@
"and pg_namespace.oid = pg_class.relnamespace "
"and pg_class.relkind in ('v', 'r')"; // only from views and relations (tables)
- result = PQexec(pg, sql.toLocal8Bit().data());
+ result = PQexec(pg, sql.toUtf8());
for (int i = 0; i < PQntuples(result); i++)
{
@@ -706,10 +698,10 @@
// Make the assumption that the geometry type for the first
// row is the same as for all other rows.
- QString table = PQgetvalue(result, i, 0); // relname
- QString schema = PQgetvalue(result, i, 1); // nspname
- QString column = PQgetvalue(result, i, 2); // attname
- QString relkind = PQgetvalue(result, i, 3); // relation kind
+ QString table = QString::fromUtf8(PQgetvalue(result, i, 0)); // relname
+ QString schema = QString::fromUtf8(PQgetvalue(result, i, 1)); // nspname
+ QString column = QString::fromUtf8(PQgetvalue(result, i, 2)); // attname
+ QString relkind = QString::fromUtf8(PQgetvalue(result, i, 3)); // relation kind
addSearchGeometryColumn(schema, table, column);
details.push_back(geomPair(fullDescription(schema, table, column, "WAITING"), "WAITING"));
@@ -720,6 +712,7 @@
return ok;
}
+#endif
void QgsDbSourceSelect::showHelp()
{
@@ -800,23 +793,23 @@
{
mStopped=false;
- PGconn *pd = PQconnectdb(mConnInfo.toLocal8Bit().data());
+ PGconn *pd = PQconnectdb(mConnInfo.toLocal8Bit());
if (PQstatus(pd) == CONNECTION_OK)
{
- PQsetClientEncoding(pd, "UNICODE");
+ PQsetClientEncoding(pd, QString("UNICODE").toLocal8Bit());
for (uint i = 0; i<schemas.size(); i++)
{
QString query = QgsDbSourceSelect::makeGeomQuery(schemas[i],
tables[i],
columns[i]);
- PGresult* gresult = PQexec(pd, query.toLocal8Bit().data());
+ PGresult* gresult = PQexec(pd, query.toUtf8());
QString type;
if (PQresultStatus(gresult) == PGRES_TUPLES_OK) {
QStringList types;
for(int j=0; j<PQntuples(gresult); j++) {
- QString type = PQgetvalue(gresult, j, 0);
+ QString type = QString::fromUtf8(PQgetvalue(gresult, j, 0));
if(type!="")
types += type;
}
Modified: trunk/qgis/src/app/qgsnewconnection.cpp
===================================================================
--- trunk/qgis/src/app/qgsnewconnection.cpp 2008-03-12 20:44:31 UTC (rev 8212)
+++ trunk/qgis/src/app/qgsnewconnection.cpp 2008-03-12 21:02:40 UTC (rev 8213)
@@ -29,6 +29,7 @@
{
#include <libpq-fe.h>
}
+
QgsNewConnection::QgsNewConnection(QWidget *parent, const QString& connName, Qt::WFlags fl)
: QDialog(parent, fl)
{
@@ -72,18 +73,22 @@
{
saveConnection();
}
+
void QgsNewConnection::on_btnHelp_clicked()
{
- helpInfo();
+ helpInfo();
}
+
void QgsNewConnection::on_btnConnect_clicked()
{
testConnection();
}
+
void QgsNewConnection::on_btnCancel_clicked(){
// cancel the dialog
reject();
}
+
void QgsNewConnection::on_cb_geometryColumnsOnly_clicked()
{
if (cb_geometryColumnsOnly->checkState() == Qt::Checked)
@@ -97,6 +102,7 @@
QgsNewConnection::~QgsNewConnection()
{
}
+
void QgsNewConnection::testConnection()
{
QgsDataSourceURI uri;
@@ -105,15 +111,15 @@
QgsLogger::debug( "PQconnectdb(" + uri.connInfo() + ");" );
PGconn *pd = PQconnectdb( uri.connInfo().toLocal8Bit().data() );
-// std::cout << pd->ErrorMessage();
+ // std::cout << pd->ErrorMessage();
if (PQstatus(pd) == CONNECTION_OK)
- {
- // Database successfully opened; we can now issue SQL commands.
- QMessageBox::information(this, tr("Test connection"), tr("Connection to %1 was successful").arg(txtDatabase->text()));
+ {
+ // Database successfully opened; we can now issue SQL commands.
+ QMessageBox::information(this, tr("Test connection"), tr("Connection to %1 was successful").arg(txtDatabase->text()));
} else
- {
- QMessageBox::information(this, tr("Test connection"), tr("Connection failed - Check settings and try again.\n\nExtended error information:\n") + QString(PQerrorMessage(pd)) );
- }
+ {
+ QMessageBox::information(this, tr("Test connection"), tr("Connection failed - Check settings and try again.\n\nExtended error information:\n") + QString(PQerrorMessage(pd)) );
+ }
// free pg connection resources
PQfinish(pd);
@@ -130,36 +136,29 @@
settings.writeEntry(baseKey + "/database", txtDatabase->text());
settings.writeEntry(baseKey + "/port", txtPort->text());
settings.writeEntry(baseKey + "/username", txtUsername->text());
- settings.writeEntry(baseKey + "/password", txtPassword->text());
+ settings.writeEntry(baseKey + "/password", chkStorePassword->isChecked() ? txtPassword->text() : "");
settings.writeEntry(baseKey + "/publicOnly", cb_publicSchemaOnly->isChecked());
settings.writeEntry(baseKey + "/geometryColumnsOnly", cb_geometryColumnsOnly->isChecked());
- if (chkStorePassword->isChecked())
- {
- settings.writeEntry(baseKey + "/save", "true");
- } else
- {
- settings.writeEntry(baseKey + "/save", "false");
- }
+ settings.writeEntry(baseKey + "/save", chkStorePassword->isChecked() ? "true" : "false");
accept();
}
+
void QgsNewConnection::helpInfo()
{
QgsContextHelp::run(context_id);
}
-/* void QgsNewConnection::saveConnection()
+
+#if 0
+void QgsNewConnection::saveConnection()
{
- QSettings settings;
- QString baseKey = "/PostgreSQL/connections/";
- baseKey += txtName->text();
- settings.writeEntry(baseKey + "/host", txtHost->text());
- settings.writeEntry(baseKey + "/database", txtDatabase->text());
+ QSettings settings;
+ QString baseKey = "/PostgreSQL/connections/";
+ baseKey += txtName->text();
+ settings.writeEntry(baseKey + "/host", txtHost->text());
+ settings.writeEntry(baseKey + "/database", txtDatabase->text());
- settings.writeEntry(baseKey + "/username", txtUsername->text());
- if (chkStorePassword->isChecked()) {
- settings.writeEntry(baseKey + "/password", txtPassword->text());
- } else{
- settings.writeEntry(baseKey + "/password", "");
- }
-
+ settings.writeEntry(baseKey + "/username", txtUsername->text());
+ settings.writeEntry(baseKey + "/password", chkStorePassword->isChecked() ? txtPassword->text() : "");
accept();
-} */
+}
+#endif
Modified: trunk/qgis/src/app/qgspgquerybuilder.cpp
===================================================================
--- trunk/qgis/src/app/qgspgquerybuilder.cpp 2008-03-12 20:44:31 UTC (rev 8212)
+++ trunk/qgis/src/app/qgspgquerybuilder.cpp 2008-03-12 21:02:40 UTC (rev 8213)
@@ -40,7 +40,7 @@
QgsDebugMsg("Attempting connect using: " + connInfo);
- mPgConnection = PQconnectdb(connInfo.toLocal8Bit().data());
+ mPgConnection = PQconnectdb(connInfo.toLocal8Bit().data()); // use what is set based on locale; after connecting, use Utf8
// check the connection status
if (PQstatus(mPgConnection) == CONNECTION_OK) {
QString datasource = QString(tr("Table <b>%1</b> in database <b>%2</b> on host <b>%3</b>, user <b>%4</b>"))
@@ -57,7 +57,7 @@
}
else
{
- QString err = PQerrorMessage(mPgConnection);
+ QString err = QString::fromLocal8Bit(PQerrorMessage(mPgConnection));
QMessageBox::critical(this, tr("Connection Failed"), tr("Connection to the database failed:") + "\n" + err);
}
}
@@ -96,22 +96,21 @@
// Populate the field vector for this layer. The field vector contains
// field name, type, length, and precision (if numeric)
QString sql = "select * from " + mUri->quotedTablename() + " limit 1";
- PGresult *result = PQexec(mPgConnection, (const char *) (sql.utf8()));
+ PGresult *result = PQexec(mPgConnection, sql.toUtf8());
QgsLogger::debug("Query executed: " + sql);
if (PQresultStatus(result) == PGRES_TUPLES_OK)
{
//--std::cout << "Field: Name, Type, Size, Modifier:" << std::endl;
for (int i = 0; i < PQnfields(result); i++) {
- QString fieldName = PQfname(result, i);
+ QString fieldName = QString::fromUtf8(PQfname(result, i));
int fldtyp = PQftype(result, i);
QString typOid = QString().setNum(fldtyp);
QgsLogger::debug("typOid is: " + typOid);
//int fieldModifier = PQfmod(result, i);
QString sql = "select typelem from pg_type where typelem = " + typOid + " and typlen = -1";
// //--std::cout << sql << std::endl;
- PGresult *oidResult = PQexec(mPgConnection,
- (const char *) (sql.utf8()));
+ PGresult *oidResult = PQexec(mPgConnection, sql.toUtf8());
if (PQresultStatus(oidResult) == PGRES_TUPLES_OK)
QgsLogger::debug("Ok fetching typelem using\n" + sql);
@@ -123,7 +122,7 @@
PQclear(oidResult);
sql = "select typname, typlen from pg_type where oid = " + poid;
// //--std::cout << sql << std::endl;
- oidResult = PQexec(mPgConnection, (const char *) (sql.utf8()));
+ oidResult = PQexec(mPgConnection, sql.toUtf8());
if (PQresultStatus(oidResult) == PGRES_TUPLES_OK)
QgsLogger::debug("Ok fetching typenam,etc\n");
@@ -180,9 +179,9 @@
// determine the field type
QgsField field = mFieldMap[mModelFields->data(lstFields->currentIndex()).toString()];
- bool mActualFieldIsChar = field.typeName().find("char") > -1;
+ mActualFieldIsChar = field.typeName().contains("char") || field.typeName().contains("text"); // really should be: field.type()==QVariant::String - but is not set correctly above
- PGresult *result = PQexec(mPgConnection, (const char *) (theSQL.utf8()));
+ PGresult *result = PQexec(mPgConnection, theSQL.toUtf8());
if (PQresultStatus(result) == PGRES_TUPLES_OK)
{
@@ -196,7 +195,7 @@
}
}else
{
- QMessageBox::warning(this, tr("Database error"), tr("<p>Failed to get sample of field values using SQL:</p><p>") + theSQL + "</p><p>Error message was: "+ QString(PQerrorMessage(mPgConnection)) + "</p>");
+ QMessageBox::warning(this, tr("Database error"), tr("<p>Failed to get sample of field values using SQL:</p><p>") + theSQL + "</p><p>Error message was: "+ QString::fromUtf8(PQerrorMessage(mPgConnection)) + "</p>");
}
// free the result set
PQclear(result);
@@ -210,7 +209,6 @@
return;
QgsField field = mFieldMap[mModelFields->data(lstFields->currentIndex()).toString()];
- bool mActualFieldIsChar = field.typeName().find("char") > -1;
QString sql = "SELECT DISTINCT \"" + myFieldName + "\" " +
"FROM (SELECT \"" + myFieldName + "\" " +
@@ -268,7 +266,7 @@
QString numRows;
QString sql = "select count(*) from " + mUri->quotedTablename()
+ " where " + txtSQL->text();
- PGresult *result = PQexec(mPgConnection, (const char *)(sql.utf8()));
+ PGresult *result = PQexec(mPgConnection, sql.toUtf8());
if (PQresultStatus(result) == PGRES_TUPLES_OK)
{
numRows = QString::fromUtf8(PQgetvalue(result, 0, 0));
@@ -280,7 +278,7 @@
{
QMessageBox::warning(this, tr("Query Failed"),
tr("An error occurred when executing the query:")
- + "\n" + QString(PQresultErrorMessage(result)));
+ + "\n" + QString::fromUtf8(PQresultErrorMessage(result)));
}
// free the result set
PQclear(result);
@@ -294,7 +292,7 @@
QString sql = "select count(*) from " + mUri->quotedTablename() + " where " + where;
long numRows;
- PGresult *result = PQexec(mPgConnection, (const char *)(sql.utf8()));
+ PGresult *result = PQexec(mPgConnection, sql.toUtf8());
if (PQresultStatus(result) == PGRES_TUPLES_OK)
{
QString rowCount = QString::fromUtf8(PQgetvalue(result, 0, 0));
@@ -303,7 +301,7 @@
else
{
numRows = -1;
- mPgErrorMessage = PQresultErrorMessage(result);
+ mPgErrorMessage = QString::fromUtf8(PQresultErrorMessage(result));
}
// free the result set
Modified: trunk/qgis/src/core/qgsdatasourceuri.cpp
===================================================================
--- trunk/qgis/src/core/qgsdatasourceuri.cpp 2008-03-12 20:44:31 UTC (rev 8212)
+++ trunk/qgis/src/core/qgsdatasourceuri.cpp 2008-03-12 21:02:40 UTC (rev 8213)
@@ -223,7 +223,7 @@
QString QgsDataSourceURI::connInfo() const
{
- QString connInfo = "dbname="+mDatabase;
+ QString connInfo = "dbname='"+mDatabase+"'";
if( mHost != "" )
{
@@ -234,7 +234,7 @@
if( mUsername != "" )
{
- connInfo += " user=" + mUsername;
+ connInfo += " user='" + mUsername + "'"; //needs to be escaped
if( mPassword != "" )
{
Modified: trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp
===================================================================
--- trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp 2008-03-12 20:44:31 UTC (rev 8212)
+++ trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp 2008-03-12 21:02:40 UTC (rev 8213)
@@ -57,20 +57,15 @@
const QString POSTGRES_KEY = "postgres";
const QString POSTGRES_DESCRIPTION = "PostgreSQL/PostGIS data provider";
-int QgsPostgresProvider::providerIds = 0;
- QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
+QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
: QgsVectorDataProvider(uri),
geomType(QGis::WKBUnknown),
mFeatureQueueSize(200),
gotPostgisVersion(FALSE)
{
-
- providerId = QString("%1").arg(providerIds++);
-
// assume this is a valid layer until we determine otherwise
valid = true;
- /* OPEN LOG FILE */
// Make connection to the data source
// For postgres, the connection information is passed as a space delimited
@@ -103,24 +98,24 @@
//pLog.open((const char *)logFile);
//QgsDebugMsg("Opened log file for " + mTableName);
- connection = connectDb( (const char *)mUri.connInfo() );
+ connection = connectDb( mUri.connInfo() );
if( connection==NULL ) {
valid = false;
return;
}
- QgsDebugMsg("Checking for select permission on the relation\n");
+ QgsDebugMsg("Checking for permissions on the relation");
// Check that we can read from the table (i.e., we have
// select permission).
- QString sql = "select * from " + mSchemaTableName + " limit 1";
- PGresult* testAccess = PQexec(connection, (const char*)(sql.utf8()));
+ QString sql = QString("select * from %1 limit 1").arg(mSchemaTableName);
+ PGresult* testAccess = PQexec(connection, sql.toUtf8());
if (PQresultStatus(testAccess) != PGRES_TUPLES_OK)
{
showMessageBox(tr("Unable to access relation"),
tr("Unable to access the ") + mSchemaTableName +
tr(" relation.\nThe error message from the database was:\n") +
- QString(PQresultErrorMessage(testAccess)) + ".\n" +
+ QString::fromUtf8(PQresultErrorMessage(testAccess)) + ".\n" +
"SQL: " + sql);
PQclear(testAccess);
valid = false;
@@ -129,22 +124,67 @@
}
PQclear(testAccess);
- PGresult *schema = PQexec(connection, "SELECT current_schema()");
- if (PQresultStatus(schema) == PGRES_TUPLES_OK)
- {
- mCurrentSchema = PQgetvalue(schema, 0, 0);
- if(mCurrentSchema==mSchemaName) {
- mUri.clearSchema();
- setDataSourceUri( mUri.uri() );
- }
+ sql = QString("SELECT "
+ "has_table_privilege(%1,'DELETE'),"
+ "has_table_privilege(%1,'UPDATE'),"
+ "has_table_privilege(%1,'INSERT'),"
+ "current_schema()")
+ .arg( quotedValue(mSchemaTableName) );
+
+ testAccess = PQexec( connection, sql.toUtf8() );
+ if( PQresultStatus(testAccess) != PGRES_TUPLES_OK ) {
+ showMessageBox(tr("Unable to access relation"),
+ tr("Unable to determine table access privileges for the ") + mSchemaTableName +
+ tr(" relation.\nThe error message from the database was:\n") +
+ QString::fromUtf8(PQresultErrorMessage(testAccess)) + ".\n" +
+ "SQL: " + sql);
+ PQclear(testAccess);
+ valid = false;
+ disconnectDb();
+ return;
}
- PQclear(schema);
+ enabledCapabilities = QgsVectorDataProvider::SelectGeometryAtId;
+
+ if( QString::fromUtf8( PQgetvalue(testAccess, 0, 0) )=="t" ) {
+ // DELETE
+ enabledCapabilities |= QgsVectorDataProvider::DeleteFeatures;
+ }
+
+ if( QString::fromUtf8( PQgetvalue(testAccess, 0, 1) )=="t" ) {
+ // UPDATE
+ enabledCapabilities |= QgsVectorDataProvider::ChangeGeometries | QgsVectorDataProvider::ChangeAttributeValues;
+ }
+
+ if( QString::fromUtf8( PQgetvalue(testAccess, 0, 2) )=="t" ) {
+ // INSERT
+ enabledCapabilities |= QgsVectorDataProvider::AddFeatures;
+ }
+
+ mCurrentSchema = QString::fromUtf8( PQgetvalue(testAccess, 0, 3) );
+ if(mCurrentSchema==mSchemaName) {
+ mUri.clearSchema();
+ setDataSourceUri( mUri.uri() );
+ }
if(mSchemaName=="")
mSchemaName=mCurrentSchema;
+ PQclear(testAccess);
- if (!getGeometryDetails()) // gets srid and geometry type
+ sql = QString("SELECT 1 FROM pg_class,pg_namespace WHERE "
+ "pg_class.relnamespace=pg_namespace.oid AND "
+ "pg_get_userbyid(relowner)=current_user AND "
+ "relname=%1 AND nspname=%2")
+ .arg( quotedValue(mTableName) )
+ .arg( quotedValue(mSchemaName) );
+ testAccess = PQexec(connection, sql.toUtf8());
+ if (PQresultStatus(testAccess) == PGRES_TUPLES_OK && PQntuples(testAccess)==1)
{
+ enabledCapabilities |= QgsVectorDataProvider::AddAttributes | QgsVectorDataProvider::DeleteAttributes;
+ }
+ PQclear(testAccess);
+
+ if ( !getGeometryDetails() ) // gets srid and geometry type
+ {
// the table is not a geometry table
numberFeatures = 0;
valid = false;
@@ -167,7 +207,7 @@
// Set the postgresql message level so that we don't get the
// 'there is no transaction in progress' warning.
#ifndef QGISDEBUG
- PQexec(connection, "set client_min_messages to error");
+ PQexec(connection, QString("set client_min_messages to error").toUtf8());
#endif
// Kick off the long running threads
@@ -241,18 +281,11 @@
//pLog.flush();
}
-PGconn *QgsPostgresProvider::connectDb(const char *conninfo)
+PGconn *QgsPostgresProvider::connectDb(const QString & conninfo)
{
- if( connections.contains(conninfo) )
- {
- QgsDebugMsg(QString("Using cached connection for ") + conninfo);
- connections[conninfo]->ref++;
- return connections[conninfo]->conn;
- }
-
QgsDebugMsg(QString("New postgres connection for ") + conninfo);
- PGconn *pd = PQconnectdb(conninfo);
+ PGconn *pd = PQconnectdb(conninfo.toLocal8Bit()); // use what is set based on locale; after connecting, use Utf8
// check the connection status
if (PQstatus(pd) != CONNECTION_OK)
{
@@ -263,7 +296,7 @@
//set client encoding to unicode because QString uses UTF-8 anyway
QgsDebugMsg("setting client encoding to UNICODE");
- int errcode=PQsetClientEncoding(pd, "UNICODE");
+ int errcode=PQsetClientEncoding(pd, QString("UNICODE").toLocal8Bit());
if(errcode==0)
{
@@ -292,32 +325,13 @@
}
//--std::cout << "Connection to the database was successful\n";
- Conn *conn = new Conn(pd);
- connections.insert( conninfo, conn );
-
return pd;
}
void QgsPostgresProvider::disconnectDb()
{
- QMapIterator <QString, Conn *> i(connections);
- while( i.hasNext() )
- {
- i.next();
-
- if( i.value()->conn == connection )
- break;
- }
-
- assert( i.value()->conn==connection );
- assert( i.value()->ref>0 );
-
- if( --i.value()->ref==0 )
- {
- PQfinish( i.value()->conn );
- delete (i.value());
- connections.remove( i.key() );
- }
+ PQfinish( connection );
+ connection = 0;
}
QString QgsPostgresProvider::storageType()
@@ -333,12 +347,12 @@
// Top up our queue if it is empty
if (mFeatureQueue.empty())
{
- QString fetch = QString("fetch forward %1 from qgisf" + providerId)
+ QString fetch = QString("fetch forward %1 from qgisf")
.arg(mFeatureQueueSize);
if(mFirstFetch)
{
- if(PQsendQuery(connection, (const char *)fetch) == 0) //fetch features in asynchronously
+ if(PQsendQuery(connection, fetch.toUtf8()) == 0) //fetch features in asynchronously
{
qWarning("PQsendQuery failed (1)");
}
@@ -353,20 +367,22 @@
{
QgsDebugMsg("End of features");
+ PQclear(queryResult);
if (ready)
- PQexec(connection, "end work");
+ PQexec(connection, QString("end work").toUtf8());
ready = false;
return false;
}
for (int row = 0; row < rows; row++)
{
- int oid = *(int *)PQgetvalue(queryResult, row, PQfnumber(queryResult,"\""+primaryKey+"\""));
+ int oid = *(int *)PQgetvalue(queryResult, row, PQfnumber(queryResult,quotedIdentifier(primaryKey).toUtf8()));
if (swapEndian)
oid = ntohl(oid); // convert oid to opposite endian
- mFeatureQueue.push(QgsFeature());
+ mFeatureQueue.push(QgsFeature());
+
// set ID
mFeatureQueue.back().setFeatureId(oid);
@@ -383,12 +399,14 @@
}
else
{
- char* attribute = PQgetvalue(queryResult, row, PQfnumber(queryResult,"\""+*name_it+"\""));
- val = QString::fromUtf8(attribute);
+ val = QString::fromUtf8(PQgetvalue(queryResult, row, PQfnumber(queryResult,quotedIdentifier(*name_it).toUtf8())));
}
switch (attributeFields[*index_it].type())
{
+ case QVariant::LongLong:
+ mFeatureQueue.back().addAttribute(*index_it, val.toLongLong());
+ break;
case QVariant::Int:
mFeatureQueue.back().addAttribute(*index_it, val.toInt());
break;
@@ -411,12 +429,12 @@
{
unsigned char *featureGeom = new unsigned char[returnedLength + 1];
memset(featureGeom, '\0', returnedLength + 1);
- memcpy(featureGeom, PQgetvalue(queryResult, row, PQfnumber(queryResult,"qgs_feature_geometry")), returnedLength);
+ memcpy(featureGeom, PQgetvalue(queryResult, row, PQfnumber(queryResult,QString("qgs_feature_geometry").toUtf8())), returnedLength);
mFeatureQueue.back().setGeometryAndOwnership(featureGeom, returnedLength + 1);
}
else
{
- mFeatureQueue.back().setGeometryAndOwnership(0, 0);
+ mFeatureQueue.back().setGeometryAndOwnership(0, 0);
QgsDebugMsg("Couldn't get the feature geometry in binary form");
}
}
@@ -424,7 +442,7 @@
PQclear(queryResult);
- if(PQsendQuery(connection, (const char *)fetch) == 0) //already fetch the next couple of features asynchronously
+ if(PQsendQuery(connection, fetch.toUtf8()) == 0) //already fetch the next couple of features asynchronously
{
qWarning("PQsendQuery failed (2)");
}
@@ -433,14 +451,14 @@
// Now return the next feature from the queue
if(mFetchGeom)
- {
- QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership();
- feature.setGeometry(featureGeom);
- }
+ {
+ QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership();
+ feature.setGeometry(featureGeom);
+ }
else
- {
- feature.setGeometryAndOwnership(0, 0);
- }
+ {
+ feature.setGeometryAndOwnership(0, 0);
+ }
feature.setFeatureId(mFeatureQueue.front().featureId());
feature.setAttributeMap(mFeatureQueue.front().attributeMap());
@@ -467,7 +485,7 @@
mFetchAttributeNames.clear();
QgsFieldMap attributeMap = fields();
QgsFieldMap::const_iterator fieldIt;
- for(QgsAttributeList::const_iterator it = mAttributesToFetch.constBegin(); \
+ for(QgsAttributeList::const_iterator it = mAttributesToFetch.constBegin();
it != mAttributesToFetch.constEnd(); ++it)
{
fieldIt = attributeMap.find(*it);
@@ -477,22 +495,23 @@
}
}
- QString declare = "declare qgisf" + providerId + " binary cursor for select \"" + primaryKey + "\"";
+ QString declare = "declare qgisf binary cursor for select " + quotedIdentifier(primaryKey);
if(fetchGeometry)
{
- declare += QString(",asbinary(\"%1\",'%2') as qgs_feature_geometry").arg(geometryColumn).arg(endianString());
+ declare += QString(",asbinary(%1,'%2') as qgs_feature_geometry")
+ .arg( quotedIdentifier(geometryColumn) )
+ .arg( endianString() );
}
for(std::list<QString>::const_iterator it = mFetchAttributeNames.begin(); it != mFetchAttributeNames.end(); ++it)
{
if( (*it) != primaryKey) //no need to fetch primary key again
{
- declare += ",\"" + *it + "\"::text";
+ declare += "," + quotedIdentifier(*it) + "::text";
}
}
- declare += " ";
- declare += QString("from %1").arg(mSchemaTableName);
+ declare += QString(" from %1").arg(mSchemaTableName);
QgsDebugMsg("Binary cursor: " + declare);
@@ -504,12 +523,12 @@
{
// Contributed by #qgis irc "creeping"
// This version actually invokes PostGIS's use of spatial indexes
- declare += " where " + geometryColumn;
+ declare += " where " + quotedIdentifier(geometryColumn);
declare += " && setsrid('BOX3D(" + rect.asWKTCoords();
declare += ")'::box3d,";
declare += srid;
declare += ")";
- declare += " and intersects(" + geometryColumn;
+ declare += " and intersects(" + quotedIdentifier(geometryColumn);
declare += ", setsrid('BOX3D(" + rect.asWKTCoords();
declare += ")'::box3d,";
declare += srid;
@@ -517,7 +536,7 @@
}
else
{
- declare += " where " + geometryColumn;
+ declare += " where " + quotedIdentifier(geometryColumn);
declare += " && setsrid('BOX3D(" + rect.asWKTCoords();
declare += ")'::box3d,";
declare += srid;
@@ -540,11 +559,11 @@
// set up the cursor
if(ready){
- PQexec(connection, "end work");
+ PQexec(connection, QString("end work").toUtf8());
}
- PQexec(connection,"begin work");
+ PQexec(connection,QString("begin work").toUtf8());
ready = true;
- PQexec(connection, (const char *)(declare.utf8()));
+ PQexec(connection, declare.toUtf8());
while(!mFeatureQueue.empty())
{
@@ -558,7 +577,6 @@
bool fetchGeometry,
QgsAttributeList fetchAttributes)
{
-
std::list<QString> attributeNames;
QgsFieldMap fldMap = fields();
QgsFieldMap::const_iterator fieldIt;
@@ -574,43 +592,46 @@
}
}
- QString sql = "declare qgisfid" + providerId + " binary cursor for select \"" + primaryKey + "\"";
+ QString sql = "declare qgisfid binary cursor for select " + quotedIdentifier(primaryKey);
if(fetchGeometry)
{
- sql += QString(",asbinary(\"%1\",'%2') as qgs_feature_geometry").arg(geometryColumn).arg(endianString());
+ sql += QString(",asbinary(%1,'%2') as qgs_feature_geometry")
+ .arg( quotedIdentifier(geometryColumn) )
+ .arg( endianString() );
}
for(namesIt = attributeNames.begin(); namesIt != attributeNames.end(); ++namesIt)
{
if( (*namesIt) != primaryKey) //no need to fetch primary key again
{
- sql += ",\"" + *namesIt + "\"::text";
+ sql += "," + quotedIdentifier(*namesIt) + "::text";
}
}
sql += " " + QString("from %1").arg(mSchemaTableName);
- sql += " where " + primaryKey + " = " + QString::number(featureId);
+ sql += " where " + quotedIdentifier(primaryKey) + "=" + QString::number(featureId);
QgsDebugMsg("Selecting feature using: " + sql);
- PQexec(connection,"begin work");
+ PQexec(connection,QString("begin work").toUtf8());
// execute query
- PQexec(connection, (const char *)(sql.utf8()));
+ PQexec(connection, sql.toUtf8());
- PGresult *res = PQexec(connection, "fetch forward 1 from qgisfid" + providerId);
+ PGresult *res = PQexec(connection, QString("fetch forward 1 from qgisfid").toUtf8());
int rows = PQntuples(res);
if (rows == 0)
{
- PQexec(connection, "end work");
+ PQclear(res);
+ PQexec(connection, QString("end work").toUtf8());
QgsDebugMsg("feature " + QString::number(featureId) + " not found");
return FALSE;
}
// set ID
- int oid = *(int *)PQgetvalue(res, 0, PQfnumber(res,"\""+primaryKey+"\""));
+ int oid = *(int *)PQgetvalue(res, 0, PQfnumber(res,quotedIdentifier(primaryKey).toUtf8()));
if (swapEndian)
oid = ntohl(oid); // convert oid to opposite endian
feature.setFeatureId(oid);
@@ -627,12 +648,14 @@
}
else
{
- char* attribute = PQgetvalue(res, 0, PQfnumber(res,*namesIt));
- val = QString::fromUtf8(attribute);
+ val = QString::fromUtf8(PQgetvalue(res, 0, PQfnumber(res,quotedIdentifier(*namesIt).toUtf8())));
}
switch (attributeFields[*it].type())
{
+ case QVariant::LongLong:
+ feature.addAttribute(*it, val.toLongLong());
+ break;
case QVariant::Int:
feature.addAttribute(*it, val.toInt());
break;
@@ -655,12 +678,13 @@
{
unsigned char *featureGeom = new unsigned char[returnedLength + 1];
memset(featureGeom, '\0', returnedLength + 1);
- memcpy(featureGeom, PQgetvalue(res, 0, PQfnumber(res,"qgs_feature_geometry")), returnedLength);
+ memcpy(featureGeom, PQgetvalue(res, 0, PQfnumber(res,QString("qgs_feature_geometry").toUtf8())), returnedLength);
feature.setGeometryAndOwnership(featureGeom, returnedLength + 1);
}
}
- PQexec(connection, "end work");
+ PQclear(res);
+ PQexec(connection, QString("end work").toUtf8());
return TRUE;
}
@@ -720,8 +744,8 @@
void QgsPostgresProvider::reset()
{
- QString move = "move 0 in qgisf" + providerId; //move cursor to first record
- PQexec(connection, (const char *)(move.utf8()));
+ QString move = "move 0 in qgisf"; //move cursor to first record
+ PQexec(connection, move.toUtf8());
mFeatureQueue.empty();
loadFields();
}
@@ -747,58 +771,59 @@
QgsDebugMsg("Loading fields for table " + mTableName);
// Get the relation oid for use in later queries
- QString sql = "SELECT oid FROM pg_class WHERE relname = '" + mTableName + "' AND relnamespace = ("
- "SELECT oid FROM pg_namespace WHERE nspname = '" + mSchemaName + "')";
- PGresult *tresult= PQexec(connection, (const char *)(sql.utf8()));
- QString tableoid = PQgetvalue(tresult, 0, 0);
+ QString sql = "SELECT regclass(" + quotedValue(mSchemaTableName) + ")::oid";
+ PGresult *tresult= PQexec(connection, sql.toUtf8());
+ QString tableoid = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
PQclear(tresult);
// Get the table description
sql = "SELECT description FROM pg_description WHERE "
"objoid = " + tableoid + " AND objsubid = 0";
- tresult = PQexec(connection, (const char*) sql.utf8());
+ tresult = PQexec(connection, sql.toUtf8());
if (PQntuples(tresult) > 0)
- mDataComment = PQgetvalue(tresult, 0, 0);
+ mDataComment = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
PQclear(tresult);
// Populate the field vector for this layer. The field vector contains
// field name, type, length, and precision (if numeric)
sql = "select * from " + mSchemaTableName + " limit 0";
- PGresult *result = PQexec(connection, (const char *) (sql.utf8()));
+ PGresult *result = PQexec(connection, sql.toUtf8());
//--std::cout << "Field: Name, Type, Size, Modifier:" << std::endl;
// The queries inside this loop could possibly be combined into one
// single query - this would make the code run faster.
+ attributeFields.clear();
for (int i = 0; i < PQnfields(result); i++)
{
- QString fieldName = PQfname(result, i);
+ QString fieldName = QString::fromUtf8(PQfname(result, i));
int fldtyp = PQftype(result, i);
QString typOid = QString().setNum(fldtyp);
int fieldModifier = PQfmod(result, i);
QString fieldComment("");
- sql = "SELECT typname, typlen FROM pg_type WHERE "
- "oid = (SELECT typelem FROM pg_type WHERE "
- "typelem = " + typOid + " AND typlen = -1)";
+ sql = "SELECT typname, typlen FROM pg_type WHERE "
+ "oid="+typOid; // just oid; needs more work to support array type
+// "oid = (SELECT Distinct typelem FROM pg_type WHERE " //needs DISTINCT to guard against 2 or more rows on int2
+// "typelem = " + typOid + " AND typlen = -1)";
- PGresult* oidResult = PQexec(connection, (const char *) sql);
- QString fieldTypeName = PQgetvalue(oidResult, 0, 0);
- QString fieldSize = PQgetvalue(oidResult, 0, 1);
+ PGresult* oidResult = PQexec(connection, sql.toUtf8());
+ QString fieldTypeName = QString::fromUtf8(PQgetvalue(oidResult, 0, 0));
+ QString fieldSize = QString::fromUtf8(PQgetvalue(oidResult, 0, 1));
PQclear(oidResult);
sql = "SELECT attnum FROM pg_attribute WHERE "
- "attrelid = " + tableoid + " AND attname = '" + fieldName + "'";
- PGresult *tresult = PQexec(connection, (const char *)(sql.utf8()));
- QString attnum = PQgetvalue(tresult, 0, 0);
+ "attrelid = " + tableoid + " AND attname = " + quotedValue(fieldName);
+ PGresult *tresult = PQexec(connection, sql.toUtf8());
+ QString attnum = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
PQclear(tresult);
sql = "SELECT description FROM pg_description WHERE "
"objoid = " + tableoid + " AND objsubid = " + attnum;
- tresult = PQexec(connection, (const char*)(sql.utf8()));
+ tresult = PQexec(connection, sql.toUtf8());
if (PQntuples(tresult) > 0)
- fieldComment = PQgetvalue(tresult, 0, 0);
+ fieldComment = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
PQclear(tresult);
QgsDebugMsg("Field: " + attnum + " maps to " + QString::number(i) + " " + fieldName + ", "
@@ -807,11 +832,14 @@
if(fieldName!=geometryColumn)
{
QVariant::Type fieldType;
- if (fieldTypeName.find("int") != -1 || fieldTypeName.find("serial") != -1)
+ if (fieldTypeName.find("int8") != -1)
+ fieldType = QVariant::LongLong;
+ else if (fieldTypeName.find("int") != -1 || fieldTypeName.find("serial") != -1)
fieldType = QVariant::Int;
- else if (fieldTypeName == "real" || fieldTypeName == "double precision" || \
- fieldTypeName.find("float") != -1)
+ else if (fieldTypeName == "real" || fieldTypeName == "double precision" || fieldTypeName.find("float") != -1)
fieldType = QVariant::Double;
+ else if (fieldTypeName == "bytea")
+ continue;
else
fieldType = QVariant::String;
attributeFields.insert(i, QgsField(fieldName, fieldType, fieldTypeName, fieldSize.toInt(), fieldModifier, fieldComment));
@@ -826,10 +854,8 @@
// can be used as a key into the table. Primary keys are always
// unique indices, so we catch them as well.
- QString sql = "select indkey from pg_index where indisunique = 't' and "
- "indrelid = (select oid from pg_class where relname = '"
- + mTableName + "' and relnamespace = (select oid from pg_namespace where "
- "nspname = '" + mSchemaName + "'))";
+ QString sql ="select indkey from pg_index where indisunique = 't' and "
+ "indrelid = regclass(" + quotedValue(mSchemaTableName) + ")::oid";
QgsDebugMsg("Getting unique index using '" + sql + "'");
@@ -849,11 +875,9 @@
// If the relation is a view try to find a suitable column to use as
// the primary key.
- sql = "select relkind from pg_class where relname = '" + mTableName +
- "' and relnamespace = (select oid from pg_namespace where "
- "nspname = '" + mSchemaName + "')";
+ sql = "SELECT relkind FROM pg_class WHERE oid = regclass(" + quotedValue(mSchemaTableName) + ")::oid";
PGresult* tableType = executeDbCommand(connection, sql);
- QString type = PQgetvalue(tableType, 0, 0);
+ QString type = QString::fromUtf8(PQgetvalue(tableType, 0, 0));
PQclear(tableType);
primaryKey = "";
@@ -864,10 +888,9 @@
// If there is an oid on the table, use that instead,
// otherwise give up
- sql = "select attname from pg_attribute where attname = 'oid' and "
- "attrelid = (select oid from pg_class where relname = '" +
- mTableName + "' and relnamespace = (select oid from pg_namespace "
- "where nspname = '" + mSchemaName + "'))";
+ sql = "SELECT attname FROM pg_attribute WHERE attname = 'oid' AND "
+ "attrelid = regclass(" + quotedValue(mSchemaTableName) + ")";
+
PGresult* oidCheck = executeDbCommand(connection, sql);
if (PQntuples(oidCheck) != 0)
@@ -909,22 +932,20 @@
std::vector<std::pair<QString, QString> > suitableKeyColumns;
for (int i = 0; i < PQntuples(pk); ++i)
{
- QString col = PQgetvalue(pk, i, 0);
+ QString col = QString::fromUtf8(PQgetvalue(pk, i, 0));
QStringList columns = QStringList::split(" ", col);
if (columns.count() == 1)
{
// Get the column name and data type
sql = "select attname, pg_type.typname from pg_attribute, pg_type where "
"atttypid = pg_type.oid and attnum = " +
- col + " and attrelid = (select oid from pg_class where " +
- "relname = '" + mTableName + "' and relnamespace = (select oid "
- "from pg_namespace where nspname = '" + mSchemaName + "'))";
+ col + " and attrelid = regclass(" + quotedValue(mSchemaTableName) + ")";
PGresult* types = executeDbCommand(connection, sql);
if( PQntuples(types) > 0 )
{
- QString columnName = PQgetvalue(types, 0, 0);
- QString columnType = PQgetvalue(types, 0, 1);
+ QString columnName = QString::fromUtf8(PQgetvalue(types, 0, 0));
+ QString columnType = QString::fromUtf8(PQgetvalue(types, 0, 1));
if (columnType != "int4")
log.append(tr("The unique index on column") +
@@ -946,9 +967,7 @@
sql = "select attname from pg_attribute, pg_type where "
"atttypid = pg_type.oid and attnum in (" +
col.replace(" ", ",")
- + ") and attrelid = (select oid from pg_class where " +
- "relname = '" + mTableName + "' and relnamespace = (select oid "
- "from pg_namespace where nspname = '" + mSchemaName + "'))";
+ + ") and attrelid = regclass(" + quotedValue(mSchemaTableName) + ")::oid";
PGresult* types = executeDbCommand(connection, sql);
QString colNames;
int numCols = PQntuples(types);
@@ -956,8 +975,9 @@
{
if (j == numCols-1)
colNames += tr("and ");
- colNames += "'" + QString(PQgetvalue(types, j, 0))
- + (j < numCols-2 ? "', " : "' ");
+ colNames += quotedValue( QString::fromUtf8(PQgetvalue(types, j, 0)) );
+ if ( j < numCols-2 )
+ colNames+= ",";
}
log.append(tr("The unique index based on columns ") + colNames +
@@ -982,9 +1002,7 @@
// If there is an oid on the table, use that instead,
// otherwise give up
sql = "select attname from pg_attribute where attname = 'oid' and "
- "attrelid = (select oid from pg_class where relname = '" +
- mTableName + "' and relnamespace = (select oid from pg_namespace "
- "where nspname = '" + mSchemaName + "'))";
+ "attrelid = regclass('" + mSchemaTableName + "')::oid";
PGresult* oidCheck = executeDbCommand(connection, sql);
if (PQntuples(oidCheck) != 0)
@@ -1051,10 +1069,8 @@
// Get the oid from pg_class for the given schema.relation for use
// in subsequent queries.
- sql = "select oid from pg_class where relname = '" + tableName +
- "' and relnamespace = (select oid from pg_namespace where "
- " nspname = '" + schemaName + "')";
- PGresult* result = PQexec(connection, (const char*)(sql.utf8()));
+ sql = "select regclass('" + quotedIdentifier(schemaName) + "." + quotedIdentifier(tableName) + "')::oid";
+ PGresult* result = PQexec(connection, sql.toUtf8());
QString rel_oid;
if (PQntuples(result) == 1)
{
@@ -1086,7 +1102,7 @@
"and (contype = 'p' or contype = 'u') "
"and array_dims(conkey) = '[1:1]'";
- result = PQexec(connection, (const char*)(sql.utf8()));
+ result = PQexec(connection, sql.toUtf8());
if (PQntuples(result) == 1 && colType == "int4")
suitable[viewCol] = iter->second;
@@ -1145,7 +1161,7 @@
sql = "select * from pg_index where indrelid = " + rel_oid +
" and indkey[0] = (select attnum from pg_attribute where "
"attrelid = " + rel_oid + " and attname = '" + i->second.column + "')";
- PGresult* result = PQexec(connection, (const char*)(sql.utf8()));
+ PGresult* result = PQexec(connection, sql.toUtf8());
if (PQntuples(result) > 0 && uniqueData(mSchemaName, mTableName, i->first))
{ // Got one. Use it.
@@ -1226,13 +1242,13 @@
bool isUnique = false;
- QString sql = "select count(distinct \"" + colName + "\") = count(\"" +
- colName + "\") from \"" + schemaName + "\".\"" + tableName + "\"";
+ QString sql = "select count(distinct " + quotedIdentifier(colName) + ") = count(" + quotedIdentifier(colName) + ") from " + quotedIdentifier(schemaName) + "." + quotedIdentifier(tableName);
- PGresult* unique = PQexec(connection, (const char*) (sql.utf8()));
+ PGresult* unique = PQexec(connection, sql.toUtf8());
if (PQntuples(unique) == 1)
- if (strncmp(PQgetvalue(unique, 0, 0),"t", 1) == 0)
+// if (strncmp(PQgetvalue(unique, 0, 0),"t", 1) == 0)
+ if (QString::fromUtf8(PQgetvalue(unique, 0, 0)).compare("t") == 0) //really should compare just first character as original did
isUnique = true;
PQclear(unique);
@@ -1243,12 +1259,12 @@
int QgsPostgresProvider::SRCFromViewColumn(const QString& ns, const QString& relname, const QString& attname_table, const QString& attname_view, const QString& viewDefinition, SRC& result) const
{
QString newViewDefSql = "SELECT definition FROM pg_views WHERE schemaname = '" + ns + "' AND viewname = '" + relname + "'";
- PGresult* newViewDefResult = PQexec(connection, (const char*)(newViewDefSql.utf8()));
+ PGresult* newViewDefResult = PQexec(connection, newViewDefSql.toUtf8());
int numEntries = PQntuples(newViewDefResult);
if(numEntries > 0) //relation is a view
{
- QString newViewDefinition(PQgetvalue(newViewDefResult, 0, 0));
+ QString newViewDefinition(QString::fromUtf8(PQgetvalue(newViewDefResult, 0, 0)));
QString newAttNameView = attname_table;
QString newAttNameTable = attname_table;
@@ -1263,12 +1279,15 @@
}
}
- QString viewColumnSql = "SELECT table_schema, table_name, column_name FROM information_schema.view_column_usage WHERE view_schema = '" + ns + "' AND view_name = '" + relname + "' AND column_name = '" + newAttNameTable +"'";
- PGresult* viewColumnResult = PQexec(connection, (const char*)(viewColumnSql.utf8()));
+ QString viewColumnSql = "SELECT table_schema, table_name, column_name FROM (SELECT DISTINCT current_database()::information_schema.sql_identifier AS view_catalog, nv.nspname::information_schema.sql_identifier AS view_schema, v.relname::information_schema.sql_identifier AS view_name, current_database()::information_schema.sql_identifier AS table_catalog, nt.nspname::information_schema.sql_identifier AS table_schema, t.relname::information_schema.sql_identifier AS table_name, a.attname::information_schema.sql_identifier AS column_name "
+" FROM pg_namespace nv, pg_class v, pg_depend dv, pg_depend dt, pg_class t, pg_namespace nt, pg_attribute a "
+" WHERE nv.oid = v.relnamespace AND v.relkind = 'v'::\"char\" AND v.oid = dv.refobjid AND dv.refclassid = 'pg_class'::regclass::oid AND dv.classid = 'pg_rewrite'::regclass::oid AND dv.deptype = 'i'::\"char\" AND dv.objid = dt.objid AND dv.refobjid <> dt.refobjid AND dt.classid = 'pg_rewrite'::regclass::oid AND dt.refclassid = 'pg_class'::regclass::oid AND dt.refobjid = t.oid AND t.relnamespace = nt.oid AND (t.relkind = ANY (ARRAY['r'::\"char\", 'v'::\"char\"])) AND t.oid = a.attrelid AND dt.refobjsubid = a.attnum "
+"ORDER BY current_database()::information_schema.sql_identifier, nv.nspname::information_schema.sql_identifier, v.relname::information_schema.sql_identifier, current_database()::information_schema.sql_identifier, nt.nspname::information_schema.sql_identifier, t.relname::information_schema.sql_identifier, a.attname::information_schema.sql_identifier) x WHERE view_schema = '" + ns + "' AND view_name = '" + relname + "' AND column_name = '" + newAttNameTable +"'";
+ PGresult* viewColumnResult = PQexec(connection, viewColumnSql.toUtf8());
if(PQntuples(viewColumnResult) > 0)
{
- QString newTableSchema = PQgetvalue(viewColumnResult, 0, 0);
- QString newTableName = PQgetvalue(viewColumnResult, 0, 1);
+ QString newTableSchema = QString::fromUtf8(PQgetvalue(viewColumnResult, 0, 0));
+ QString newTableName = QString::fromUtf8(PQgetvalue(viewColumnResult, 0, 1));
int retvalue = SRCFromViewColumn(newTableSchema, newTableName, newAttNameTable, newAttNameView, newViewDefinition, result);
PQclear(viewColumnResult);
return retvalue;
@@ -1288,12 +1307,12 @@
QgsDebugMsg("***********************************************************************************");
QgsDebugMsg(typeSql);
QgsDebugMsg("***********************************************************************************");
- PGresult* typeSqlResult = PQexec(connection, (const char*)(typeSql.utf8()));
+ PGresult* typeSqlResult = PQexec(connection, typeSql.toUtf8());
if(PQntuples(typeSqlResult) < 1)
{
return 1;
}
- QString type = PQgetvalue(typeSqlResult, 0, 0);
+ QString type = QString::fromUtf8(PQgetvalue(typeSqlResult, 0, 0));
PQclear(typeSqlResult);
result.schema=ns;
@@ -1309,18 +1328,21 @@
void QgsPostgresProvider::findColumns(tableCols& cols)
{
- QString viewColumnSql = "SELECT table_schema, table_name, column_name FROM information_schema.view_column_usage WHERE view_schema = '" + mSchemaName + "' AND view_name = '" + mTableName + "'";
- PGresult* viewColumnResult = PQexec(connection, (const char*)(viewColumnSql.utf8()));
+ QString viewColumnSql = "SELECT table_schema, table_name, column_name FROM (SELECT DISTINCT current_database() AS view_catalog, nv.nspname AS view_schema, v.relname AS view_name, current_database() AS table_catalog, nt.nspname AS table_schema, t.relname AS table_name, a.attname AS column_name "
+" FROM pg_namespace nv, pg_class v, pg_depend dv, pg_depend dt, pg_class t, pg_namespace nt, pg_attribute a "
+" WHERE nv.oid = v.relnamespace AND v.relkind = 'v'::\"char\" AND v.oid = dv.refobjid AND dv.refclassid = 'pg_class'::regclass::oid AND dv.classid = 'pg_rewrite'::regclass::oid AND dv.deptype = 'i'::\"char\" AND dv.objid = dt.objid AND dv.refobjid <> dt.refobjid AND dt.classid = 'pg_rewrite'::regclass::oid AND dt.refclassid = 'pg_class'::regclass::oid AND dt.refobjid = t.oid AND t.relnamespace = nt.oid AND (t.relkind = ANY (ARRAY['r'::\"char\", 'v'::\"char\"])) AND t.oid = a.attrelid AND dt.refobjsubid = a.attnum "
+"ORDER BY current_database(), nv.nspname, v.relname, current_database(), nt.nspname, t.relname, a.attname) x WHERE view_schema = '" + mSchemaName + "' AND view_name = '" + mTableName + "'";
+ PGresult* viewColumnResult = PQexec(connection, viewColumnSql.toUtf8());
//find out view definition
QString viewDefSql = "SELECT definition FROM pg_views WHERE schemaname = '" + mSchemaName + "' AND viewname = '" + mTableName + "'";
- PGresult* viewDefResult = PQexec(connection, (const char*)(viewDefSql.utf8()));
+ PGresult* viewDefResult = PQexec(connection, viewDefSql.toUtf8());
if(PQntuples(viewDefResult) < 1)
{
PQclear(viewDefResult);
return;
}
- QString viewDefinition(PQgetvalue(viewDefResult, 0, 0));
+ QString viewDefinition(QString::fromUtf8(PQgetvalue(viewDefResult, 0, 0)));
PQclear(viewDefResult);
QString ns, relname, attname_table, attname_view;
@@ -1328,9 +1350,9 @@
for(int i = 0; i < PQntuples(viewColumnResult); ++i)
{
- ns = PQgetvalue(viewColumnResult, i, 0);
- relname = PQgetvalue(viewColumnResult, i, 1);
- attname_table = PQgetvalue(viewColumnResult, i, 2);
+ ns = QString::fromUtf8(PQgetvalue(viewColumnResult, i, 0));
+ relname = QString::fromUtf8(PQgetvalue(viewColumnResult, i, 1));
+ attname_table = QString::fromUtf8(PQgetvalue(viewColumnResult, i, 2));
//find out original attribute name
attname_view = attname_table;
@@ -1574,14 +1596,14 @@
QString sql;
if(sqlWhereClause.isEmpty())
{
- sql = QString("select min(\"%1\") from %2").arg(fld.name()).arg(mSchemaTableName);
+ sql = QString("select min(%1) from %2").arg(quotedIdentifier(fld.name())).arg(mSchemaTableName);
}
else
{
- sql = QString("select min(\"%1\") from %2").arg(fld.name()).arg(mSchemaTableName)+" where "+sqlWhereClause;
+ sql = QString("select min(%1) from %2").arg(quotedIdentifier(fld.name())).arg(mSchemaTableName)+" where "+sqlWhereClause;
}
- PGresult *rmin = PQexec(connection,(const char *)(sql.utf8()));
- QString minValue = PQgetvalue(rmin,0,0);
+ PGresult *rmin = PQexec(connection, sql.toUtf8());
+ QString minValue = QString::fromUtf8(PQgetvalue(rmin,0,0));
PQclear(rmin);
return minValue.toDouble();
}
@@ -1595,14 +1617,14 @@
QString sql;
if(sqlWhereClause.isEmpty())
{
- sql = QString("select max(\"%1\") from %2").arg(fld.name()).arg(mSchemaTableName);
+ sql = QString("select max(%1) from %2").arg(quotedIdentifier(fld.name())).arg(mSchemaTableName);
}
else
{
- sql = QString("select max(\"%1\") from %2").arg(fld.name()).arg(mSchemaTableName)+" where "+sqlWhereClause;
+ sql = QString("select max(%1) from %2").arg(quotedIdentifier(fld.name())).arg(mSchemaTableName)+" where "+sqlWhereClause;
}
- PGresult *rmax = PQexec(connection,(const char *)(sql.utf8()));
- QString maxValue = PQgetvalue(rmax,0,0);
+ PGresult *rmax = PQexec(connection, sql.toUtf8());
+ QString maxValue = QString::fromUtf8(PQgetvalue(rmax,0,0));
PQclear(rmax);
return maxValue.toDouble();
}
@@ -1612,12 +1634,12 @@
{
QString sql;
- sql = QString("select max(\"%1\") from %2")
- .arg(primaryKey)
+ sql = QString("select max(%1) from %2")
+ .arg(quotedIdentifier(primaryKey))
.arg(mSchemaTableName);
- PGresult *rmax = PQexec(connection,(const char *)(sql.utf8()));
- QString maxValue = PQgetvalue(rmax,0,0);
+ PGresult *rmax = PQexec(connection, sql.toUtf8());
+ QString maxValue = QString::fromUtf8(PQgetvalue(rmax,0,0));
PQclear(rmax);
return maxValue.toInt();
@@ -1628,203 +1650,6 @@
return valid;
}
-bool QgsPostgresProvider::addFeature(QgsFeature& f, int primaryKeyHighWater)
-{
- QgsDebugMsg("Entering.");
-
- // Determine which insertion method to use for WKB
- // PostGIS 1.0+ uses BYTEA
- // earlier versions use HEX
- bool useWkbHex(FALSE);
-
- if (!gotPostgisVersion)
- {
- postgisVersion(connection);
- }
-
- QgsDebugMsg("PostGIS version is major: " + QString::number(postgisVersionMajor) +
- ", minor: " + QString::number(postgisVersionMinor));
-
- if (postgisVersionMajor < 1)
- {
- useWkbHex = TRUE;
- }
-
- // Start building insert string
- QString insert("INSERT INTO ");
- insert+=mSchemaTableName;
- insert+=" (";
-
- // add the name of the geometry column to the insert statement
- insert += "\"" + geometryColumn;
-
- // add the name of the primary key column to the insert statement
- insert += "\",\"";
- insert += primaryKey + "\"";
-
- QgsDebugMsg("Constructing insert SQL, currently at: " + insert);
-
- //add the names of the other fields to the insert
- const QgsAttributeMap& attributevec = f.attributeMap();
-
- QgsDebugMsg("Got attribute map.");
-
- for(QgsAttributeMap::const_iterator it = attributevec.begin(); it != attributevec.end(); ++it)
- {
- QString fieldname;
- QgsFieldMap::const_iterator fit = attributeFields.find(it.key());
- if (fit != attributeFields.end())
- fieldname = fit->name();
-
- QgsDebugMsg("Checking field against: " + fieldname);
-
- if (
- (fieldname != "") &&
- (fieldname != geometryColumn) &&
- (fieldname != primaryKey) &&
- (!(it->isNull()))
- )
- {
- insert+=",\"";
- insert+=fieldname +"\"";
- }
- }
-
- insert+=") VALUES (GeomFromWKB('";
-
- // Add the WKB geometry to the INSERT statement
- QgsGeometry* geometry = f.geometry();
- unsigned char* geom = geometry->wkbBuffer();
- for (uint i=0; i < geometry->wkbSize(); ++i)
- {
- if (useWkbHex)
- {
- // PostGIS < 1.0 wants hex
- QString hex = QString::number((int) geom[i], 16).upper();
-
- if (hex.length() == 1)
- {
- hex = "0" + hex;
- }
-
- insert += hex;
- }
- else
- {
- // Postgis 1.0 wants bytea
- QString oct = QString::number((int) geom[i], 8);
-
- if(oct.length()==3)
- {
- oct="\\\\"+oct;
- }
- else if(oct.length()==1)
- {
- oct="\\\\00"+oct;
- }
- else if(oct.length()==2)
- {
- oct="\\\\0"+oct;
- }
-
- insert += oct;
- }
- }
-
- if (useWkbHex)
- {
- insert += "',"+srid+")";
- }
- else
- {
- insert += "::bytea',"+srid+")";
- }
-
- //add the primary key value to the insert statement
- insert += ",";
- insert += QString::number(primaryKeyHighWater);
-
- //add the field values to the insert statement
- for(QgsAttributeMap::const_iterator it=attributevec.begin();it!=attributevec.end();++it)
- {
- QString fieldname;
- QgsFieldMap::const_iterator fit = attributeFields.find(it.key());
- if (fit != attributeFields.end())
- fieldname = fit->name();
-
- QgsDebugMsg("Checking field name " + fieldname);
-
- if (
- (fieldname != "") &&
- (fieldname != geometryColumn) &&
- (fieldname != primaryKey) &&
- (!(it->isNull()))
- )
- {
- QString fieldvalue = it->toString();
- bool charactertype=false;
- insert+=",";
-
- QgsDebugMsg("Field is in layer with value " + fieldvalue);
-
- //add quotes if the field is a character or date type and not
- //the postgres provided default value
- if(fieldvalue != "NULL" && fieldvalue != getDefaultValue(it.key()).toString() )
- {
- if(it->type() == QVariant::String || it->type() == QVariant::Char)
- {
- charactertype=true;
- }
- }
-
- // important: escape quotes in field value
- fieldvalue.replace("'", "''");
-
- //request default value explicitly if fieldvalue is an empty string
- if(fieldvalue.isEmpty())
- {
- insert += "DEFAULT";
- }
- else
- {
- // XXX isn't it better to always escape field value?
- if(charactertype)
- {
- insert+="'";
- }
-
- insert+=fieldvalue;
-
- if(charactertype)
- {
- insert+="'";
- }
- }
- }
- }
-
- insert+=")";
- QgsDebugMsg("insert statement is: "+insert);
- qWarning("insert statement is: "+insert);
-
- //send INSERT statement and do error handling
- PGresult* result=PQexec(connection, (const char *)(insert.utf8()));
- if(result==0)
- {
- showMessageBox(tr("INSERT error"),tr("An error occured during feature insertion"));
- return false;
- }
- ExecStatusType message=PQresultStatus(result);
- if(message==PGRES_FATAL_ERROR)
- {
- showMessageBox(tr("INSERT error"),QString(PQresultErrorMessage(result)));
- return false;
- }
-
- QgsDebugMsg("Exiting with true.");
- return true;
-}
-
QVariant QgsPostgresProvider::getDefaultValue(int fieldId)
{
// Get the default column value from the Postgres information
@@ -1844,39 +1669,16 @@
QString defaultValue("");
- PGresult* result = PQexec(connection, (const char*)(sql.utf8()));
+ PGresult* result = PQexec(connection, sql.toUtf8());
if (PQntuples(result) == 1)
- defaultValue = PQgetvalue(result, 0, 0);
+ defaultValue = QString::fromUtf8(PQgetvalue(result, 0, 0));
PQclear(result);
return defaultValue;
}
-bool QgsPostgresProvider::deleteFeature(int id)
-{
- QString sql("DELETE FROM "+mSchemaTableName+" WHERE \""+primaryKey+"\" = "+QString::number(id));
-
- QgsDebugMsg("delete sql: "+sql);
-
- //send DELETE statement and do error handling
- PGresult* result=PQexec(connection, (const char *)(sql.utf8()));
- if(result==0)
- {
- showMessageBox(tr("DELETE error"),tr("An error occured during deletion from disk"));
- return false;
- }
- ExecStatusType message=PQresultStatus(result);
- if(message==PGRES_FATAL_ERROR)
- {
- showMessageBox(tr("DELETE error"),QString(PQresultErrorMessage(result)));
- return false;
- }
-
- return true;
-}
-
/**
* Check to see if GEOS is available
*/
@@ -1890,8 +1692,8 @@
/* Functions for determining available features in postGIS */
QString QgsPostgresProvider::postgisVersion(PGconn *connection)
{
- PGresult *result = PQexec(connection, "select postgis_version()");
- postgisVersionInfo = PQgetvalue(result,0,0);
+ PGresult *result = PQexec(connection, QString("select postgis_version()").toUtf8());
+ postgisVersionInfo = QString::fromUtf8(PQgetvalue(result,0,0));
QgsDebugMsg("PostGIS version info: " + postgisVersionInfo);
@@ -1912,40 +1714,169 @@
// parse out the capabilities and store them
QStringList geos = postgisParts.grep("GEOS");
- if(geos.size() == 1){
+ if(geos.size() == 1) {
geosAvailable = (geos[0].find("=1") > -1);
}
QStringList gist = postgisParts.grep("STATS");
- if(gist.size() == 1){
+ if(gist.size() == 1) {
gistAvailable = (geos[0].find("=1") > -1);
}
QStringList proj = postgisParts.grep("PROJ");
- if(proj.size() == 1){
+ if(proj.size() == 1) {
projAvailable = (proj[0].find("=1") > -1);
}
+ useWkbHex = postgisVersionMajor < 1;
+
gotPostgisVersion = TRUE;
return postgisVersionInfo;
}
+QByteArray QgsPostgresProvider::paramValue(QString fieldValue, const QString &defaultValue) const
+{
+ if( fieldValue=="NULL" )
+ return 0;
+
+ if( fieldValue==defaultValue && !defaultValue.isEmpty() )
+ {
+ PGresult *result = PQexec( connection, QString("select %1").arg(defaultValue).toUtf8() );
+ fieldValue = QString::fromUtf8(PQgetvalue(result,0,0));
+ PQclear(result);
+ }
+
+ return fieldValue.toUtf8();
+}
+
bool QgsPostgresProvider::addFeatures(QgsFeatureList & flist)
{
+ if( flist.size() == 0 )
+ return true;
+
bool returnvalue=true;
- PQexec(connection,"BEGIN");
- int primaryKeyHighWater = maxPrimaryKeyValue();
+ try {
+ PQexec(connection,QString("BEGIN").toUtf8());
- for(QgsFeatureList::iterator it=flist.begin();it!=flist.end();++it)
- {
- primaryKeyHighWater++;
- if(!addFeature(*it, primaryKeyHighWater))
+ // Prepare the INSERT statement
+ QString insert = QString("INSERT INTO %1(%2,%3")
+ .arg( mSchemaTableName )
+ .arg( quotedIdentifier(geometryColumn) )
+ .arg( quotedIdentifier(primaryKey) ),
+ values = QString(") VALUES (GeomFromWKB($1%1,%2),$2")
+ .arg( useWkbHex ? "" : "::bytea" )
+ .arg( srid );
+
+ const QgsAttributeMap &attributevec = flist[0].attributeMap();
+
+ QStringList defaultValue;
+ QList<int> fieldId;
+
+ // look for unique attribute values to place in statement instead of passing as parameter
+ // e.g. for defaults
+ for(QgsAttributeMap::const_iterator it = attributevec.begin(); it != attributevec.end(); it++)
{
- returnvalue=false;
- // TODO: exit loop here?
+ QgsFieldMap::const_iterator fit = attributeFields.find( it.key() );
+ if (fit == attributeFields.end() )
+ continue;
+
+ QString fieldname = fit->name();
+
+ QgsDebugMsg("Checking field against: " + fieldname);
+
+ if( fieldname.isEmpty() || fieldname==geometryColumn || fieldname==primaryKey || it->isNull() )
+ continue;
+
+ QString fieldvalue = it->toString();
+
+ int i;
+ for(i=1; i<flist.size(); i++)
+ {
+ const QgsAttributeMap &attributevec = flist[i].attributeMap();
+
+ QgsAttributeMap::const_iterator thisit = attributevec.find( it.key() );
+ if( thisit == attributevec.end() )
+ break;
+
+ if( thisit->toString() != fieldvalue )
+ break;
+ }
+
+ insert += "," + quotedIdentifier(fieldname);
+
+ QString defVal = getDefaultValue( it.key() ).toString();
+
+ if( i==flist.size() )
+ {
+ if( fieldvalue=="NULL" || (fieldvalue==defVal && !defVal.isEmpty()) )
+ {
+ values += "," + fieldvalue;
+ }
+ else
+ {
+ values += "," + quotedValue(fieldvalue);
+ }
+ }
+ else
+ {
+ // value is not unique => add parameter
+ values += QString(",$%1").arg( defaultValue.size()+3 );
+ defaultValue.append( defVal );
+ fieldId.append( it.key() );
+ }
}
+
+ insert += values + ")";
+
+ PGresult *stmt = PQprepare(connection, "addfeatures", insert.toUtf8(), fieldId.size()+2, NULL);
+ if(stmt==0 || PQresultStatus(stmt)==PGRES_FATAL_ERROR)
+ throw PGException(stmt);
+
+ int primaryKeyHighWater = maxPrimaryKeyValue();
+ const char **param = new const char *[ fieldId.size()+2 ];
+
+ for(QgsFeatureList::iterator features=flist.begin(); features!=flist.end(); features++)
+ {
+ const QgsAttributeMap &attributevec = features->attributeMap();
+
+ QString geomParam;
+ appendGeomString( features->geometry(), geomParam);
+
+ QList<QByteArray> qparam;
+
+ qparam.append( geomParam.toUtf8() );
+ qparam.append( QString("%1").arg( ++primaryKeyHighWater ).toUtf8() );
+
+ param[0] = qparam[0];
+ param[1] = qparam[1];
+
+ for(int i=0; i<fieldId.size(); i++)
+ {
+ qparam.append( paramValue( attributevec[ fieldId[i] ].toString(), defaultValue[i] ) );
+ param[i+2] = qparam[i+2];
+ }
+
+ PGresult *result = PQexecPrepared(connection, "addfeatures", fieldId.size()+2, param, NULL, NULL, 0);
+ if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
+ {
+ PQclear(stmt);
+ delete param;
+ throw PGException(result);
+ }
+
+ PQclear(result);
+ }
+
+ PQclear(stmt);
+ delete param;
+
+ PQexec(connection,QString("COMMIT").toUtf8());
+ } catch(PGException &e) {
+ e.showErrorMessage( tr("Error while adding features") );
+ PQexec(connection,QString("ROLLBACK").toUtf8());
+ returnvalue = false;
}
- PQexec(connection,"COMMIT");
+
reset();
return returnvalue;
}
@@ -1953,15 +1884,28 @@
bool QgsPostgresProvider::deleteFeatures(const QgsFeatureIds & id)
{
bool returnvalue=true;
- PQexec(connection,"BEGIN");
- for(QgsFeatureIds::const_iterator it=id.begin();it!=id.end();++it)
- {
- if(!deleteFeature(*it))
- {
- returnvalue=false;
+
+ try {
+ PQexec(connection,QString("BEGIN").toUtf8());
+
+ for(QgsFeatureIds::const_iterator it=id.begin();it!=id.end();++it) {
+ QString sql("DELETE FROM "+mSchemaTableName+" WHERE "+quotedIdentifier(primaryKey)+"="+QString::number(*it));
+
+ QgsDebugMsg("delete sql: "+sql);
+
+ //send DELETE statement and do error handling
+ PGresult* result=PQexec(connection, sql.toUtf8());
+ if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
+ throw PGException(result);
+ PQclear(result);
}
+
+ PQexec(connection,QString("COMMIT").toUtf8());
+ } catch(PGException &e) {
+ e.showErrorMessage( tr("Error while deleting features") );
+ PQexec(connection,QString("ROLLBACK").toUtf8());
+ returnvalue = false;
}
- PQexec(connection,"COMMIT");
reset();
return returnvalue;
}
@@ -1969,26 +1913,30 @@
bool QgsPostgresProvider::addAttributes(const QgsNewAttributesMap & name)
{
bool returnvalue=true;
- PQexec(connection,"BEGIN");
- for(QgsNewAttributesMap::const_iterator iter=name.begin();iter!=name.end();++iter)
- {
- QString sql="ALTER TABLE "+mSchemaTableName+" ADD COLUMN \""+iter.key()+"\" "+iter.value();
- QgsDebugMsg(sql);
+ try {
+ PQexec(connection,QString("BEGIN").toUtf8());
- //send sql statement and do error handling
- PGresult* result=PQexec(connection, (const char *)(sql.utf8()));
- if(result==0)
+ for(QgsNewAttributesMap::const_iterator iter=name.begin();iter!=name.end();++iter)
{
- returnvalue=false;
- ExecStatusType message=PQresultStatus(result);
- if(message==PGRES_FATAL_ERROR)
- {
- showMessageBox("ALTER TABLE error",QString(PQresultErrorMessage(result)));
- }
+ QString sql="ALTER TABLE "+mSchemaTableName+" ADD COLUMN "+quotedIdentifier(iter.key())+" " +iter.value();
+
+ QgsDebugMsg(sql);
+
+ //send sql statement and do error handling
+ PGresult* result=PQexec(connection, sql.toUtf8());
+ if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
+ throw PGException(result);
+ PQclear(result);
}
+
+ PQexec(connection,QString("COMMIT").toUtf8());
+ } catch(PGException &e) {
+ e.showErrorMessage( tr("Error while adding attributes") );
+ PQexec(connection,QString("ROLLBACK").toUtf8());
+ returnvalue = false;
}
- PQexec(connection,"COMMIT");
+
reset();
return returnvalue;
}
@@ -1996,208 +1944,149 @@
bool QgsPostgresProvider::deleteAttributes(const QgsAttributeIds& ids)
{
bool returnvalue=true;
- PQexec(connection,"BEGIN");
- for(QgsAttributeIds::const_iterator iter=ids.begin();iter != ids.end();++iter)
- {
- QgsFieldMap::const_iterator field_it = attributeFields.find(*iter);
- if(field_it == attributeFields.constEnd())
- {
- continue;
- }
- QString column = field_it->name();
- QString sql="ALTER TABLE "+mSchemaTableName+" DROP COLUMN \""+column+"\"";
+ try {
+ PQexec(connection,QString("BEGIN").toUtf8());
- //send sql statement and do error handling
- PGresult* result=PQexec(connection, (const char *)(sql.utf8()));
- if(result==0)
+ for(QgsAttributeIds::const_iterator iter=ids.begin();iter != ids.end();++iter)
{
- returnvalue=false;
- ExecStatusType message=PQresultStatus(result);
- if(message==PGRES_FATAL_ERROR)
- {
- showMessageBox("ALTER TABLE error",QString(PQresultErrorMessage(result)));
- }
- }
- else
- {
+ QgsFieldMap::const_iterator field_it = attributeFields.find(*iter);
+ if(field_it == attributeFields.constEnd())
+ continue;
+
+ QString column = field_it->name();
+ QString sql="ALTER TABLE "+mSchemaTableName+" DROP COLUMN "+quotedIdentifier(column);
+
+ //send sql statement and do error handling
+ PGresult* result=PQexec(connection, sql.toUtf8());
+ if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
+ throw PGException(result);
+ PQclear(result);
+
//delete the attribute from attributeFields
attributeFields.remove(*iter);
}
+
+ PQexec(connection,QString("COMMIT").toUtf8());
+ } catch(PGException &e) {
+ e.showErrorMessage( tr("Error while deleting attributes") );
+ PQexec(connection,QString("ROLLBACK").toUtf8());
+ returnvalue = false;
}
- PQexec(connection,"COMMIT");
+
reset();
return returnvalue;
}
bool QgsPostgresProvider::changeAttributeValues(const QgsChangedAttributesMap & attr_map)
{
- bool returnvalue=true;
- PQexec(connection,"BEGIN");
+ bool returnvalue=true;
- // cycle through the features
- for(QgsChangedAttributesMap::const_iterator iter=attr_map.begin();iter!=attr_map.end();++iter)
- {
- int fid = iter.key();
- const QgsAttributeMap& attrs = iter.value();
+ try {
+ PQexec(connection,QString("BEGIN").toUtf8());
- // cycle through the changed attributes of the feature
- for(QgsAttributeMap::const_iterator siter = attrs.begin(); siter != attrs.end(); ++siter)
+ // cycle through the features
+ for(QgsChangedAttributesMap::const_iterator iter=attr_map.begin();iter!=attr_map.end();++iter)
{
- QString val = siter->toString();
- QString fieldName = attributeFields[siter.key()].name();
+ int fid = iter.key();
+
+ // skip added features
+ if(fid<0)
+ continue;
- // escape quotes
- val.replace("'", "''");
+ const QgsAttributeMap& attrs = iter.value();
- QString sql="UPDATE "+mSchemaTableName+" SET \""+fieldName+"\"='"+val+"' WHERE \"" +primaryKey+"\"="+QString::number(fid);
- QgsDebugMsg(sql);
-
- // s end sql statement and do error handling
- // TODO: Make all error handling like this one
- PGresult* result=PQexec(connection, (const char *)(sql.utf8()));
- if (result==0)
+ // cycle through the changed attributes of the feature
+ for(QgsAttributeMap::const_iterator siter = attrs.begin(); siter != attrs.end(); ++siter)
{
- showMessageBox(tr("PostGIS error"),
- tr("An error occured contacting the PostgreSQL database"));
- return false;
- }
- ExecStatusType message=PQresultStatus(result);
- if(message==PGRES_FATAL_ERROR)
- {
- showMessageBox(tr("PostGIS error"),tr("The PostgreSQL database returned: ")
- + QString(PQresultErrorMessage(result))
- + "\n" + tr("When trying: ") + sql);
- return false;
- }
+ QString fieldName = attributeFields[siter.key()].name();
+ QString sql = QString("UPDATE %1 SET %2=%3 WHERE %4=%5")
+ .arg( mSchemaTableName )
+ .arg( quotedIdentifier(fieldName) )
+ .arg( quotedValue( siter->toString() ) )
+ .arg( quotedIdentifier(primaryKey) )
+ .arg( fid );
+ QgsDebugMsg(sql);
+
+ PGresult* result=PQexec(connection, sql.toUtf8());
+ if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
+ throw PGException(result);
+ PQclear(result);
+ }
}
+
+ PQexec(connection,QString("COMMIT").toUtf8());
+ } catch(PGException &e) {
+ e.showErrorMessage( tr("Error while changing attributes") );
+ PQexec(connection,QString("ROLLBACK").toUtf8());
+ returnvalue = false;
}
- PQexec(connection,"COMMIT");
+
reset();
+
return returnvalue;
}
+void QgsPostgresProvider::appendGeomString(QgsGeometry *geom, QString &geomString) const
+{
+ unsigned char *buf = geom->wkbBuffer();
+ for (uint i=0; i < geom->wkbSize(); ++i)
+ {
+ if (useWkbHex)
+ geomString += QString("%1").arg( (int) buf[i], 2, 16, QChar('0'));
+ else
+ geomString += QString("\\%1").arg( (int) buf[i], 3, 8, QChar('0'));
+ }
+}
+
bool QgsPostgresProvider::changeGeometryValues(QgsGeometryMap & geometry_map)
{
QgsDebugMsg("entering.");
bool returnvalue = true;
- // Determine which insertion method to use for WKB
- // PostGIS 1.0+ uses BYTEA
- // earlier versions use HEX
- bool useWkbHex(FALSE);
+ try {
+ // Start the PostGIS transaction
+ PQexec(connection,QString("BEGIN").toUtf8());
- if (!gotPostgisVersion)
- {
- postgisVersion(connection);
- }
-
- QgsDebugMsg("PostGIS version is major: " + QString::number(postgisVersionMajor) +
- ", minor: " + QString::number(postgisVersionMinor));
-
- if (postgisVersionMajor < 1)
- {
- useWkbHex = TRUE;
- }
-
- // Start the PostGIS transaction
-
- PQexec(connection,"BEGIN");
-
- for(QgsGeometryMap::iterator iter = geometry_map.begin();
+ for(QgsGeometryMap::iterator iter = geometry_map.begin();
iter != geometry_map.end();
++iter)
- {
-
- QgsDebugMsg("iterating over the map of changed geometries...");
-
- if (iter->wkbBuffer())
{
- QgsDebugMsg("iterating over feature id " + QString::number(iter.key()));
- QString sql = "UPDATE "+ mSchemaTableName +" SET \"" +
- geometryColumn + "\"=";
+ QgsDebugMsg("iterating over the map of changed geometries...");
- sql += "GeomFromWKB('";
-
- // Add the WKB geometry to the UPDATE statement
- unsigned char* geom = iter->wkbBuffer();
- for (uint i=0; i < iter->wkbSize(); ++i)
+ if (iter->wkbBuffer())
{
- if (useWkbHex)
- {
- // PostGIS < 1.0 wants hex
- QString hex = QString::number((int) geom[i], 16).upper();
+ QgsDebugMsg("iterating over feature id " + QString::number(iter.key()));
- if (hex.length() == 1)
- {
- hex = "0" + hex;
- }
+ QString sql = QString("UPDATE %1 SET %2=GeomFromWKB('")
+ .arg( mSchemaTableName )
+ .arg( quotedIdentifier(geometryColumn) );
+ appendGeomString(&*iter, sql);
+ sql += QString("'%1,%2) WHERE %3=%4")
+ .arg( useWkbHex ? "::bytea" : "" )
+ .arg( srid )
+ .arg( quotedIdentifier(primaryKey) )
+ .arg( iter.key() );
- sql += hex;
- }
- else
- {
- // Postgis 1.0 wants bytea
- QString oct = QString::number((int) geom[i], 8);
+ QgsDebugMsg("Updating with: " + sql);
- if(oct.length()==3)
- {
- oct="\\\\"+oct;
- }
- else if(oct.length()==1)
- {
- oct="\\\\00"+oct;
- }
- else if(oct.length()==2)
- {
- oct="\\\\0"+oct;
- }
+ PGresult* result=PQexec(connection, sql.toUtf8());
+ if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
+ throw PGException(result);
+ PQclear(result);
+ } // if (*iter)
+ } // for each feature
- sql += oct;
- }
- }
+ PQexec(connection,QString("COMMIT").toUtf8());
+ } catch(PGException &e) {
+ e.showErrorMessage( tr("Error while changing attributes") );
+ PQexec(connection,QString("ROLLBACK").toUtf8());
+ returnvalue = false;
+ }
- if (useWkbHex)
- {
- sql += "',"+srid+")";
- }
- else
- {
- sql += "::bytea',"+srid+")";
- }
-
- sql += " WHERE \"" +primaryKey+"\"="+QString::number(iter.key());
-
- QgsDebugMsg("Updating with: " + sql);
-
- // send sql statement and do error handling
- // TODO: Make all error handling like this one
- PGresult* result=PQexec(connection, (const char *)(sql.utf8()));
- if (result==0)
- {
- showMessageBox(tr("PostGIS error"), tr("An error occured contacting the PostgreSQL database"));
- return false;
- }
- ExecStatusType message=PQresultStatus(result);
- if(message==PGRES_FATAL_ERROR)
- {
- showMessageBox(tr("PostGIS error"), tr("The PostgreSQL database returned: ")
- + QString(PQresultErrorMessage(result))
- + "\n" + tr("When trying: ") + sql);
- return false;
- }
-
- } // if (*iter)
-
- } // for each feature
-
- PQexec(connection,"COMMIT");
-
- // TODO: Reset Geometry dirty if commit was OK
-
reset();
QgsDebugMsg("exiting.");
@@ -2218,15 +2107,7 @@
int QgsPostgresProvider::capabilities() const
{
- return (
- QgsVectorDataProvider::AddFeatures |
- QgsVectorDataProvider::DeleteFeatures |
- QgsVectorDataProvider::ChangeAttributeValues |
- QgsVectorDataProvider::AddAttributes |
- QgsVectorDataProvider::DeleteAttributes |
- QgsVectorDataProvider::ChangeGeometries |
- QgsVectorDataProvider::SelectGeometryAtId
- );
+ return enabledCapabilities;
}
void QgsPostgresProvider::setSubsetString(QString theSQL)
@@ -2264,12 +2145,12 @@
}
#endif
- PGresult *result = PQexec(connection, (const char *) (sql.utf8()));
+ PGresult *result = PQexec(connection, sql.toUtf8());
QgsDebugMsg("Approximate Number of features as text: " +
- QString(PQgetvalue(result, 0, 0)));
+ QString::fromUtf8(PQgetvalue(result, 0, 0)));
- numberFeatures = QString(PQgetvalue(result, 0, 0)).toLong();
+ numberFeatures = QString::fromUtf8(PQgetvalue(result, 0, 0)).toLong();
PQclear(result);
QgsDebugMsg("Approximate Number of features: " + QString::number(numberFeatures));
@@ -2285,7 +2166,7 @@
// get the approximate extent by retreiving the bounding box
// of the first few items with a geometry
- QString sql = "select box3d(" + geometryColumn + ") from "
+ QString sql = "select box3d(" + quotedIdentifier(geometryColumn) + ") from "
+ mSchemaTableName + " where ";
if(sqlWhereClause.length() > 0)
@@ -2293,20 +2174,20 @@
sql += "(" + sqlWhereClause + ") and ";
}
- sql += "not IsEmpty(" + geometryColumn + ") limit 5";
+ sql += "not IsEmpty(" + quotedIdentifier(geometryColumn) + ") limit 5";
#if WASTE_TIME
- sql = "select xmax(extent(\"" + geometryColumn + "\")) as xmax,"
- "xmin(extent(\"" + geometryColumn + "\")) as xmin,"
- "ymax(extent(\"" + geometryColumn + "\")) as ymax,"
- "ymin(extent(\"" + geometryColumn + "\")) as ymin"
+ sql = "select xmax(extent(" + quotedIdentifier(geometryColumn) + ")) as xmax,"
+ "xmin(extent(" + quotedIdentifier(geometryColumn) + ")) as xmin,"
+ "ymax(extent(" + quotedIdentifier(geometryColumn) + ")) as ymax,"
+ "ymin(extent(" + quotedIdentifier(geometryColumn) + ")) as ymin"
" from " + mSchemaTableName;
#endif
QgsDebugMsg("Getting approximate extent using: '" + sql + "'");
- PGresult *result = PQexec(connection, (const char *) (sql.utf8()));
+ PGresult *result = PQexec(connection, sql.toUtf8());
// TODO: Guard against the result having no rows
@@ -2338,7 +2219,7 @@
// get the extents
- QString sql = "select extent(\"" + geometryColumn + "\") from " +
+ QString sql = "select extent(" + quotedIdentifier(geometryColumn) + ") from " +
mSchemaTableName;
if(sqlWhereClause.length() > 0)
{
@@ -2346,16 +2227,16 @@
}
#if WASTE_TIME
- sql = "select xmax(extent(\"" + geometryColumn + "\")) as xmax,"
- "xmin(extent(\"" + geometryColumn + "\")) as xmin,"
- "ymax(extent(\"" + geometryColumn + "\")) as ymax,"
- "ymin(extent(\"" + geometryColumn + "\")) as ymin"
+ sql = "select xmax(extent(" + quotedIdentifier(geometryColumn) + ")) as xmax,"
+ "xmin(extent(" + quotedIdentifier(geometryColumn) + ")) as xmin,"
+ "ymax(extent(" + quotedIdentifier(geometryColumn) + ")) as ymax,"
+ "ymin(extent(" + quotedIdentifier(geometryColumn) + ")) as ymin"
" from " + mSchemaTableName;
#endif
QgsDebugMsg("Getting extents using schema.table: " + sql);
- PGresult *result = PQexec(connection, (const char *) (sql.utf8()));
+ PGresult *result = PQexec(connection, sql.toUtf8());
if(PQntuples(result)>0)
{
std::string box3d = PQgetvalue(result, 0, 0);
@@ -2473,28 +2354,26 @@
// version 7.4, binary cursors return data in XDR whereas previous versions
// return data in the endian of the server
- QString firstOid = "select oid from pg_class where relname = '" +
- mTableName + "' and relnamespace = (select oid from pg_namespace where nspname = '"
- + mSchemaName + "')";
- PGresult * oidResult = PQexec(connection, (const char*)(firstOid.utf8()));
+ QString firstOid = "select regclass('" + mSchemaTableName + "')::oid";
+ PGresult * oidResult = PQexec(connection, firstOid.toUtf8());
// get the int value from a "normal" select
- QString oidValue = PQgetvalue(oidResult,0,0);
+ QString oidValue = QString::fromUtf8(PQgetvalue(oidResult,0,0));
PQclear(oidResult);
QgsDebugMsg("Creating binary cursor");
// get the same value using a binary cursor
- PQexec(connection,"begin work");
- QString oidDeclare = QString("declare oidcursor binary cursor for select oid from pg_class where relname = '%1' and relnamespace = (select oid from pg_namespace where nspname = '%2')").arg(mTableName).arg(mSchemaName);
+ PQexec(connection,QString("begin work").toUtf8());
+ QString oidDeclare = "declare oidcursor binary cursor for select regclass('" + mSchemaTableName + "')::oid";
// set up the cursor
- PQexec(connection, (const char *)oidDeclare);
+ PQexec(connection, oidDeclare.toUtf8());
QString fetch = "fetch forward 1 from oidcursor";
QgsDebugMsg("Fetching a record and attempting to get check endian-ness");
- PGresult *fResult = PQexec(connection, (const char *)fetch);
- PQexec(connection, "end work");
+ PGresult *fResult = PQexec(connection, fetch.toUtf8());
+ PQexec(connection, QString("end work").toUtf8());
swapEndian = true;
if(PQntuples(fResult) > 0){
// get the oid value from the binary cursor
@@ -2531,8 +2410,8 @@
if (PQntuples(result) > 0)
{
- srid = PQgetvalue(result, 0, PQfnumber(result, "srid"));
- fType = PQgetvalue(result, 0, PQfnumber(result, "type"));
+ srid = QString::fromUtf8(PQgetvalue(result, 0, PQfnumber(result, QString("srid").toUtf8())));
+ fType = QString::fromUtf8(PQgetvalue(result, 0, PQfnumber(result, QString("type").toUtf8())));
PQclear(result);
}
else
@@ -2542,8 +2421,8 @@
// fail if there is no data in the relevant table.
PQclear(result); // for the query just before the if() statement
sql = "select "
- "srid(\"" + geometryColumn + "\"), "
- "geometrytype(\"" + geometryColumn + "\") from " +
+ "srid(" + quotedIdentifier(geometryColumn) + "), "
+ "geometrytype(" + quotedIdentifier(geometryColumn) + ") from " +
mSchemaTableName;
//it is possible that the where clause restricts the feature type
@@ -2559,8 +2438,8 @@
if (PQntuples(result) > 0)
{
- srid = PQgetvalue(result, 0, PQfnumber(result, "srid"));
- fType = PQgetvalue(result, 0, PQfnumber(result, "geometrytype"));
+ srid = QString::fromUtf8(PQgetvalue(result, 0, PQfnumber(result, QString("srid").toUtf8())));
+ fType = QString::fromUtf8(PQgetvalue(result, 0, PQfnumber(result, QString("geometrytype").toUtf8())));
}
PQclear(result);
}
@@ -2577,7 +2456,7 @@
" when geometrytype(%1) IN ('LINESTRING','MULTILINESTRING') THEN 'LINESTRING'"
" when geometrytype(%1) IN ('POLYGON','MULTIPOLYGON') THEN 'POLYGON'"
" end "
- "from %2").arg(geometryColumn).arg(mSchemaTableName);
+ "from %2").arg(quotedIdentifier(geometryColumn)).arg(mSchemaTableName);
if(mUri.sql()!="")
sql += " where " + mUri.sql();
@@ -2585,7 +2464,7 @@
if (PQntuples(result)==1)
{
- fType = PQgetvalue(result, 0, 0);
+ fType = QString::fromUtf8(PQgetvalue(result, 0, 0));
}
PQclear(result);
}
@@ -2649,18 +2528,31 @@
PGresult* QgsPostgresProvider::executeDbCommand(PGconn* connection,
const QString& sql)
{
- PGresult *result = PQexec(connection, (const char *) (sql.utf8()));
+ PGresult *result = PQexec(connection, sql.toUtf8());
QgsDebugMsg("Executed SQL: " + sql);
if (PQresultStatus(result) == PGRES_TUPLES_OK) {
QgsDebugMsg("Command was successful.");
} else {
QgsDebugMsg("Command was unsuccessful. The error message was: "
- + QString( PQresultErrorMessage(result) ) );
+ + QString::fromUtf8( PQresultErrorMessage(result) ) );
}
return result;
}
+QString QgsPostgresProvider::quotedIdentifier( QString ident )
+{
+ ident.replace('"', "\"\"");
+ return ident.prepend("\"").append("\"");
+}
+
+QString QgsPostgresProvider::quotedValue( QString value )
+{
+ // FIXME: use PQescapeStringConn
+ value.replace("'", "''");
+ return value.prepend("'").append("'");
+}
+
void QgsPostgresProvider::showMessageBox(const QString& title,
const QString& text)
{
@@ -2747,8 +2639,7 @@
* Required isProvider function. Used to determine if this shared library
* is a data provider plugin
*/
-QGISEXTERN bool isProvider(){
+QGISEXTERN bool isProvider()
+{
return true;
}
-
-QMap<QString, QgsPostgresProvider::Conn *> QgsPostgresProvider::connections;
Modified: trunk/qgis/src/providers/postgres/qgspostgresprovider.h
===================================================================
--- trunk/qgis/src/providers/postgres/qgspostgresprovider.h 2008-03-12 20:44:31 UTC (rev 8212)
+++ trunk/qgis/src/providers/postgres/qgspostgresprovider.h 2008-03-12 21:02:40 UTC (rev 8213)
@@ -327,6 +327,15 @@
void repaintRequested();
private:
+
+ /** Double quote a PostgreSQL identifier for placement in a SQL string.
+ */
+ QString quotedIdentifier( QString ident );
+
+ /** Quote a value for placement in a SQL string.
+ */
+ QString quotedValue( QString value );
+
/** Load the field list
*/
void loadFields();
@@ -445,8 +454,8 @@
// Produces a QMessageBox with the given title and text. Doesn't
// return until the user has dismissed the dialog box.
- void showMessageBox(const QString& title, const QString& text);
- void showMessageBox(const QString& title, const QStringList& text);
+ static void showMessageBox(const QString& title, const QString& text);
+ static void showMessageBox(const QString& title, const QStringList& text);
// A simple class to store the rows of the sql executed in the
// findColumns() function.
@@ -465,14 +474,44 @@
QString column_type;
};
+ struct PGException {
+ PGException(PGresult *r) : result(r)
+ {
+ }
+ PGException(const PGException &e) : result(e.result)
+ {
+ }
+
+ ~PGException()
+ {
+ if(result)
+ PQclear(result);
+ }
+
+ QString errorMessage() const
+ {
+ return result ?
+ QString::fromUtf8(PQresultErrorMessage(result)) :
+ tr("unexpected PostgreSQL error");
+ }
+
+ void showErrorMessage(QString title) const
+ {
+ showMessageBox(title, errorMessage() );
+ }
+
+ private:
+ PGresult *result;
+ };
+
// A simple class to store four strings
class SRC
{
public:
SRC() {};
SRC(QString s, QString r, QString c, QString t) :
- schema(s), relation(r), column(c), type(t) {};
+ schema(s), relation(r), column(c), type(t) {};
QString schema, relation, column, type;
};
@@ -529,6 +568,8 @@
//! PROJ4 capability
bool projAvailable;
+ int enabledCapabilities;
+
/**Returns the maximum value of the primary key attribute
@note You should run this inside of a PostgreSQL transaction
so that you can safely increment the value returned for
@@ -536,13 +577,6 @@
*/
int maxPrimaryKeyValue();
- /** Writes a single feature
- @param primaryKeyHighWater is the recommended value of the primary key for this new feature. */
- bool addFeature(QgsFeature& f, int primaryKeyHighWater);
-
- /**Deletes a feature*/
- bool deleteFeature(int id);
-
//! Get the feature count based on the where clause
long getFeatureCount();
@@ -552,22 +586,15 @@
/**
* Event sink for events from threads
*/
- void customEvent ( QCustomEvent * e );
+ void customEvent ( QCustomEvent *e );
-private:
- struct Conn {
- Conn(PGconn *connection) : ref(1), conn(connection) {}
-
- int ref;
- PGconn *conn;
- };
-
- PGconn *connectDb(const char *conninfo);
+ PGconn *connectDb(const QString &conninfo);
void disconnectDb();
- static QMap<QString, Conn *> connections;
- static int providerIds;
- QString providerId;
+ bool useWkbHex;
+
+ void appendGeomString(QgsGeometry *geom, QString &geomParam) const;
+ QByteArray paramValue(QString fieldvalue, const QString &defaultValue) const;
};
#endif
More information about the QGIS-commit
mailing list