Index: src/app/qgspgquerybuilder.cpp =================================================================== --- src/app/qgspgquerybuilder.cpp (revision 8182) +++ src/app/qgspgquerybuilder.cpp (working copy) @@ -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 %1 in database %2 on host %3, user %4")) @@ -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().find("char") > -1 || field.typeName().find("text") > -1 ; // 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("

Failed to get sample of field values using SQL:

") + theSQL + "

Error message was: "+ QString(PQerrorMessage(mPgConnection)) + "

"); + QMessageBox::warning(this, tr("Database error"), tr("

Failed to get sample of field values using SQL:

") + theSQL + "

Error message was: "+ QString::fromUtf8(PQerrorMessage(mPgConnection)) + "

"); } // 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 Index: src/app/qgsnewconnection.cpp =================================================================== --- src/app/qgsnewconnection.cpp (revision 8182) +++ src/app/qgsnewconnection.cpp (working copy) @@ -130,7 +130,14 @@ settings.writeEntry(baseKey + "/database", txtDatabase->text()); settings.writeEntry(baseKey + "/port", txtPort->text()); settings.writeEntry(baseKey + "/username", txtUsername->text()); - settings.writeEntry(baseKey + "/password", txtPassword->text()); + if (chkStorePassword->isChecked()) + { + settings.writeEntry(baseKey + "/password", txtPassword->text()); + } + else + { + settings.writeEntry(baseKey + "/password", ""); + } settings.writeEntry(baseKey + "/publicOnly", cb_publicSchemaOnly->isChecked()); settings.writeEntry(baseKey + "/geometryColumnsOnly", cb_geometryColumnsOnly->isChecked()); if (chkStorePassword->isChecked()) Index: src/app/qgsdbsourceselect.cpp =================================================================== --- src/app/qgsdbsourceselect.cpp (revision 8182) +++ src/app/qgsdbsourceselect.cpp (working copy) @@ -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 connections; Index: src/providers/postgres/qgspostgresprovider.cpp =================================================================== --- src/providers/postgres/qgspostgresprovider.cpp (revision 8182) +++ src/providers/postgres/qgspostgresprovider.cpp (working copy) @@ -103,7 +103,7 @@ //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; @@ -114,13 +114,13 @@ // 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())); + 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,10 +129,10 @@ } PQclear(testAccess); - PGresult *schema = PQexec(connection, "SELECT current_schema()"); + PGresult *schema = PQexec(connection, QString("SELECT current_schema()").toUtf8()); if (PQresultStatus(schema) == PGRES_TUPLES_OK) { - mCurrentSchema = PQgetvalue(schema, 0, 0); + mCurrentSchema = QString::fromUtf8(PQgetvalue(schema, 0, 0)); if(mCurrentSchema==mSchemaName) { mUri.clearSchema(); setDataSourceUri( mUri.uri() ); @@ -167,7 +167,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,7 +241,7 @@ //pLog.flush(); } -PGconn *QgsPostgresProvider::connectDb(const char *conninfo) +PGconn *QgsPostgresProvider::connectDb(const QString & conninfo) { if( connections.contains(conninfo) ) { @@ -252,7 +252,7 @@ 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 +263,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) { @@ -338,7 +338,7 @@ 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,15 +353,16 @@ { 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,quoteIdentifier(primaryKey).toUtf8())); if (swapEndian) oid = ntohl(oid); // convert oid to opposite endian @@ -383,12 +384,14 @@ } else { - char* attribute = PQgetvalue(queryResult, row, PQfnumber(queryResult,"\""+*name_it+"\"")); - val = QString::fromUtf8(attribute); + val = QString::fromUtf8(PQgetvalue(queryResult, row, PQfnumber(queryResult,quoteIdentifier(*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,7 +414,7 @@ { 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 @@ -424,7 +427,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)"); } @@ -477,17 +480,17 @@ } } - QString declare = "declare qgisf" + providerId + " binary cursor for select \"" + primaryKey + "\""; + QString declare = "declare qgisf" + providerId + " binary cursor for select " + quoteIdentifier(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(quoteIdentifier(geometryColumn)).arg(endianString()); } for(std::list::const_iterator it = mFetchAttributeNames.begin(); it != mFetchAttributeNames.end(); ++it) { if( (*it) != primaryKey) //no need to fetch primary key again { - declare += ",\"" + *it + "\"::text"; + declare += "," + quoteIdentifier(*it) + "::text"; } } @@ -504,12 +507,12 @@ { // Contributed by #qgis irc "creeping" // This version actually invokes PostGIS's use of spatial indexes - declare += " where " + geometryColumn; + declare += " where " + quoteIdentifier(geometryColumn); declare += " && setsrid('BOX3D(" + rect.asWKTCoords(); declare += ")'::box3d,"; declare += srid; declare += ")"; - declare += " and intersects(" + geometryColumn; + declare += " and intersects(" + quoteIdentifier(geometryColumn); declare += ", setsrid('BOX3D(" + rect.asWKTCoords(); declare += ")'::box3d,"; declare += srid; @@ -517,7 +520,7 @@ } else { - declare += " where " + geometryColumn; + declare += " where " + quoteIdentifier(geometryColumn); declare += " && setsrid('BOX3D(" + rect.asWKTCoords(); declare += ")'::box3d,"; declare += srid; @@ -540,11 +543,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 +561,6 @@ bool fetchGeometry, QgsAttributeList fetchAttributes) { - std::list attributeNames; QgsFieldMap fldMap = fields(); QgsFieldMap::const_iterator fieldIt; @@ -574,43 +576,44 @@ } } - QString sql = "declare qgisfid" + providerId + " binary cursor for select \"" + primaryKey + "\""; + QString sql = "declare qgisfid" + providerId + " binary cursor for select " + quoteIdentifier(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(quoteIdentifier(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 += "," + quoteIdentifier(*namesIt) + "::text"; } } sql += " " + QString("from %1").arg(mSchemaTableName); - sql += " where " + primaryKey + " = " + QString::number(featureId); + sql += " where " + quoteIdentifier(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, ("fetch forward 1 from qgisfid" + providerId).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,quoteIdentifier(primaryKey).toUtf8())); if (swapEndian) oid = ntohl(oid); // convert oid to opposite endian feature.setFeatureId(oid); @@ -627,12 +630,14 @@ } else { - char* attribute = PQgetvalue(res, 0, PQfnumber(res,*namesIt)); - val = QString::fromUtf8(attribute); + val = QString::fromUtf8(PQgetvalue(res, 0, PQfnumber(res,quoteIdentifier(*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 +660,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; } @@ -721,7 +727,7 @@ void QgsPostgresProvider::reset() { QString move = "move 0 in qgisf" + providerId; //move cursor to first record - PQexec(connection, (const char *)(move.utf8())); + PQexec(connection, move.toUtf8()); mFeatureQueue.empty(); loadFields(); } @@ -747,25 +753,24 @@ 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('" + 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 @@ -773,32 +778,33 @@ 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); + 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,7 +813,9 @@ 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) @@ -826,10 +834,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('" + mSchemaTableName + "')::oid" QgsDebugMsg("Getting unique index using '" + sql + "'"); @@ -849,11 +855,10 @@ // 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('" + 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 +869,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('" + mSchemaTableName + "')"; + PGresult* oidCheck = executeDbCommand(connection, sql); if (PQntuples(oidCheck) != 0) @@ -909,22 +913,20 @@ std::vector > 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('" + 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 +948,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('" + mSchemaTableName + "')::oid"; PGresult* types = executeDbCommand(connection, sql); QString colNames; int numCols = PQntuples(types); @@ -956,7 +956,7 @@ { if (j == numCols-1) colNames += tr("and "); - colNames += "'" + QString(PQgetvalue(types, j, 0)) + colNames += "'" + QString::fromUtf8(PQgetvalue(types, j, 0)) + (j < numCols-2 ? "', " : "' "); } @@ -982,9 +982,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 +1049,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('" + quoteIdentifier(schemaName) + "." + quoteIdentifier(tableName) + "')::oid"; + PGresult* result = PQexec(connection, sql.toUtf8()); QString rel_oid; if (PQntuples(result) == 1) { @@ -1086,7 +1082,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 +1141,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 +1222,13 @@ bool isUnique = false; - QString sql = "select count(distinct \"" + colName + "\") = count(\"" + - colName + "\") from \"" + schemaName + "\".\"" + tableName + "\""; + QString sql = "select count(distinct " + quoteIdentifier(colName) + ") = count(" + quoteIdentifier(colName) + ") from " + quoteIdentifier(schemaName) + "." + quoteIdentifier(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 +1239,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 +1259,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 +1287,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 +1308,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 +1330,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 +1576,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(quoteIdentifier(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(quoteIdentifier(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 +1597,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(quoteIdentifier(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(quoteIdentifier(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 +1614,12 @@ { QString sql; - sql = QString("select max(\"%1\") from %2") - .arg(primaryKey) + sql = QString("select max(%1) from %2") + .arg(quoteIdentifier(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(); @@ -1656,11 +1658,11 @@ insert+=" ("; // add the name of the geometry column to the insert statement - insert += "\"" + geometryColumn; + insert += quoteIdentifier(geometryColumn); // add the name of the primary key column to the insert statement - insert += "\",\""; - insert += primaryKey + "\""; + insert += ","; + insert += quoteIdentifier(primaryKey); QgsDebugMsg("Constructing insert SQL, currently at: " + insert); @@ -1685,8 +1687,8 @@ (!(it->isNull())) ) { - insert+=",\""; - insert+=fieldname +"\""; + insert+=","; + insert+=quoteIdentifier(fieldname); } } @@ -1777,8 +1779,6 @@ } } - // important: escape quotes in field value - fieldvalue.replace("'", "''"); //request default value explicitly if fieldvalue is an empty string if(fieldvalue.isEmpty()) @@ -1790,6 +1790,7 @@ // XXX isn't it better to always escape field value? if(charactertype) { + fieldvalue.replace("'", "''"); // escape quotes on text type fields; needs more work as other characters like '\' may need it as well; really should use PQescapeStringConn() insert+="'"; } @@ -1808,7 +1809,7 @@ qWarning("insert statement is: "+insert); //send INSERT statement and do error handling - PGresult* result=PQexec(connection, (const char *)(insert.utf8())); + PGresult* result=PQexec(connection, insert.toUtf8()); if(result==0) { showMessageBox(tr("INSERT error"),tr("An error occured during feature insertion")); @@ -1817,7 +1818,7 @@ ExecStatusType message=PQresultStatus(result); if(message==PGRES_FATAL_ERROR) { - showMessageBox(tr("INSERT error"),QString(PQresultErrorMessage(result))); + showMessageBox(tr("INSERT error"),QString::fromUtf8(PQresultErrorMessage(result))); return false; } @@ -1844,10 +1845,10 @@ 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); @@ -1856,12 +1857,12 @@ bool QgsPostgresProvider::deleteFeature(int id) { - QString sql("DELETE FROM "+mSchemaTableName+" WHERE \""+primaryKey+"\" = "+QString::number(id)); + QString sql("DELETE FROM "+mSchemaTableName+" WHERE "+quoteIdentifier(primaryKey)+" = "+QString::number(id)); QgsDebugMsg("delete sql: "+sql); //send DELETE statement and do error handling - PGresult* result=PQexec(connection, (const char *)(sql.utf8())); + PGresult* result=PQexec(connection, sql.toUtf8()); if(result==0) { showMessageBox(tr("DELETE error"),tr("An error occured during deletion from disk")); @@ -1870,7 +1871,7 @@ ExecStatusType message=PQresultStatus(result); if(message==PGRES_FATAL_ERROR) { - showMessageBox(tr("DELETE error"),QString(PQresultErrorMessage(result))); + showMessageBox(tr("DELETE error"),QString::fromUtf8(PQresultErrorMessage(result))); return false; } @@ -1890,8 +1891,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); @@ -1932,7 +1933,7 @@ bool QgsPostgresProvider::addFeatures(QgsFeatureList & flist) { bool returnvalue=true; - PQexec(connection,"BEGIN"); + PQexec(connection,QString("BEGIN").toUtf8()); int primaryKeyHighWater = maxPrimaryKeyValue(); @@ -1945,7 +1946,7 @@ // TODO: exit loop here? } } - PQexec(connection,"COMMIT"); + PQexec(connection,QString("COMMIT").toUtf8()); reset(); return returnvalue; } @@ -1953,7 +1954,7 @@ bool QgsPostgresProvider::deleteFeatures(const QgsFeatureIds & id) { bool returnvalue=true; - PQexec(connection,"BEGIN"); + PQexec(connection,QString("BEGIN").toUtf8()); for(QgsFeatureIds::const_iterator it=id.begin();it!=id.end();++it) { if(!deleteFeature(*it)) @@ -1961,7 +1962,7 @@ returnvalue=false; } } - PQexec(connection,"COMMIT"); + PQexec(connection,QString("COMMIT").toUtf8()); reset(); return returnvalue; } @@ -1969,26 +1970,33 @@ bool QgsPostgresProvider::addAttributes(const QgsNewAttributesMap & name) { bool returnvalue=true; - PQexec(connection,"BEGIN"); + PQexec(connection,QString("BEGIN").toUtf8()); + for(QgsNewAttributesMap::const_iterator iter=name.begin();iter!=name.end();++iter) { - QString sql="ALTER TABLE "+mSchemaTableName+" ADD COLUMN \""+iter.key()+"\" "+iter.value(); + QString sql="ALTER TABLE "+mSchemaTableName+" ADD COLUMN "+quoteIdentifier(iter.key())+" " +iter.value(); QgsDebugMsg(sql); //send sql statement and do error handling - PGresult* result=PQexec(connection, (const char *)(sql.utf8())); + PGresult* result=PQexec(connection, sql.toUtf8()); if(result==0) { + // this condition is unlikely to occur; no message box is displayed returnvalue=false; + } + else + { ExecStatusType message=PQresultStatus(result); if(message==PGRES_FATAL_ERROR) { - showMessageBox("ALTER TABLE error",QString(PQresultErrorMessage(result))); + showMessageBox("ALTER TABLE error",QString::fromUtf8(PQresultErrorMessage(result))); + returnvalue=false; } } + if (false==returnvalue) break; //break out of for loop on error } - PQexec(connection,"COMMIT"); + PQexec(connection,QString("COMMIT").toUtf8()); reset(); return returnvalue; } @@ -1996,7 +2004,7 @@ bool QgsPostgresProvider::deleteAttributes(const QgsAttributeIds& ids) { bool returnvalue=true; - PQexec(connection,"BEGIN"); + PQexec(connection,QString("BEGIN").toUtf8()); for(QgsAttributeIds::const_iterator iter=ids.begin();iter != ids.end();++iter) { @@ -2006,26 +2014,32 @@ continue; } QString column = field_it->name(); - QString sql="ALTER TABLE "+mSchemaTableName+" DROP COLUMN \""+column+"\""; + QString sql="ALTER TABLE "+mSchemaTableName+" DROP COLUMN "+quoteIdentifier(column); //send sql statement and do error handling - PGresult* result=PQexec(connection, (const char *)(sql.utf8())); + PGresult* result=PQexec(connection, sql.toUtf8()); if(result==0) { + // this condition is unlikely to occur; no message box is displayed returnvalue=false; + } + else + { ExecStatusType message=PQresultStatus(result); if(message==PGRES_FATAL_ERROR) { - showMessageBox("ALTER TABLE error",QString(PQresultErrorMessage(result))); + showMessageBox("ALTER TABLE error",QString::fromUtf8(PQresultErrorMessage(result))); + returnvalue=false; } - } - else - { + else + { //delete the attribute from attributeFields attributeFields.remove(*iter); + } } + if (false==returnvalue) break; //break out of for loop on error } - PQexec(connection,"COMMIT"); + PQexec(connection,QString("COMMIT").toUtf8()); reset(); return returnvalue; } @@ -2033,7 +2047,7 @@ bool QgsPostgresProvider::changeAttributeValues(const QgsChangedAttributesMap & attr_map) { bool returnvalue=true; - PQexec(connection,"BEGIN"); + PQexec(connection,QString("BEGIN").toUtf8()); // cycle through the features for(QgsChangedAttributesMap::const_iterator iter=attr_map.begin();iter!=attr_map.end();++iter) @@ -2050,12 +2064,12 @@ // escape quotes val.replace("'", "''"); - QString sql="UPDATE "+mSchemaTableName+" SET \""+fieldName+"\"='"+val+"' WHERE \"" +primaryKey+"\"="+QString::number(fid); + QString sql="UPDATE "+mSchemaTableName+" SET "+quoteIdentifier(fieldName)+"='"+val+"' WHERE " +quoteIdentifier(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())); + PGresult* result=PQexec(connection, sql.toUtf8()); if (result==0) { showMessageBox(tr("PostGIS error"), @@ -2066,14 +2080,14 @@ if(message==PGRES_FATAL_ERROR) { showMessageBox(tr("PostGIS error"),tr("The PostgreSQL database returned: ") - + QString(PQresultErrorMessage(result)) + + QString::fromUtf8(PQresultErrorMessage(result)) + "\n" + tr("When trying: ") + sql); return false; } } } - PQexec(connection,"COMMIT"); + PQexec(connection,QString("COMMIT").toUtf8()); reset(); return returnvalue; } @@ -2104,7 +2118,7 @@ // Start the PostGIS transaction - PQexec(connection,"BEGIN"); + PQexec(connection,QString("BEGIN").toUtf8()); for(QgsGeometryMap::iterator iter = geometry_map.begin(); iter != geometry_map.end(); @@ -2117,8 +2131,8 @@ { QgsDebugMsg("iterating over feature id " + QString::number(iter.key())); - QString sql = "UPDATE "+ mSchemaTableName +" SET \"" + - geometryColumn + "\"="; + QString sql = "UPDATE "+ mSchemaTableName +" SET " + + quoteIdentifier(geometryColumn) + "="; sql += "GeomFromWKB('"; @@ -2169,13 +2183,13 @@ sql += "::bytea',"+srid+")"; } - sql += " WHERE \"" +primaryKey+"\"="+QString::number(iter.key()); + sql += " WHERE " +quoteIdentifier(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())); + PGresult* result=PQexec(connection, sql.toUtf8()); if (result==0) { showMessageBox(tr("PostGIS error"), tr("An error occured contacting the PostgreSQL database")); @@ -2185,7 +2199,7 @@ if(message==PGRES_FATAL_ERROR) { showMessageBox(tr("PostGIS error"), tr("The PostgreSQL database returned: ") - + QString(PQresultErrorMessage(result)) + + QString::fromUtf8(PQresultErrorMessage(result)) + "\n" + tr("When trying: ") + sql); return false; } @@ -2194,7 +2208,7 @@ } // for each feature - PQexec(connection,"COMMIT"); + PQexec(connection,QString("COMMIT").toUtf8()); // TODO: Reset Geometry dirty if commit was OK @@ -2264,12 +2278,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 +2299,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(" + quoteIdentifier(geometryColumn) + ") from " + mSchemaTableName + " where "; if(sqlWhereClause.length() > 0) @@ -2293,20 +2307,20 @@ sql += "(" + sqlWhereClause + ") and "; } - sql += "not IsEmpty(" + geometryColumn + ") limit 5"; + sql += "not IsEmpty(" + quoteIdentifier(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(" + quoteIdentifier(geometryColumn) + ")) as xmax," + "xmin(extent(" + quoteIdentifier(geometryColumn) + ")) as xmin," + "ymax(extent(" + quoteIdentifier(geometryColumn) + ")) as ymax," + "ymin(extent(" + quoteIdentifier(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 +2352,7 @@ // get the extents - QString sql = "select extent(\"" + geometryColumn + "\") from " + + QString sql = "select extent(" + quoteIdentifier(geometryColumn) + ") from " + mSchemaTableName; if(sqlWhereClause.length() > 0) { @@ -2346,16 +2360,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(" + quoteIdentifier(geometryColumn) + ")) as xmax," + "xmin(extent(" + quoteIdentifier(geometryColumn) + ")) as xmin," + "ymax(extent(" + quoteIdentifier(geometryColumn) + ")) as ymax," + "ymin(extent(" + quoteIdentifier(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 +2487,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 +2543,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 +2554,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(" + quoteIdentifier(geometryColumn) + "), " + "geometrytype(" + quoteIdentifier(geometryColumn) + ") from " + mSchemaTableName; //it is possible that the where clause restricts the feature type @@ -2559,8 +2571,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 +2589,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(quoteIdentifier(geometryColumn)).arg(mSchemaTableName); if(mUri.sql()!="") sql += " where " + mUri.sql(); @@ -2585,7 +2597,7 @@ if (PQntuples(result)==1) { - fType = PQgetvalue(result, 0, 0); + fType = QString::fromUtf8(PQgetvalue(result, 0, 0)); } PQclear(result); } @@ -2649,18 +2661,23 @@ 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::quoteIdentifier( const QString &ident ) +{ + return QString( ident ).prepend("\"").append("\""); +} // QgsPostgresProvider::quoteIdentifier( const QString &ident ) + void QgsPostgresProvider::showMessageBox(const QString& title, const QString& text) {