patch.diff

patch - Giuseppe Sucameli, 2010-04-19 04:58 AM

Download (43.4 KB)

View differences:

src/providers/postgres/qgspostgresprovider.h (working copy)
333 333

  
334 334
    QString whereClause( int featureId ) const;
335 335

  
336
    bool checkPermsAndCapabilities();
337

  
336 338
    const QgsField &field( int index ) const;
337 339

  
338 340
    /** Double quote a PostgreSQL identifier for placement in a SQL string.
......
383 385
     * Flag indicating if the layer data source is a valid PostgreSQL layer
384 386
     */
385 387
    bool valid;
388

  
389
    bool isCustomQuery;
390

  
386 391
    /**
387 392
     * Name of the table with no schema
388 393
     */
......
403 408
     * SQL statement used to limit the features retrieved
404 409
     */
405 410
    QString sqlWhereClause;
411

  
412
    QString sqlCustomSelect;
406 413
    /**
407 414
     * Primary key column for fetching features. If there is no primary key
408 415
     * the oid is used to fetch features.
src/providers/postgres/qgspostgresprovider.cpp (working copy)
81 81
  mSchemaName = mUri.schema();
82 82
  mTableName = mUri.table();
83 83
  geometryColumn = mUri.geometryColumn();
84
  sqlWhereClause = mUri.sql();
85 84
  primaryKey = mUri.keyColumn();
86 85
  mUseEstimatedMetadata = mUri.useEstimatedMetadata();
87 86

  
88
  // Keep a schema qualified table name for convenience later on.
89
  mSchemaTableName = mUri.quotedTablename();
87
  if ( mSchemaName.isEmpty() && mTableName.isEmpty() )
88
  {
89
    isCustomQuery = true;
90
    sqlCustomSelect = mUri.sql();
91
    sqlCustomSelect.remove( QRegExp( "\\;.*") );
90 92

  
93
    sqlWhereClause = QString();
94
  }
95
  else
96
  {
97
    isCustomQuery = false;
98
    sqlWhereClause = mUri.sql();
99

  
100
    // Keep a schema qualified table name for convenience later on.
101
    mSchemaTableName = mUri.quotedTablename();
102
  }
103

  
91 104
  QgsDebugMsg( "Table name is " + mTableName );
92
  QgsDebugMsg( "SQL is " + sqlWhereClause );
105
  QgsDebugMsg( "SQL is " + !isCustomQuery ? sqlWhereClause : sqlCustomSelect );
93 106
  QgsDebugMsg( "Connection info is " + mUri.connectionInfo() );
94 107

  
95 108
  QgsDebugMsg( "Geometry column is: " + geometryColumn );
......
104 117
    return;
105 118
  }
106 119

  
107
  QgsDebugMsg( "Checking for permissions on the relation" );
108

  
109
  // Check that we can read from the table (i.e., we have
110
  // select permission).
111
  QString sql = QString( "select * from %1 limit 1" ).arg( mSchemaTableName );
112
  Result testAccess = connectionRO->PQexec( sql );
113
  if ( PQresultStatus( testAccess ) != PGRES_TUPLES_OK )
120
  if ( !checkPermsAndCapabilities() ) // check permissions and set capabilities
114 121
  {
115
    showMessageBox( tr( "Unable to access relation" ),
116
                    tr( "Unable to access the %1 relation.\nThe error message from the database was:\n%2.\nSQL: %3" )
117
                    .arg( mSchemaTableName )
118
                    .arg( QString::fromUtf8( PQresultErrorMessage( testAccess ) ) )
119
                    .arg( sql ) );
120 122
    valid = false;
121 123
    disconnectDb();
122 124
    return;
123 125
  }
124 126

  
125
  if ( connectionRO->pgVersion() >= 80400 )
126
  {
127
    sql = QString( "SELECT "
128
                   "has_table_privilege(%1,'DELETE'),"
129
                   "has_any_column_privilege(%1,'UPDATE'),"
130
                   "has_column_privilege(%1,%2,'UPDATE'),"
131
                   "has_table_privilege(%1,'INSERT'),"
132
                   "current_schema()" )
133
          .arg( quotedValue( mSchemaTableName ) ).arg( quotedValue( geometryColumn ) );
134
  }
135
  else
136
  {
137
    sql = QString( "SELECT "
138
                   "has_table_privilege(%1,'DELETE'),"
139
                   "has_table_privilege(%1,'UPDATE'),"
140
                   "has_table_privilege(%1,'UPDATE'),"
141
                   "has_table_privilege(%1,'INSERT'),"
142
                   "current_schema()" )
143
          .arg( quotedValue( mSchemaTableName ) );
144
  }
145

  
146
  testAccess = connectionRO->PQexec( sql );
147
  if ( PQresultStatus( testAccess ) != PGRES_TUPLES_OK )
148
  {
149
    showMessageBox( tr( "Unable to access relation" ),
150
                    tr( "Unable to determine table access privileges for the %1 relation.\nThe error message from the database was:\n%2.\nSQL: %3" )
151
                    .arg( mSchemaTableName )
152
                    .arg( QString::fromUtf8( PQresultErrorMessage( testAccess ) ) )
153
                    .arg( sql ) );
154
    valid = false;
155
    disconnectDb();
156
    return;
157
  }
158

  
159
  // postgres has fast access to features at id (thanks to primary key / unique index)
160
  // the latter flag is here just for compatibility
161
  enabledCapabilities = QgsVectorDataProvider::SelectAtId | QgsVectorDataProvider::SelectGeometryAtId;
162

  
163
  if ( QString::fromUtf8( PQgetvalue( testAccess, 0, 0 ) ) == "t" )
164
  {
165
    // DELETE
166
    enabledCapabilities |= QgsVectorDataProvider::DeleteFeatures;
167
  }
168

  
169
  if ( QString::fromUtf8( PQgetvalue( testAccess, 0, 1 ) ) == "t" )
170
  {
171
    // UPDATE
172
    enabledCapabilities |= QgsVectorDataProvider::ChangeAttributeValues;
173
  }
174

  
175
  if ( QString::fromUtf8( PQgetvalue( testAccess, 0, 2 ) ) == "t" )
176
  {
177
    // UPDATE
178
    enabledCapabilities |= QgsVectorDataProvider::ChangeGeometries;
179
  }
180

  
181
  if ( QString::fromUtf8( PQgetvalue( testAccess, 0, 3 ) ) == "t" )
182
  {
183
    // INSERT
184
    enabledCapabilities |= QgsVectorDataProvider::AddFeatures;
185
  }
186

  
187
  mCurrentSchema = QString::fromUtf8( PQgetvalue( testAccess, 0, 4 ) );
188
  if ( mCurrentSchema == mSchemaName )
189
  {
190
    mUri.clearSchema();
191
  }
192

  
193
  if ( mSchemaName == "" )
194
    mSchemaName = mCurrentSchema;
195

  
196
  sql = QString( "SELECT 1 FROM pg_class,pg_namespace WHERE "
197
                 "pg_class.relnamespace=pg_namespace.oid AND "
198
                 "pg_get_userbyid(relowner)=current_user AND "
199
                 "relname=%1 AND nspname=%2" )
200
        .arg( quotedValue( mTableName ) )
201
        .arg( quotedValue( mSchemaName ) );
202
  testAccess = connectionRO->PQexec( sql );
203
  if ( PQresultStatus( testAccess ) == PGRES_TUPLES_OK && PQntuples( testAccess ) == 1 )
204
  {
205
    enabledCapabilities |= QgsVectorDataProvider::AddAttributes | QgsVectorDataProvider::DeleteAttributes;
206
  }
207

  
208 127
  if ( !getGeometryDetails() ) // gets srid and geometry type
209 128
  {
210 129
    // the table is not a geometry table
......
485 404
      query += "," + fieldExpression( fld );
486 405
    }
487 406

  
488
    query += " from " + mSchemaTableName;
407
    query += QString(" from %1" ).arg( !isCustomQuery ? mSchemaTableName : sqlCustomSelect );
489 408

  
490 409
    if ( !whereClause.isEmpty() )
491 410
      query += QString( " where %1" ).arg( whereClause );
......
876 795

  
877 796
void QgsPostgresProvider::loadFields()
878 797
{
879
  QgsDebugMsg( "Loading fields for table " + mTableName );
798
  QString sql;
799
  if ( !isCustomQuery )
800
  {
801
    QgsDebugMsg( "Loading fields for table " + mTableName );
880 802

  
881
  // Get the relation oid for use in later queries
882
  QString sql = QString( "SELECT regclass(%1)::oid" ).arg( quotedValue( mSchemaTableName ) );
883
  Result tresult = connectionRO->PQexec( sql );
884
  QString tableoid = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
803
    // Get the relation oid for use in later queries
804
    sql = QString( "SELECT regclass(%1)::oid" ).arg( quotedValue( mSchemaTableName ) );
805
    Result tresult = connectionRO->PQexec( sql );
806
    QString tblOid = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
885 807

  
886
  // Get the table description
887
  sql = QString( "SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=0" ).arg( tableoid );
888
  tresult = connectionRO->PQexec( sql );
889
  if ( PQntuples( tresult ) > 0 )
890
    mDataComment = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
808
    // Get the table description
809
    sql = QString( "SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=0" ).arg( tblOid );
810
    tresult = connectionRO->PQexec( sql );
811
    if ( PQntuples( tresult ) > 0 )
812
      mDataComment = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
891 813

  
892
  // Populate the field vector for this layer. The field vector contains
893
  // field name, type, length, and precision (if numeric)
894
  sql = QString( "select * from %1 limit 0" ).arg( mSchemaTableName );
814
    // Populate the field vector for this layer. The field vector contains
815
    // field name, type, length, and precision (if numeric)
816
    sql = QString( "select * from %1 limit 0" ).arg( mSchemaTableName );
817
  }
818
  else
819
  {
820
    sql = QString( "select * from %1 limit 0" ).arg( sqlCustomSelect );
821
  }
895 822

  
896 823
  Result result = connectionRO->PQexec( sql );
897 824

  
......
909 836
    QString typOid = QString().setNum( fldtyp );
910 837
    int fieldModifier = PQfmod( result, i );
911 838
    QString fieldComment( "" );
839
    int tbloid = PQftable( result, i );
912 840

  
913 841
    sql = QString( "SELECT typname,typtype,typelem,typlen FROM pg_type WHERE oid=%1" ).arg( typOid );
914 842
    // just oid; needs more work to support array type
......
921 849
    QString fieldElem = QString::fromUtf8( PQgetvalue( oidResult, 0, 2 ) );
922 850
    int fieldSize = QString::fromUtf8( PQgetvalue( oidResult, 0, 3 ) ).toInt();
923 851

  
924
    sql = QString( "SELECT attnum FROM pg_attribute WHERE attrelid=%1 AND attname=%2" )
925
          .arg( tableoid ).arg( quotedValue( fieldName ) );
852
    if ( tbloid >= 0 )
853
    {
854
      QString tableOid = QString().setNum( tbloid );
926 855

  
927
    Result tresult = connectionRO->PQexec( sql );
928
    QString attnum = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
856
      sql = QString( "SELECT attnum FROM pg_attribute WHERE attrelid=%1 AND attname=%2" )
857
            .arg( tableOid ).arg( quotedValue( fieldName ) );
929 858

  
930
    sql = QString( "SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=%2" )
931
          .arg( tableoid ).arg( attnum );
859
      Result tresult = connectionRO->PQexec( sql );
860
      QString attnum = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
932 861

  
933
    tresult = connectionRO->PQexec( sql );
934
    if ( PQntuples( tresult ) > 0 )
935
      fieldComment = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
862
      sql = QString( "SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=%2" )
863
            .arg( tableOid ).arg( attnum );
936 864

  
865
      tresult = connectionRO->PQexec( sql );
866
      if ( PQntuples( tresult ) > 0 )
867
        fieldComment = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
868
    }
869

  
937 870
    QVariant::Type fieldType;
938 871

  
939 872
    if ( fieldTType == "b" )
......
1007 940
  }
1008 941
}
1009 942

  
943
bool QgsPostgresProvider::checkPermsAndCapabilities()
944
{
945
  QgsDebugMsg( "Checking for permissions on the relation" );
946

  
947
  Result testAccess;
948
  if ( !isCustomQuery )
949
  {
950
    // Check that we can read from the table (i.e., we have
951
    // select permission).
952
    QString sql = QString( "select * from %1 limit 1" ).arg( mSchemaTableName );
953
    Result testAccess = connectionRO->PQexec( sql );
954
    if ( PQresultStatus( testAccess ) != PGRES_TUPLES_OK )
955
    {
956
      showMessageBox( tr( "Unable to access relation" ),
957
                      tr( "Unable to access the %1 relation.\nThe error message from the database was:\n%2.\nSQL: %3" )
958
                      .arg( mSchemaTableName )
959
                      .arg( QString::fromUtf8( PQresultErrorMessage( testAccess ) ) )
960
                      .arg( sql ) );
961
      return false;
962
    }
963

  
964
    if ( connectionRO->pgVersion() >= 80400 )
965
    {
966
      sql = QString( "SELECT "
967
                     "has_table_privilege(%1,'DELETE'),"
968
                     "has_any_column_privilege(%1,'UPDATE'),"
969
                     "has_column_privilege(%1,%2,'UPDATE'),"
970
                     "has_table_privilege(%1,'INSERT'),"
971
                     "current_schema()" )
972
            .arg( quotedValue( mSchemaTableName ) ).arg( quotedValue( geometryColumn ) );
973
    }
974
    else
975
    {
976
      sql = QString( "SELECT "
977
                     "has_table_privilege(%1,'DELETE'),"
978
                     "has_table_privilege(%1,'UPDATE'),"
979
                     "has_table_privilege(%1,'UPDATE'),"
980
                     "has_table_privilege(%1,'INSERT'),"
981
                     "current_schema()" )
982
            .arg( quotedValue( mSchemaTableName ) );
983
    }
984

  
985
    testAccess = connectionRO->PQexec( sql );
986
    if ( PQresultStatus( testAccess ) != PGRES_TUPLES_OK )
987
    {
988
      showMessageBox( tr( "Unable to access relation" ),
989
                      tr( "Unable to determine table access privileges for the %1 relation.\nThe error message from the database was:\n%2.\nSQL: %3" )
990
                      .arg( mSchemaTableName )
991
                      .arg( QString::fromUtf8( PQresultErrorMessage( testAccess ) ) )
992
                      .arg( sql ) );
993
      return false;
994
    }
995

  
996
    // postgres has fast access to features at id (thanks to primary key / unique index)
997
    // the latter flag is here just for compatibility
998
    enabledCapabilities = QgsVectorDataProvider::SelectAtId | QgsVectorDataProvider::SelectGeometryAtId;
999

  
1000
    if ( QString::fromUtf8( PQgetvalue( testAccess, 0, 0 ) ) == "t" )
1001
    {
1002
      // DELETE
1003
      enabledCapabilities |= QgsVectorDataProvider::DeleteFeatures;
1004
    }
1005

  
1006
    if ( QString::fromUtf8( PQgetvalue( testAccess, 0, 1 ) ) == "t" )
1007
    {
1008
      // UPDATE
1009
      enabledCapabilities |= QgsVectorDataProvider::ChangeAttributeValues;
1010
    }
1011

  
1012
    if ( QString::fromUtf8( PQgetvalue( testAccess, 0, 2 ) ) == "t" )
1013
    {
1014
      // UPDATE
1015
      enabledCapabilities |= QgsVectorDataProvider::ChangeGeometries;
1016
    }
1017

  
1018
    if ( QString::fromUtf8( PQgetvalue( testAccess, 0, 3 ) ) == "t" )
1019
    {
1020
      // INSERT
1021
      enabledCapabilities |= QgsVectorDataProvider::AddFeatures;
1022
    }
1023

  
1024
    mCurrentSchema = QString::fromUtf8( PQgetvalue( testAccess, 0, 4 ) );
1025
    if ( mCurrentSchema == mSchemaName )
1026
    {
1027
      mUri.clearSchema();
1028
    }
1029

  
1030
    if ( mSchemaName == "" )
1031
      mSchemaName = mCurrentSchema;
1032

  
1033
    sql = QString( "SELECT 1 FROM pg_class,pg_namespace WHERE "
1034
                   "pg_class.relnamespace=pg_namespace.oid AND "
1035
                   "pg_get_userbyid(relowner)=current_user AND "
1036
                   "relname=%1 AND nspname=%2" )
1037
          .arg( quotedValue( mTableName ) )
1038
          .arg( quotedValue( mSchemaName ) );
1039
    testAccess = connectionRO->PQexec( sql );
1040
    if ( PQresultStatus( testAccess ) == PGRES_TUPLES_OK && PQntuples( testAccess ) == 1 )
1041
    {
1042
      enabledCapabilities |= QgsVectorDataProvider::AddAttributes | QgsVectorDataProvider::DeleteAttributes;
1043
    }
1044
  }
1045
  else
1046
  {
1047
    // Check if the sql is a select query
1048
    if ( !sqlCustomSelect.startsWith( "select", Qt::CaseInsensitive ) )
1049
    {
1050
      QgsDebugMsg( "The custom query is not a select query." );
1051
      //TODO show a message by showMessageBox()
1052
      return false;
1053
    }
1054

  
1055
    // get a new alias for the neasted query
1056
    int index = 0;
1057
    QString alias;
1058
    QRegExp regex;
1059
    do
1060
    {
1061
      alias = QString( "subQuery_%1" ).arg( QString::number( index++ ) );
1062
      QString pattern = QString( "(\\\"?)%1\\1" ).arg( QRegExp::escape( alias ) );
1063
      regex.setPattern( pattern );
1064
      regex.setCaseSensitivity( Qt::CaseInsensitive );
1065
    }
1066
    while( sqlCustomSelect.contains( regex ) );
1067

  
1068
    // convert the custom query into a neasted query
1069
    sqlCustomSelect = QString( "( %1 ) as %2" )
1070
                  .arg( sqlCustomSelect )
1071
                  .arg( quotedIdentifier( alias ) );
1072

  
1073
    QString sql = QString( "select * from %1 limit 1" )
1074
                  .arg( sqlCustomSelect );
1075

  
1076
    testAccess = connectionRO->PQexec( sql );
1077
    if ( PQresultStatus( testAccess ) != PGRES_TUPLES_OK )
1078
    {
1079
      showMessageBox( tr( "Unable execute the query" ),
1080
                      tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
1081
                      .arg( QString::fromUtf8( PQresultErrorMessage( testAccess ) ) )
1082
                      .arg( sql ) );
1083
      return false;
1084
    }
1085

  
1086
    enabledCapabilities = QgsVectorDataProvider::SelectAtId | QgsVectorDataProvider::SelectGeometryAtId;
1087
  }
1088

  
1089
  return true;
1090
}
1091

  
1010 1092
QString QgsPostgresProvider::getPrimaryKey()
1011 1093
{
1012 1094
  // If we find a database primary key we will set this to true.  If it is a column which is serving
......
1017 1099
  // can be used as a key into the table. Primary keys are always
1018 1100
  // unique indices, so we catch them as well.
1019 1101

  
1020
  QString sql = QString( "select indkey from pg_index where indisunique and indrelid=regclass(%1)::oid and indpred is null" )
1021
                .arg( quotedValue( mSchemaTableName ) );
1102
  QString sql;
1103
  if ( !isCustomQuery )
1104
  {
1105
    sql = QString( "select indkey from pg_index where indisunique and indrelid=regclass(%1)::oid and indpred is null" )
1106
          .arg( quotedValue( mSchemaTableName ) );
1022 1107

  
1023
  QgsDebugMsg( "Getting unique index using '" + sql + "'" );
1108
    QgsDebugMsg( "Getting unique index using '" + sql + "'" );
1024 1109

  
1025
  Result pk = connectionRO->PQexec( sql );
1110
    Result pk = connectionRO->PQexec( sql );
1026 1111

  
1027
  QgsDebugMsg( "Got " + QString::number( PQntuples( pk ) ) + " rows." );
1112
    QgsDebugMsg( "Got " + QString::number( PQntuples( pk ) ) + " rows." );
1028 1113

  
1029
  QStringList log;
1114
    QStringList log;
1030 1115

  
1031
  // if we got no tuples we ain't got no unique index :)
1032
  if ( PQntuples( pk ) == 0 )
1033
  {
1034
    QgsDebugMsg( "Relation has no unique index -- investigating alternatives" );
1035

  
1036
    // Two options here. If the relation is a table, see if there is
1037
    // an oid column that can be used instead.
1038
    // If the relation is a view try to find a suitable column to use as
1039
    // the primary key.
1040

  
1041
    sql = QString( "SELECT relkind FROM pg_class WHERE oid=regclass(%1)::oid" )
1042
          .arg( quotedValue( mSchemaTableName ) );
1043
    Result tableType = connectionRO->PQexec( sql );
1044
    QString type = QString::fromUtf8( PQgetvalue( tableType, 0, 0 ) );
1045

  
1046
    if ( type == "r" ) // the relation is a table
1116
    // if we got no tuples we ain't got no unique index :)
1117
    if ( PQntuples( pk ) == 0 )
1047 1118
    {
1048
      QgsDebugMsg( "Relation is a table. Checking to see if it has an oid column." );
1119
      QgsDebugMsg( "Relation has no unique index -- investigating alternatives" );
1049 1120

  
1050
      primaryKey = "";
1121
      // Two options here. If the relation is a table, see if there is
1122
      // an oid column that can be used instead.
1123
      // If the relation is a view try to find a suitable column to use as
1124
      // the primary key.
1051 1125

  
1052
      // If there is an oid on the table, use that instead,
1053
      // otherwise give up
1054
      sql = QString( "SELECT attname FROM pg_attribute WHERE attname='oid' AND attrelid=regclass(%1)" )
1126
      sql = QString( "SELECT relkind FROM pg_class WHERE oid=regclass(%1)::oid" )
1055 1127
            .arg( quotedValue( mSchemaTableName ) );
1128
      Result tableType = connectionRO->PQexec( sql );
1129
      QString type = QString::fromUtf8( PQgetvalue( tableType, 0, 0 ) );
1056 1130

  
1057
      Result oidCheck = connectionRO->PQexec( sql );
1058

  
1059
      if ( PQntuples( oidCheck ) != 0 )
1131
      if ( type == "r" ) // the relation is a table
1060 1132
      {
1061
        // Could warn the user here that performance will suffer if
1062
        // oid isn't indexed (and that they may want to add a
1063
        // primary key to the table)
1064
        primaryKey = "oid";
1065
        primaryKeyType = "int4";
1066
        mIsDbPrimaryKey = true;
1067
      }
1068
      else
1069
      {
1070
        sql = QString( "SELECT attname FROM pg_attribute WHERE attname='ctid' AND attrelid=regclass(%1)" )
1133
        QgsDebugMsg( "Relation is a table. Checking to see if it has an oid column." );
1134
  
1135
        primaryKey = "";
1136
  
1137
        // If there is an oid on the table, use that instead,
1138
        // otherwise give up
1139
        sql = QString( "SELECT attname FROM pg_attribute WHERE attname='oid' AND attrelid=regclass(%1)" )
1071 1140
              .arg( quotedValue( mSchemaTableName ) );
1072

  
1073
        Result ctidCheck = connectionRO->PQexec( sql );
1074

  
1075
        if ( PQntuples( ctidCheck ) == 1 )
1141
  
1142
        Result oidCheck = connectionRO->PQexec( sql );
1143
  
1144
        if ( PQntuples( oidCheck ) != 0 )
1076 1145
        {
1077
          sql = QString( "SELECT max(substring(ctid::text from E'\\\\((\\\\d+),\\\\d+\\\\)')::integer) from %1" )
1078
                .arg( mSchemaTableName );
1079

  
1146
          // Could warn the user here that performance will suffer if
1147
          // oid isn't indexed (and that they may want to add a
1148
          // primary key to the table)
1149
          primaryKey = "oid";
1150
          primaryKeyType = "int4";
1151
          mIsDbPrimaryKey = true;
1152
        }
1153
        else
1154
        {
1155
          sql = QString( "SELECT attname FROM pg_attribute WHERE attname='ctid' AND attrelid=regclass(%1)" )
1156
                .arg( quotedValue( mSchemaTableName ) );
1157
  
1080 1158
          Result ctidCheck = connectionRO->PQexec( sql );
1159
  
1081 1160
          if ( PQntuples( ctidCheck ) == 1 )
1082 1161
          {
1083
            int id = QString( PQgetvalue( ctidCheck, 0, 0 ) ).toInt();
1084

  
1085
            if ( id < 0x10000 )
1162
            sql = QString( "SELECT max(substring(ctid::text from E'\\\\((\\\\d+),\\\\d+\\\\)')::integer) from %1" )
1163
                  .arg( mSchemaTableName );
1164
  
1165
            Result ctidCheck = connectionRO->PQexec( sql );
1166
            if ( PQntuples( ctidCheck ) == 1 )
1086 1167
            {
1087
              // fallback to ctid
1088
              primaryKey = "ctid";
1089
              primaryKeyType = "tid";
1090
              mIsDbPrimaryKey = true;
1168
              int id = QString( PQgetvalue( ctidCheck, 0, 0 ) ).toInt();
1169
  
1170
              if ( id < 0x10000 )
1171
              {
1172
                // fallback to ctid
1173
                primaryKey = "ctid";
1174
                primaryKeyType = "tid";
1175
                mIsDbPrimaryKey = true;
1176
              }
1091 1177
            }
1092 1178
          }
1093 1179
        }
1094
      }
1095

  
1096
      if ( primaryKey.isEmpty() )
1097
      {
1098
        showMessageBox( tr( "No suitable key column in table" ),
1099
                        tr( "The table has no column suitable for use as a key.\n\n"
1100
                            "Quantum GIS requires that the table either has a column of type\n"
1101
                            "int4 with a unique constraint on it (which includes the\n"
1102
                            "primary key), has a PostgreSQL oid column or has a ctid\n"
1103
                            "column with a 16bit block number.\n" ) );
1104
      }
1105
      else
1106
      {
1107
        mPrimaryKeyDefault = defaultValue( primaryKey ).toString();
1108
        if ( mPrimaryKeyDefault.isNull() )
1180
  
1181
        if ( primaryKey.isEmpty() )
1109 1182
        {
1110
          mPrimaryKeyDefault = QString( "max(%1)+1 from %2.%3" )
1111
                               .arg( quotedIdentifier( primaryKey ) )
1112
                               .arg( quotedIdentifier( mSchemaName ) )
1113
                               .arg( quotedIdentifier( mTableName ) );
1183
          showMessageBox( tr( "No suitable key column in table" ),
1184
                          tr( "The table has no column suitable for use as a key.\n\n"
1185
                              "Quantum GIS requires that the table either has a column of type\n"
1186
                              "int4 with a unique constraint on it (which includes the\n"
1187
                              "primary key), has a PostgreSQL oid column or has a ctid\n"
1188
                              "column with a 16bit block number.\n" ) );
1114 1189
        }
1190
        else
1191
        {
1192
          mPrimaryKeyDefault = defaultValue( primaryKey ).toString();
1193
          if ( mPrimaryKeyDefault.isNull() )
1194
          {
1195
            mPrimaryKeyDefault = QString( "max(%1)+1 from %2.%3" )
1196
                                 .arg( quotedIdentifier( primaryKey ) )
1197
                                 .arg( quotedIdentifier( mSchemaName ) )
1198
                                 .arg( quotedIdentifier( mTableName ) );
1199
          }
1200
        }
1115 1201
      }
1116
    }
1117
    else if ( type == "v" ) // the relation is a view
1118
    {
1119
      if ( !primaryKey.isEmpty() )
1202
      else if ( type == "v" ) // the relation is a view
1120 1203
      {
1121
        // check last used candidate
1122
        sql = QString( "select pg_type.typname from pg_attribute,pg_type where atttypid=pg_type.oid and attname=%1 and attrelid=regclass(%2)" )
1123
              .arg( quotedValue( primaryKey ) ).arg( quotedValue( mSchemaTableName ) );
1124

  
1125
        QgsDebugMsg( "checking candidate: " + sql );
1126

  
1127
        Result result = connectionRO->PQexec( sql );
1128

  
1129
        QString type;
1130
        if ( PQresultStatus( result ) == PGRES_TUPLES_OK &&
1131
             PQntuples( result ) == 1 )
1204
        if ( !primaryKey.isEmpty() )
1132 1205
        {
1133
          type = PQgetvalue( result, 0, 0 );
1206
          // check last used candidate
1207
          sql = QString( "select pg_type.typname from pg_attribute,pg_type where atttypid=pg_type.oid and attname=%1 and attrelid=regclass(%2)" )
1208
                .arg( quotedValue( primaryKey ) ).arg( quotedValue( mSchemaTableName ) );
1209
  
1210
          QgsDebugMsg( "checking candidate: " + sql );
1211
  
1212
          Result result = connectionRO->PQexec( sql );
1213
  
1214
          QString type;
1215
          if ( PQresultStatus( result ) == PGRES_TUPLES_OK &&
1216
               PQntuples( result ) == 1 )
1217
          {
1218
            type = PQgetvalue( result, 0, 0 );
1219
          }
1220
  
1221
          // mPrimaryKeyDefault stays null and is retrieved later on demand
1222
  
1223
          if (( type != "int4" && type != "oid" ) ||
1224
              !uniqueData( mSchemaName, mTableName, primaryKey ) )
1225
          {
1226
            primaryKey = "";
1227
          }
1134 1228
        }
1135

  
1136
        // mPrimaryKeyDefault stays null and is retrieved later on demand
1137

  
1138
        if (( type != "int4" && type != "oid" ) ||
1139
            !uniqueData( mSchemaName, mTableName, primaryKey ) )
1229
  
1230
        if ( primaryKey.isEmpty() )
1140 1231
        {
1141
          primaryKey = "";
1232
          parseView();
1142 1233
        }
1143 1234
      }
1144

  
1145
      if ( primaryKey.isEmpty() )
1146
      {
1147
        parseView();
1148
      }
1235
      else
1236
        QgsDebugMsg( "Unexpected relation type of '" + type + "'." );
1149 1237
    }
1150
    else
1151
      QgsDebugMsg( "Unexpected relation type of '" + type + "'." );
1152
  }
1153
  else // have some unique indices on the table. Now choose one...
1154
  {
1155
    // choose which (if more than one) unique index to use
1156
    std::vector<std::pair<QString, QString> > suitableKeyColumns;
1157
    for ( int i = 0; i < PQntuples( pk ); ++i )
1238
    else // have some unique indices on the table. Now choose one...
1158 1239
    {
1159
      QString col = QString::fromUtf8( PQgetvalue( pk, i, 0 ) );
1160
      QStringList columns = col.split( " ", QString::SkipEmptyParts );
1161
      if ( columns.count() == 1 )
1240
      // choose which (if more than one) unique index to use
1241
      std::vector<std::pair<QString, QString> > suitableKeyColumns;
1242
      for ( int i = 0; i < PQntuples( pk ); ++i )
1162 1243
      {
1163
        // Get the column name and data type
1164
        sql = QString( "select attname,pg_type.typname from pg_attribute,pg_type where atttypid=pg_type.oid and attnum=%1 and attrelid=regclass(%2)" )
1165
              .arg( col ).arg( quotedValue( mSchemaTableName ) );
1166
        Result types = connectionRO->PQexec( sql );
1167

  
1168
        if ( PQntuples( types ) > 0 )
1244
        QString col = QString::fromUtf8( PQgetvalue( pk, i, 0 ) );
1245
        QStringList columns = col.split( " ", QString::SkipEmptyParts );
1246
        if ( columns.count() == 1 )
1169 1247
        {
1170
          QString columnName = QString::fromUtf8( PQgetvalue( types, 0, 0 ) );
1171
          QString columnType = QString::fromUtf8( PQgetvalue( types, 0, 1 ) );
1172

  
1173
          if ( columnType != "int4" )
1174
            log.append( tr( "The unique index on column '%1' is unsuitable because Quantum GIS does not currently "
1175
                            "support non-int4 type columns as a key into the table.\n" ).arg( columnName ) );
1248
          // Get the column name and data type
1249
          sql = QString( "select attname,pg_type.typname from pg_attribute,pg_type where atttypid=pg_type.oid and attnum=%1 and attrelid=regclass(%2)" )
1250
                .arg( col ).arg( quotedValue( mSchemaTableName ) );
1251
          Result types = connectionRO->PQexec( sql );
1252
  
1253
          if ( PQntuples( types ) > 0 )
1254
          {
1255
            QString columnName = QString::fromUtf8( PQgetvalue( types, 0, 0 ) );
1256
            QString columnType = QString::fromUtf8( PQgetvalue( types, 0, 1 ) );
1257
  
1258
            if ( columnType != "int4" )
1259
              log.append( tr( "The unique index on column '%1' is unsuitable because Quantum GIS does not currently "
1260
                              "support non-int4 type columns as a key into the table.\n" ).arg( columnName ) );
1261
            else
1262
            {
1263
              mIsDbPrimaryKey = true;
1264
              suitableKeyColumns.push_back( std::make_pair( columnName, columnType ) );
1265
            }
1266
          }
1176 1267
          else
1177 1268
          {
1178
            mIsDbPrimaryKey = true;
1179
            suitableKeyColumns.push_back( std::make_pair( columnName, columnType ) );
1269
            //QgsDebugMsg( QString("name and type of %3. column of %1.%2 not found").arg(mSchemaName).arg(mTables).arg(col) );
1180 1270
          }
1181 1271
        }
1182 1272
        else
1183 1273
        {
1184
          //QgsDebugMsg( QString("name and type of %3. column of %1.%2 not found").arg(mSchemaName).arg(mTables).arg(col) );
1274
          sql = QString( "select attname from pg_attribute, pg_type where atttypid=pg_type.oid and attnum in (%1) and attrelid=regclass(%2)::oid" )
1275
                .arg( col.replace( " ", "," ) )
1276
                .arg( quotedValue( mSchemaTableName ) );
1277
  
1278
          Result types = connectionRO->PQexec( sql );
1279
          QString colNames;
1280
          int numCols = PQntuples( types );
1281
          for ( int j = 0; j < numCols; ++j )
1282
          {
1283
            if ( j == numCols - 1 )
1284
              colNames += tr( "and " );
1285
            colNames += quotedValue( QString::fromUtf8( PQgetvalue( types, j, 0 ) ) );
1286
            if ( j < numCols - 2 )
1287
              colNames += ",";
1288
          }
1289
  
1290
          log.append( tr( "The unique index based on columns %1 is unsuitable because Quantum GIS does not currently "
1291
                          "support multiple columns as a key into the table.\n" ).arg( colNames ) );
1185 1292
        }
1186 1293
      }
1294
  
1295
      // suitableKeyColumns now contains the name of columns (and their
1296
      // data type) that
1297
      // are suitable for use as a key into the table. If there is
1298
      // more than one we need to choose one. For the moment, just
1299
      // choose the first in the list.
1300
  
1301
      if ( suitableKeyColumns.size() > 0 )
1302
      {
1303
        primaryKey = suitableKeyColumns[0].first;
1304
        primaryKeyType = suitableKeyColumns[0].second;
1305
      }
1187 1306
      else
1188 1307
      {
1189
        sql = QString( "select attname from pg_attribute, pg_type where atttypid=pg_type.oid and attnum in (%1) and attrelid=regclass(%2)::oid" )
1190
              .arg( col.replace( " ", "," ) )
1191
              .arg( quotedValue( mSchemaTableName ) );
1192

  
1193
        Result types = connectionRO->PQexec( sql );
1194
        QString colNames;
1195
        int numCols = PQntuples( types );
1196
        for ( int j = 0; j < numCols; ++j )
1308
        // If there is an oid on the table, use that instead,
1309
        // otherwise give up
1310
        sql = QString( "select attname from pg_attribute where attname='oid' and attrelid=regclass(%1)::oid" ).arg( quotedValue( mSchemaTableName ) );
1311
        Result oidCheck = connectionRO->PQexec( sql );
1312
  
1313
        if ( PQntuples( oidCheck ) != 0 )
1197 1314
        {
1198
          if ( j == numCols - 1 )
1199
            colNames += tr( "and " );
1200
          colNames += quotedValue( QString::fromUtf8( PQgetvalue( types, j, 0 ) ) );
1201
          if ( j < numCols - 2 )
1202
            colNames += ",";
1315
          primaryKey = "oid";
1316
          primaryKeyType = "int4";
1203 1317
        }
1204

  
1205
        log.append( tr( "The unique index based on columns %1 is unsuitable because Quantum GIS does not currently "
1206
                        "support multiple columns as a key into the table.\n" ).arg( colNames ) );
1318
        else
1319
        {
1320
          log.prepend( "There were no columns in the table that were suitable "
1321
                       "as a qgis key into the table (either a column with a "
1322
                       "unique index and type int4 or a PostgreSQL oid column.\n" );
1323
        }
1207 1324
      }
1208
    }
1209

  
1210
    // suitableKeyColumns now contains the name of columns (and their
1211
    // data type) that
1212
    // are suitable for use as a key into the table. If there is
1213
    // more than one we need to choose one. For the moment, just
1214
    // choose the first in the list.
1215

  
1216
    if ( suitableKeyColumns.size() > 0 )
1217
    {
1218
      primaryKey = suitableKeyColumns[0].first;
1219
      primaryKeyType = suitableKeyColumns[0].second;
1220
    }
1221
    else
1222
    {
1223
      // If there is an oid on the table, use that instead,
1224
      // otherwise give up
1225
      sql = QString( "select attname from pg_attribute where attname='oid' and attrelid=regclass(%1)::oid" ).arg( quotedValue( mSchemaTableName ) );
1226
      Result oidCheck = connectionRO->PQexec( sql );
1227

  
1228
      if ( PQntuples( oidCheck ) != 0 )
1325
  
1326
      // Either primaryKey has been set by the above code, or it
1327
      // hasn't. If not, present some info to the user to give them some
1328
      // idea of why not.
1329
      if ( primaryKey.isEmpty() )
1229 1330
      {
1230
        primaryKey = "oid";
1231
        primaryKeyType = "int4";
1331
        // Give some info to the user about why things didn't work out.
1332
        valid = false;
1333
        showMessageBox( tr( "Unable to find a key column" ), log );
1232 1334
      }
1233 1335
      else
1234 1336
      {
1235
        log.prepend( "There were no columns in the table that were suitable "
1236
                     "as a qgis key into the table (either a column with a "
1237
                     "unique index and type int4 or a PostgreSQL oid column.\n" );
1337
        mPrimaryKeyDefault = defaultValue( primaryKey ).toString();
1338
        if ( mPrimaryKeyDefault.isNull() )
1339
        {
1340
          mPrimaryKeyDefault = QString( "max(%1)+1 from %2.%3" )
1341
                               .arg( quotedIdentifier( primaryKey ) )
1342
                               .arg( quotedIdentifier( mSchemaName ) )
1343
                               .arg( quotedIdentifier( mTableName ) );
1344
        }
1238 1345
      }
1239 1346
    }
1240

  
1241
    // Either primaryKey has been set by the above code, or it
1242
    // hasn't. If not, present some info to the user to give them some
1243
    // idea of why not.
1244
    if ( primaryKey.isEmpty() )
1245
    {
1246
      // Give some info to the user about why things didn't work out.
1247
      valid = false;
1248
      showMessageBox( tr( "Unable to find a key column" ), log );
1249
    }
1250
    else
1251
    {
1252
      mPrimaryKeyDefault = defaultValue( primaryKey ).toString();
1253
      if ( mPrimaryKeyDefault.isNull() )
1254
      {
1255
        mPrimaryKeyDefault = QString( "max(%1)+1 from %2.%3" )
1256
                             .arg( quotedIdentifier( primaryKey ) )
1257
                             .arg( quotedIdentifier( mSchemaName ) )
1258
                             .arg( quotedIdentifier( mTableName ) );
1259
      }
1260
    }
1261 1347
  }
1262 1348

  
1263 1349
  if ( !primaryKey.isNull() )
......
1780 1866
  {
1781 1867
    // get the field name
1782 1868
    const QgsField &fld = field( index );
1783
    QString sql;
1784
    if ( sqlWhereClause.isEmpty() )
1869
    QString sql = QString( "select min(%1) from %2" )
1870
                  .arg( quotedIdentifier( fld.name() ) )
1871
                  .arg( !isCustomQuery ? mSchemaTableName : sqlCustomSelect );
1872
    
1873
    if ( !sqlWhereClause.isEmpty() )
1785 1874
    {
1786
      sql = QString( "select min(%1) from %2" )
1787
            .arg( quotedIdentifier( fld.name() ) )
1788
            .arg( mSchemaTableName );
1875
      sql += QString( " where %1" ).arg( sqlWhereClause );
1789 1876
    }
1790
    else
1791
    {
1792
      sql = QString( "select min(%1) from %2 where %3" )
1793
            .arg( quotedIdentifier( fld.name() ) )
1794
            .arg( mSchemaTableName )
1795
            .arg( sqlWhereClause );
1796
    }
1877
    
1797 1878
    Result rmin = connectionRO->PQexec( sql );
1798 1879
    return convertValue( fld.type(), QString::fromUtf8( PQgetvalue( rmin, 0, 0 ) ) );
1799 1880
  }
......
1812 1893
  {
1813 1894
    // get the field name
1814 1895
    const QgsField &fld = field( index );
1815
    QString sql;
1816
    if ( sqlWhereClause.isEmpty() )
1896
    QString sql = QString( "select distinct %1 from %2" )
1897
                  .arg( quotedIdentifier( fld.name() ) )
1898
                  .arg( !isCustomQuery ? mSchemaTableName : sqlCustomSelect );
1899

  
1900
    if ( !sqlWhereClause.isEmpty() )
1817 1901
    {
1818
      sql = QString( "select distinct %1 from %2 order by %1" )
1819
            .arg( quotedIdentifier( fld.name() ) )
1820
            .arg( mSchemaTableName );
1902
      sql += QString( " where %1" ).arg( sqlWhereClause );
1821 1903
    }
1822
    else
1823
    {
1824
      sql = QString( "select distinct %1 from %2 where %3 order by %1" )
1825
            .arg( quotedIdentifier( fld.name() ) )
1826
            .arg( mSchemaTableName )
1827
            .arg( sqlWhereClause );
1828
    }
1829 1904

  
1905
    sql +=  QString( " order by %1" )
1906
            .arg( quotedIdentifier( fld.name() ) );
1907

  
1830 1908
    if ( limit >= 0 )
1831 1909
    {
1832 1910
      sql += QString( " LIMIT %1" ).arg( limit );
......
1891 1969
bool QgsPostgresProvider::parseEnumRange( QStringList& enumValues, const QString& attributeName ) const
1892 1970
{
1893 1971
  enumValues.clear();
1894
  QString enumRangeSql = QString( "SELECT enum_range(%1) from %2 limit 1" ).arg( quotedIdentifier( attributeName ) ).arg( mSchemaTableName );
1972
  QString enumRangeSql = QString( "SELECT enum_range(%1) from %2 limit 1" )
1973
                         .arg( quotedIdentifier( attributeName ) )
1974
                         .arg( !isCustomQuery ? mSchemaTableName : sqlCustomSelect );
1895 1975
  Result enumRangeRes = connectionRO->PQexec( enumRangeSql );
1896 1976
  if ( PQresultStatus( enumRangeRes ) == PGRES_TUPLES_OK && PQntuples( enumRangeRes ) > 0 )
1897 1977
  {
......
1979 2059
  {
1980 2060
    // get the field name
1981 2061
    const QgsField &fld = field( index );
1982
    QString sql;
1983
    if ( sqlWhereClause.isEmpty() )
2062
    QString sql = QString( "select max(%1) from %2" )
2063
                  .arg( quotedIdentifier( fld.name() ) )
2064
                  .arg( !isCustomQuery ? mSchemaTableName : sqlCustomSelect );
2065

  
2066
    if ( !sqlWhereClause.isEmpty() )
1984 2067
    {
1985
      sql = QString( "select max(%1) from %2" )
1986
            .arg( quotedIdentifier( fld.name() ) )
1987
            .arg( mSchemaTableName );
2068
      sql += QString( " where %1" ).arg( sqlWhereClause );
1988 2069
    }
1989
    else
1990
    {
1991
      sql = QString( "select max(%1) from %2 where %3" )
1992
            .arg( quotedIdentifier( fld.name() ) )
1993
            .arg( mSchemaTableName )
1994
            .arg( sqlWhereClause );
1995
    }
2070

  
1996 2071
    Result rmax = connectionRO->PQexec( sql );
1997 2072
    return convertValue( fld.type(), QString::fromUtf8( PQgetvalue( rmax, 0, 0 ) ) );
1998 2073
  }
......
2663 2738
  // a thread the task of getting the full count.
2664 2739
  QString sql;
2665 2740

  
2666
  if ( mUseEstimatedMetadata )
2741
  if ( !isCustomQuery && mUseEstimatedMetadata )
2667 2742
  {
2668 2743
    sql = QString( "select reltuples::int from pg_catalog.pg_class where oid=regclass(%1)::oid" ).arg( quotedValue( mSchemaTableName ) );
2669 2744
  }
2670 2745
  else
2671 2746
  {
2672
    sql = QString( "select count(*) from %1" ).arg( mSchemaTableName );
2747
    sql = QString( "select count(*) from %1" ).arg( !isCustomQuery ? mSchemaTableName : sqlCustomSelect );
2673 2748

  
2674
    if ( sqlWhereClause.length() > 0 )
2749
    if ( !sqlWhereClause.isEmpty() )
2675 2750
    {
2676 2751
      sql += " where " + sqlWhereClause;
2677 2752
    }
......
2696 2771
  QString ext;
2697 2772

  
2698 2773
  // get the extents
2699
  if ( mUseEstimatedMetadata || sqlWhereClause.isEmpty() )
2774
  if ( !isCustomQuery && ( mUseEstimatedMetadata || sqlWhereClause.isEmpty() ) )
2700 2775
  {
2701 2776
    // do stats exists?
2702 2777
    sql = QString( "SELECT COUNT(*) FROM pg_stats WHERE schemaname=%1 AND tablename=%2 AND attname=%3" )
......
2727 2802
  {
2728 2803
    sql = QString( "select extent(%1) from %2" )
2729 2804
          .arg( quotedIdentifier( geometryColumn ) )
2730
          .arg( mSchemaTableName );
2805
          .arg( !isCustomQuery ? mSchemaTableName : sqlCustomSelect );
2731 2806

  
2732 2807
    if ( !sqlWhereClause.isEmpty() )
2733
      sql += QString( "where %1" ).arg( sqlWhereClause );
2808
      sql += QString( " where %1" ).arg( sqlWhereClause );
2734 2809

  
2735 2810
    result = connectionRO->PQexec( sql );
2736 2811
    if ( PQresultStatus( result ) != PGRES_TUPLES_OK )
......
2823 2898
  // version 7.4, binary cursors return data in XDR whereas previous versions
2824 2899
  // return data in the endian of the server
2825 2900

  
2826
  QString firstOid = QString( "select regclass(%1)::oid" ).arg( quotedValue( mSchemaTableName ) );
2827
  Result oidResult = connectionRO->PQexec( firstOid );
2828
  // get the int value from a "normal" select
2829
  QString oidValue = QString::fromUtf8( PQgetvalue( oidResult, 0, 0 ) );
2901
  QString oidValue;
2902
  QString schemaTableName;
2830 2903

  
2904
  if ( isCustomQuery )
2905
  {
2906
    QString sql = QString( "select * from %1 limit 0" ).arg( sqlCustomSelect );
2907
    Result res = connectionRO->PQexec( sql );
2908

  
2909
    // loop through the returned fields to get a valid oid
2910
    // TODO check if we have found a table oid at loop exit
2911
    for ( int i = 0; i < PQnfields( res ); i++ )
2912
    {
2913
      int tableOid = PQftable( res, i );
2914
      if ( tableOid >= 0 )
2915
      {
2916
        oidValue = QString::number( tableOid );
2917
        break;
2918
      }
2919
    }
2920

  
2921
    // get the table name
2922
    res = connectionRO->PQexec( QString( "SELECT relname FROM pg_class WHERE oid=%1" ).arg( oidValue ) );
2923
    schemaTableName = QString::fromUtf8( PQgetvalue( res, 0, 0 ) );
2924
  }
2925
  else
2926
  {
2927
    schemaTableName = mSchemaTableName;
2928

  
2929
    QString firstOid = QString( "select regclass(%1)::oid" ).arg( quotedValue( schemaTableName ) );
2930
    Result oidResult = connectionRO->PQexec( firstOid );
2931
    // get the int value from a "normal" select
2932
    oidValue = QString::fromUtf8( PQgetvalue( oidResult, 0, 0 ) );
2933
  }
2934

  
2831 2935
  QgsDebugMsg( "Creating binary cursor" );
2832 2936

  
2833 2937
  // get the same value using a binary cursor
2834
  connectionRO->openCursor( "oidcursor", QString( "select regclass(%1)::oid" ).arg( quotedValue( mSchemaTableName ) ) );
2938
  connectionRO->openCursor( "oidcursor", QString( "select regclass(%1)::oid" ).arg( quotedValue( schemaTableName ) ) );
2835 2939

  
2836 2940
  QgsDebugMsg( "Fetching a record and attempting to get check endian-ness" );
2837 2941

  
......
2861 2965
  valid = false;
2862 2966
  QStringList log;
2863 2967

  
2864
  QString sql = QString( "select type,srid from geometry_columns"
2865
                         " where f_table_name=%1 and f_geometry_column=%2 and f_table_schema=%3" )
2866
                .arg( quotedValue( mTableName ) )
2867
                .arg( quotedValue( geometryColumn ) )
2868
                .arg( quotedValue( mSchemaName ) );
2968
  Result result;
2969
  QString sql;
2869 2970

  
2870
  QgsDebugMsg( "Getting geometry column: " + sql );
2971
  if ( !isCustomQuery )
2972
  {
2973
    sql = QString( "select type,srid from geometry_columns"
2974
                   " where f_table_name=%1 and f_geometry_column=%2 and f_table_schema=%3" )
2975
          .arg( quotedValue( mTableName ) )
2976
          .arg( quotedValue( geometryColumn ) )
2977
          .arg( quotedValue( mSchemaName ) );
2871 2978

  
2872
  Result result = connectionRO->PQexec( sql );
2979
    QgsDebugMsg( "Getting geometry column: " + sql );
2873 2980

  
2874
  QgsDebugMsg( "geometry column query returned " + QString::number( PQntuples( result ) ) );
2981
    Result result = connectionRO->PQexec( sql );
2875 2982

  
2876
  if ( PQntuples( result ) > 0 )
2877
  {
2878
    fType = QString::fromUtf8( PQgetvalue( result, 0, 0 ) );
2879
    srid = QString::fromUtf8( PQgetvalue( result, 0, 1 ) );
2983
    QgsDebugMsg( "geometry column query returned " + QString::number( PQntuples( result ) ) );
2984

  
2985
    if ( PQntuples( result ) > 0 )
2986
    {
2987
      fType = QString::fromUtf8( PQgetvalue( result, 0, 0 ) );
2988
      srid = QString::fromUtf8( PQgetvalue( result, 0, 1 ) );
2989
    }
2880 2990
  }
2881
  else
2991

  
2992
  if ( srid.isEmpty() || fType.isEmpty() )
2882 2993
  {
2883 2994
    // Didn't find what we need in the geometry_columns table, so
2884 2995
    // get stuff from the relevant column instead. This may (will?)
2885 2996
    // fail if there is no data in the relevant table.
2886 2997
    sql = QString( "select srid(%1),geometrytype(%1) from %2" )
2887 2998
          .arg( quotedIdentifier( geometryColumn ) )
2888
          .arg( mSchemaTableName );
2999
          .arg( !isCustomQuery ? mSchemaTableName : sqlCustomSelect );
2889 3000

  
2890 3001
    //it is possible that the where clause restricts the feature type
2891 3002
    if ( !sqlWhereClause.isEmpty() )
......
2926 3037
      }
2927 3038
      else
2928 3039
      {
2929
        sql += mSchemaTableName;
3040
        sql += !isCustomQuery ? mSchemaTableName : sqlCustomSelect;
2930 3041
      }
2931 3042

  
2932
      if ( mUri.sql() != "" )
2933
        sql += " where " + mUri.sql();
3043
      if ( !sqlWhereClause.isEmpty() )
3044
          sql += " where " + sqlWhereClause;
2934 3045

  
2935 3046
      result = connectionRO->PQexec( sql );
2936 3047