82 |
82 |
mTableName = mUri.table();
|
83 |
83 |
geometryColumn = mUri.geometryColumn();
|
84 |
84 |
sqlWhereClause = mUri.sql();
|
|
85 |
|
|
86 |
if ( mSchemaName.isEmpty() &&
|
|
87 |
mTableName.startsWith( "(select", Qt::CaseInsensitive ) &&
|
|
88 |
mTableName.endsWith( ")" ) )
|
|
89 |
{
|
|
90 |
isQuery = true;
|
|
91 |
mQuery = mTableName;
|
|
92 |
mTableName = "";
|
|
93 |
}
|
|
94 |
else
|
|
95 |
{
|
|
96 |
isQuery = false;
|
|
97 |
mQuery = mUri.quotedTablename();
|
|
98 |
}
|
|
99 |
|
85 |
100 |
primaryKey = mUri.keyColumn();
|
86 |
101 |
mUseEstimatedMetadata = mUri.useEstimatedMetadata();
|
87 |
102 |
|
88 |
|
// Keep a schema qualified table name for convenience later on.
|
89 |
|
mSchemaTableName = mUri.quotedTablename();
|
90 |
|
|
91 |
|
QgsDebugMsg( "Table name is " + mTableName );
|
92 |
|
QgsDebugMsg( "SQL is " + sqlWhereClause );
|
93 |
103 |
QgsDebugMsg( "Connection info is " + mUri.connectionInfo() );
|
94 |
|
|
95 |
104 |
QgsDebugMsg( "Geometry column is: " + geometryColumn );
|
96 |
105 |
QgsDebugMsg( "Schema is: " + mSchemaName );
|
97 |
106 |
QgsDebugMsg( "Table name is: " + mTableName );
|
|
107 |
QgsDebugMsg( "Query is: " + mQuery );
|
|
108 |
QgsDebugMsg( "Where clause is: " + sqlWhereClause );
|
98 |
109 |
|
99 |
110 |
connectionRW = NULL;
|
100 |
111 |
connectionRO = Conn::connectDb( mUri.connectionInfo(), true );
|
... | ... | |
104 |
115 |
return;
|
105 |
116 |
}
|
106 |
117 |
|
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 )
|
|
118 |
if ( !hasSufficientPermsAndCapabilities() ) // check permissions and set capabilities
|
114 |
119 |
{
|
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 |
120 |
valid = false;
|
121 |
121 |
disconnectDb();
|
122 |
122 |
return;
|
123 |
123 |
}
|
124 |
124 |
|
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 |
125 |
if ( !getGeometryDetails() ) // gets srid and geometry type
|
209 |
126 |
{
|
210 |
127 |
// the table is not a geometry table
|
... | ... | |
485 |
402 |
query += "," + fieldExpression( fld );
|
486 |
403 |
}
|
487 |
404 |
|
488 |
|
query += " from " + mSchemaTableName;
|
|
405 |
query += " from " + mQuery;
|
489 |
406 |
|
490 |
407 |
if ( !whereClause.isEmpty() )
|
491 |
408 |
query += QString( " where %1" ).arg( whereClause );
|
... | ... | |
675 |
592 |
QString fetch = QString( "fetch forward %1 from %2" ).arg( mFeatureQueueSize ).arg( cursorName );
|
676 |
593 |
if ( connectionRO->PQsendQuery( fetch ) == 0 ) // fetch features asynchronously
|
677 |
594 |
{
|
678 |
|
QgsDebugMsg( "PQsendQuery failed (1)" );
|
|
595 |
QgsDebugMsg( "PQsendQuery failed" );
|
679 |
596 |
}
|
680 |
597 |
|
681 |
598 |
Result queryResult;
|
... | ... | |
876 |
793 |
|
877 |
794 |
void QgsPostgresProvider::loadFields()
|
878 |
795 |
{
|
879 |
|
QgsDebugMsg( "Loading fields for table " + mTableName );
|
|
796 |
if ( !isQuery )
|
|
797 |
{
|
|
798 |
QgsDebugMsg( "Loading fields for table " + mTableName );
|
880 |
799 |
|
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 ) );
|
|
800 |
// Get the relation oid for use in later queries
|
|
801 |
QString sql = QString( "SELECT regclass(%1)::oid" ).arg( quotedValue( mQuery ) );
|
|
802 |
Result tresult = connectionRO->PQexec( sql );
|
|
803 |
QString tableoid = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
|
885 |
804 |
|
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 ) );
|
|
805 |
// Get the table description
|
|
806 |
sql = QString( "SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=0" ).arg( tableoid );
|
|
807 |
tresult = connectionRO->PQexec( sql );
|
|
808 |
if ( PQntuples( tresult ) > 0 )
|
|
809 |
mDataComment = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
|
|
810 |
}
|
891 |
811 |
|
892 |
812 |
// Populate the field vector for this layer. The field vector contains
|
893 |
813 |
// field name, type, length, and precision (if numeric)
|
894 |
|
sql = QString( "select * from %1 limit 0" ).arg( mSchemaTableName );
|
|
814 |
QString sql = QString( "select * from %1 limit 0" ).arg( mQuery );
|
895 |
815 |
|
896 |
816 |
Result result = connectionRO->PQexec( sql );
|
897 |
817 |
|
... | ... | |
909 |
829 |
QString typOid = QString().setNum( fldtyp );
|
910 |
830 |
int fieldModifier = PQfmod( result, i );
|
911 |
831 |
QString fieldComment( "" );
|
|
832 |
int tableoid = PQftable( result, i );
|
912 |
833 |
|
913 |
834 |
sql = QString( "SELECT typname,typtype,typelem,typlen FROM pg_type WHERE oid=%1" ).arg( typOid );
|
914 |
835 |
// just oid; needs more work to support array type
|
... | ... | |
921 |
842 |
QString fieldElem = QString::fromUtf8( PQgetvalue( oidResult, 0, 2 ) );
|
922 |
843 |
int fieldSize = QString::fromUtf8( PQgetvalue( oidResult, 0, 3 ) ).toInt();
|
923 |
844 |
|
924 |
|
sql = QString( "SELECT attnum FROM pg_attribute WHERE attrelid=%1 AND attname=%2" )
|
925 |
|
.arg( tableoid ).arg( quotedValue( fieldName ) );
|
|
845 |
if ( tableoid >= 0 )
|
|
846 |
{
|
|
847 |
sql = QString( "SELECT attnum FROM pg_attribute WHERE attrelid=%1 AND attname=%2" )
|
|
848 |
.arg( tableoid ).arg( quotedValue( fieldName ) );
|
926 |
849 |
|
927 |
|
Result tresult = connectionRO->PQexec( sql );
|
928 |
|
QString attnum = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
|
|
850 |
Result tresult = connectionRO->PQexec( sql );
|
|
851 |
QString attnum = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
|
929 |
852 |
|
930 |
|
sql = QString( "SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=%2" )
|
931 |
|
.arg( tableoid ).arg( attnum );
|
|
853 |
sql = QString( "SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=%2" )
|
|
854 |
.arg( tableoid ).arg( attnum );
|
932 |
855 |
|
933 |
|
tresult = connectionRO->PQexec( sql );
|
934 |
|
if ( PQntuples( tresult ) > 0 )
|
935 |
|
fieldComment = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
|
|
856 |
tresult = connectionRO->PQexec( sql );
|
|
857 |
if ( PQntuples( tresult ) > 0 )
|
|
858 |
fieldComment = QString::fromUtf8( PQgetvalue( tresult, 0, 0 ) );
|
|
859 |
}
|
936 |
860 |
|
937 |
861 |
QVariant::Type fieldType;
|
938 |
862 |
|
... | ... | |
1007 |
931 |
}
|
1008 |
932 |
}
|
1009 |
933 |
|
|
934 |
bool QgsPostgresProvider::hasSufficientPermsAndCapabilities()
|
|
935 |
{
|
|
936 |
QgsDebugMsg( "Checking for permissions on the relation" );
|
|
937 |
|
|
938 |
Result testAccess;
|
|
939 |
if ( !isQuery )
|
|
940 |
{
|
|
941 |
// Check that we can read from the table (i.e., we have
|
|
942 |
// select permission).
|
|
943 |
QString sql = QString( "select * from %1 limit 1" ).arg( mQuery );
|
|
944 |
Result testAccess = connectionRO->PQexec( sql );
|
|
945 |
if ( PQresultStatus( testAccess ) != PGRES_TUPLES_OK )
|
|
946 |
{
|
|
947 |
showMessageBox( tr( "Unable to access relation" ),
|
|
948 |
tr( "Unable to access the %1 relation.\nThe error message from the database was:\n%2.\nSQL: %3" )
|
|
949 |
.arg( mQuery )
|
|
950 |
.arg( QString::fromUtf8( PQresultErrorMessage( testAccess ) ) )
|
|
951 |
.arg( sql ) );
|
|
952 |
return false;
|
|
953 |
}
|
|
954 |
|
|
955 |
if ( connectionRO->pgVersion() >= 80400 )
|
|
956 |
{
|
|
957 |
sql = QString( "SELECT "
|
|
958 |
"has_table_privilege(%1,'DELETE'),"
|
|
959 |
"has_any_column_privilege(%1,'UPDATE'),"
|
|
960 |
"has_column_privilege(%1,%2,'UPDATE'),"
|
|
961 |
"has_table_privilege(%1,'INSERT'),"
|
|
962 |
"current_schema()" )
|
|
963 |
.arg( quotedValue( mQuery ) ).arg( quotedValue( geometryColumn ) );
|
|
964 |
}
|
|
965 |
else
|
|
966 |
{
|
|
967 |
sql = QString( "SELECT "
|
|
968 |
"has_table_privilege(%1,'DELETE'),"
|
|
969 |
"has_table_privilege(%1,'UPDATE'),"
|
|
970 |
"has_table_privilege(%1,'UPDATE'),"
|
|
971 |
"has_table_privilege(%1,'INSERT'),"
|
|
972 |
"current_schema()" )
|
|
973 |
.arg( quotedValue( mQuery ) );
|
|
974 |
}
|
|
975 |
|
|
976 |
testAccess = connectionRO->PQexec( sql );
|
|
977 |
if ( PQresultStatus( testAccess ) != PGRES_TUPLES_OK )
|
|
978 |
{
|
|
979 |
showMessageBox( tr( "Unable to access relation" ),
|
|
980 |
tr( "Unable to determine table access privileges for the %1 relation.\nThe error message from the database was:\n%2.\nSQL: %3" )
|
|
981 |
.arg( mQuery )
|
|
982 |
.arg( QString::fromUtf8( PQresultErrorMessage( testAccess ) ) )
|
|
983 |
.arg( sql ) );
|
|
984 |
return false;
|
|
985 |
}
|
|
986 |
|
|
987 |
// postgres has fast access to features at id (thanks to primary key / unique index)
|
|
988 |
// the latter flag is here just for compatibility
|
|
989 |
enabledCapabilities = QgsVectorDataProvider::SelectAtId | QgsVectorDataProvider::SelectGeometryAtId;
|
|
990 |
|
|
991 |
if ( QString::fromUtf8( PQgetvalue( testAccess, 0, 0 ) ) == "t" )
|
|
992 |
{
|
|
993 |
// DELETE
|
|
994 |
enabledCapabilities |= QgsVectorDataProvider::DeleteFeatures;
|
|
995 |
}
|
|
996 |
|
|
997 |
if ( QString::fromUtf8( PQgetvalue( testAccess, 0, 1 ) ) == "t" )
|
|
998 |
{
|
|
999 |
// UPDATE
|
|
1000 |
enabledCapabilities |= QgsVectorDataProvider::ChangeAttributeValues;
|
|
1001 |
}
|
|
1002 |
|
|
1003 |
if ( QString::fromUtf8( PQgetvalue( testAccess, 0, 2 ) ) == "t" )
|
|
1004 |
{
|
|
1005 |
// UPDATE
|
|
1006 |
enabledCapabilities |= QgsVectorDataProvider::ChangeGeometries;
|
|
1007 |
}
|
|
1008 |
|
|
1009 |
if ( QString::fromUtf8( PQgetvalue( testAccess, 0, 3 ) ) == "t" )
|
|
1010 |
{
|
|
1011 |
// INSERT
|
|
1012 |
enabledCapabilities |= QgsVectorDataProvider::AddFeatures;
|
|
1013 |
}
|
|
1014 |
|
|
1015 |
mCurrentSchema = QString::fromUtf8( PQgetvalue( testAccess, 0, 4 ) );
|
|
1016 |
if ( mCurrentSchema == mSchemaName )
|
|
1017 |
{
|
|
1018 |
mUri.clearSchema();
|
|
1019 |
}
|
|
1020 |
|
|
1021 |
if ( mSchemaName == "" )
|
|
1022 |
mSchemaName = mCurrentSchema;
|
|
1023 |
|
|
1024 |
sql = QString( "SELECT 1 FROM pg_class,pg_namespace WHERE "
|
|
1025 |
"pg_class.relnamespace=pg_namespace.oid AND "
|
|
1026 |
"pg_get_userbyid(relowner)=current_user AND "
|
|
1027 |
"relname=%1 AND nspname=%2" )
|
|
1028 |
.arg( quotedValue( mTableName ) )
|
|
1029 |
.arg( quotedValue( mSchemaName ) );
|
|
1030 |
testAccess = connectionRO->PQexec( sql );
|
|
1031 |
if ( PQresultStatus( testAccess ) == PGRES_TUPLES_OK && PQntuples( testAccess ) == 1 )
|
|
1032 |
{
|
|
1033 |
enabledCapabilities |= QgsVectorDataProvider::AddAttributes | QgsVectorDataProvider::DeleteAttributes;
|
|
1034 |
}
|
|
1035 |
}
|
|
1036 |
else
|
|
1037 |
{
|
|
1038 |
// Check if the sql is a select query
|
|
1039 |
if ( !mQuery.startsWith( "(select", Qt::CaseInsensitive ) &&
|
|
1040 |
!mQuery.endsWith( ")" ) )
|
|
1041 |
{
|
|
1042 |
QgsDebugMsg( "The custom query is not a select query." );
|
|
1043 |
//TODO show a message by showMessageBox()
|
|
1044 |
return false;
|
|
1045 |
}
|
|
1046 |
|
|
1047 |
// get a new alias for the subquery
|
|
1048 |
int index = 0;
|
|
1049 |
QString alias;
|
|
1050 |
QRegExp regex;
|
|
1051 |
do
|
|
1052 |
{
|
|
1053 |
alias = QString( "subQuery_%1" ).arg( QString::number( index++ ) );
|
|
1054 |
QString pattern = QString( "(\\\"?)%1\\1" ).arg( QRegExp::escape( alias ) );
|
|
1055 |
regex.setPattern( pattern );
|
|
1056 |
regex.setCaseSensitivity( Qt::CaseInsensitive );
|
|
1057 |
}
|
|
1058 |
while ( mQuery.contains( regex ) );
|
|
1059 |
|
|
1060 |
// convert the custom query into a subquery
|
|
1061 |
mQuery = QString( "%1 as %2" )
|
|
1062 |
.arg( mQuery )
|
|
1063 |
.arg( quotedIdentifier( alias ) );
|
|
1064 |
|
|
1065 |
QString sql = QString( "select * from %1 limit 1" ).arg( mQuery );
|
|
1066 |
|
|
1067 |
testAccess = connectionRO->PQexec( sql );
|
|
1068 |
if ( PQresultStatus( testAccess ) != PGRES_TUPLES_OK )
|
|
1069 |
{
|
|
1070 |
showMessageBox( tr( "Unable execute the query" ),
|
|
1071 |
tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
|
1072 |
.arg( QString::fromUtf8( PQresultErrorMessage( testAccess ) ) )
|
|
1073 |
.arg( sql ) );
|
|
1074 |
return false;
|
|
1075 |
}
|
|
1076 |
|
|
1077 |
enabledCapabilities = QgsVectorDataProvider::SelectAtId | QgsVectorDataProvider::SelectGeometryAtId;
|
|
1078 |
}
|
|
1079 |
|
|
1080 |
return true;
|
|
1081 |
}
|
|
1082 |
|
1010 |
1083 |
QString QgsPostgresProvider::getPrimaryKey()
|
1011 |
1084 |
{
|
1012 |
1085 |
// If we find a database primary key we will set this to true. If it is a column which is serving
|
... | ... | |
1017 |
1090 |
// can be used as a key into the table. Primary keys are always
|
1018 |
1091 |
// unique indices, so we catch them as well.
|
1019 |
1092 |
|
1020 |
|
QString sql = QString( "select indkey from pg_index where indisunique and indrelid=regclass(%1)::oid and indpred is null" )
|
1021 |
|
.arg( quotedValue( mSchemaTableName ) );
|
|
1093 |
QString sql;
|
|
1094 |
if ( !isQuery )
|
|
1095 |
{
|
|
1096 |
sql = QString( "select indkey from pg_index where indisunique and indrelid=regclass(%1)::oid and indpred is null" )
|
|
1097 |
.arg( quotedValue( mQuery ) );
|
1022 |
1098 |
|
1023 |
|
QgsDebugMsg( "Getting unique index using '" + sql + "'" );
|
|
1099 |
QgsDebugMsg( "Getting unique index using '" + sql + "'" );
|
1024 |
1100 |
|
1025 |
|
Result pk = connectionRO->PQexec( sql );
|
|
1101 |
Result pk = connectionRO->PQexec( sql );
|
1026 |
1102 |
|
1027 |
|
QgsDebugMsg( "Got " + QString::number( PQntuples( pk ) ) + " rows." );
|
|
1103 |
QgsDebugMsg( "Got " + QString::number( PQntuples( pk ) ) + " rows." );
|
1028 |
1104 |
|
1029 |
|
QStringList log;
|
|
1105 |
QStringList log;
|
1030 |
1106 |
|
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" );
|
|
1107 |
// if we got no tuples we ain't got no unique index :)
|
|
1108 |
if ( PQntuples( pk ) == 0 )
|
|
1109 |
{
|
|
1110 |
QgsDebugMsg( "Relation has no unique index -- investigating alternatives" );
|
1035 |
1111 |
|
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.
|
|
1112 |
// Two options here. If the relation is a table, see if there is
|
|
1113 |
// an oid column that can be used instead.
|
|
1114 |
// If the relation is a view try to find a suitable column to use as
|
|
1115 |
// the primary key.
|
1040 |
1116 |
|
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 ) );
|
|
1117 |
sql = QString( "SELECT relkind FROM pg_class WHERE oid=regclass(%1)::oid" )
|
|
1118 |
.arg( quotedValue( mQuery ) );
|
|
1119 |
Result tableType = connectionRO->PQexec( sql );
|
|
1120 |
QString type = QString::fromUtf8( PQgetvalue( tableType, 0, 0 ) );
|
1045 |
1121 |
|
1046 |
|
if ( type == "r" ) // the relation is a table
|
1047 |
|
{
|
1048 |
|
QgsDebugMsg( "Relation is a table. Checking to see if it has an oid column." );
|
|
1122 |
if ( type == "r" ) // the relation is a table
|
|
1123 |
{
|
|
1124 |
QgsDebugMsg( "Relation is a table. Checking to see if it has an oid column." );
|
1049 |
1125 |
|
1050 |
|
primaryKey = "";
|
|
1126 |
primaryKey = "";
|
1051 |
1127 |
|
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)" )
|
1055 |
|
.arg( quotedValue( mSchemaTableName ) );
|
|
1128 |
// If there is an oid on the table, use that instead,
|
|
1129 |
// otherwise give up
|
|
1130 |
sql = QString( "SELECT attname FROM pg_attribute WHERE attname='oid' AND attrelid=regclass(%1)" )
|
|
1131 |
.arg( quotedValue( mQuery ) );
|
1056 |
1132 |
|
1057 |
|
Result oidCheck = connectionRO->PQexec( sql );
|
|
1133 |
Result oidCheck = connectionRO->PQexec( sql );
|
1058 |
1134 |
|
1059 |
|
if ( PQntuples( oidCheck ) != 0 )
|
1060 |
|
{
|
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)" )
|
1071 |
|
.arg( quotedValue( mSchemaTableName ) );
|
1072 |
|
|
1073 |
|
Result ctidCheck = connectionRO->PQexec( sql );
|
1074 |
|
|
1075 |
|
if ( PQntuples( ctidCheck ) == 1 )
|
|
1135 |
if ( PQntuples( oidCheck ) != 0 )
|
1076 |
1136 |
{
|
1077 |
|
sql = QString( "SELECT max(substring(ctid::text from E'\\\\((\\\\d+),\\\\d+\\\\)')::integer) from %1" )
|
1078 |
|
.arg( mSchemaTableName );
|
|
1137 |
// Could warn the user here that performance will suffer if
|
|
1138 |
// oid isn't indexed (and that they may want to add a
|
|
1139 |
// primary key to the table)
|
|
1140 |
primaryKey = "oid";
|
|
1141 |
primaryKeyType = "int4";
|
|
1142 |
mIsDbPrimaryKey = true;
|
|
1143 |
}
|
|
1144 |
else
|
|
1145 |
{
|
|
1146 |
sql = QString( "SELECT attname FROM pg_attribute WHERE attname='ctid' AND attrelid=regclass(%1)" )
|
|
1147 |
.arg( quotedValue( mQuery ) );
|
1079 |
1148 |
|
1080 |
1149 |
Result ctidCheck = connectionRO->PQexec( sql );
|
|
1150 |
|
1081 |
1151 |
if ( PQntuples( ctidCheck ) == 1 )
|
1082 |
1152 |
{
|
1083 |
|
int id = QString( PQgetvalue( ctidCheck, 0, 0 ) ).toInt();
|
|
1153 |
sql = QString( "SELECT max(substring(ctid::text from E'\\\\((\\\\d+),\\\\d+\\\\)')::integer) from %1" )
|
|
1154 |
.arg( mQuery );
|
1084 |
1155 |
|
1085 |
|
if ( id < 0x10000 )
|
|
1156 |
Result ctidCheck = connectionRO->PQexec( sql );
|
|
1157 |
if ( PQntuples( ctidCheck ) == 1 )
|
1086 |
1158 |
{
|
1087 |
|
// fallback to ctid
|
1088 |
|
primaryKey = "ctid";
|
1089 |
|
primaryKeyType = "tid";
|
1090 |
|
mIsDbPrimaryKey = true;
|
|
1159 |
int id = QString( PQgetvalue( ctidCheck, 0, 0 ) ).toInt();
|
|
1160 |
|
|
1161 |
if ( id < 0x10000 )
|
|
1162 |
{
|
|
1163 |
// fallback to ctid
|
|
1164 |
primaryKey = "ctid";
|
|
1165 |
primaryKeyType = "tid";
|
|
1166 |
mIsDbPrimaryKey = true;
|
|
1167 |
}
|
1091 |
1168 |
}
|
1092 |
1169 |
}
|
1093 |
1170 |
}
|
1094 |
|
}
|
1095 |
1171 |
|
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() )
|
|
1172 |
if ( primaryKey.isEmpty() )
|
1109 |
1173 |
{
|
1110 |
|
mPrimaryKeyDefault = QString( "max(%1)+1 from %2.%3" )
|
1111 |
|
.arg( quotedIdentifier( primaryKey ) )
|
1112 |
|
.arg( quotedIdentifier( mSchemaName ) )
|
1113 |
|
.arg( quotedIdentifier( mTableName ) );
|
|
1174 |
showMessageBox( tr( "No suitable key column in table" ),
|
|
1175 |
tr( "The table has no column suitable for use as a key.\n\n"
|
|
1176 |
"Quantum GIS requires that the table either has a column of type\n"
|
|
1177 |
"int4 with a unique constraint on it (which includes the\n"
|
|
1178 |
"primary key), has a PostgreSQL oid column or has a ctid\n"
|
|
1179 |
"column with a 16bit block number.\n" ) );
|
1114 |
1180 |
}
|
|
1181 |
else
|
|
1182 |
{
|
|
1183 |
mPrimaryKeyDefault = defaultValue( primaryKey ).toString();
|
|
1184 |
if ( mPrimaryKeyDefault.isNull() )
|
|
1185 |
{
|
|
1186 |
mPrimaryKeyDefault = QString( "max(%1)+1 from %2.%3" )
|
|
1187 |
.arg( quotedIdentifier( primaryKey ) )
|
|
1188 |
.arg( quotedIdentifier( mSchemaName ) )
|
|
1189 |
.arg( quotedIdentifier( mTableName ) );
|
|
1190 |
}
|
|
1191 |
}
|
1115 |
1192 |
}
|
1116 |
|
}
|
1117 |
|
else if ( type == "v" ) // the relation is a view
|
1118 |
|
{
|
1119 |
|
if ( !primaryKey.isEmpty() )
|
|
1193 |
else if ( type == "v" ) // the relation is a view
|
1120 |
1194 |
{
|
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 ) );
|
|
1195 |
if ( !primaryKey.isEmpty() )
|
|
1196 |
{
|
|
1197 |
// check last used candidate
|
|
1198 |
sql = QString( "select pg_type.typname from pg_attribute,pg_type where atttypid=pg_type.oid and attname=%1 and attrelid=regclass(%2)" )
|
|
1199 |
.arg( quotedValue( primaryKey ) ).arg( quotedValue( mQuery ) );
|
1124 |
1200 |
|
1125 |
|
QgsDebugMsg( "checking candidate: " + sql );
|
|
1201 |
QgsDebugMsg( "checking candidate: " + sql );
|
1126 |
1202 |
|
1127 |
|
Result result = connectionRO->PQexec( sql );
|
|
1203 |
Result result = connectionRO->PQexec( sql );
|
1128 |
1204 |
|
1129 |
|
QString type;
|
1130 |
|
if ( PQresultStatus( result ) == PGRES_TUPLES_OK &&
|
1131 |
|
PQntuples( result ) == 1 )
|
1132 |
|
{
|
1133 |
|
type = PQgetvalue( result, 0, 0 );
|
|
1205 |
QString type;
|
|
1206 |
if ( PQresultStatus( result ) == PGRES_TUPLES_OK &&
|
|
1207 |
PQntuples( result ) == 1 )
|
|
1208 |
{
|
|
1209 |
type = PQgetvalue( result, 0, 0 );
|
|
1210 |
}
|
|
1211 |
|
|
1212 |
// mPrimaryKeyDefault stays null and is retrieved later on demand
|
|
1213 |
|
|
1214 |
if (( type != "int4" && type != "oid" ) ||
|
|
1215 |
!uniqueData( mQuery, primaryKey ) )
|
|
1216 |
{
|
|
1217 |
primaryKey = "";
|
|
1218 |
}
|
1134 |
1219 |
}
|
1135 |
1220 |
|
1136 |
|
// mPrimaryKeyDefault stays null and is retrieved later on demand
|
1137 |
|
|
1138 |
|
if (( type != "int4" && type != "oid" ) ||
|
1139 |
|
!uniqueData( mSchemaName, mTableName, primaryKey ) )
|
|
1221 |
if ( primaryKey.isEmpty() )
|
1140 |
1222 |
{
|
1141 |
|
primaryKey = "";
|
|
1223 |
parseView();
|
1142 |
1224 |
}
|
1143 |
1225 |
}
|
1144 |
|
|
1145 |
|
if ( primaryKey.isEmpty() )
|
1146 |
|
{
|
1147 |
|
parseView();
|
1148 |
|
}
|
|
1226 |
else
|
|
1227 |
QgsDebugMsg( "Unexpected relation type of '" + type + "'." );
|
1149 |
1228 |
}
|
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 )
|
|
1229 |
else // have some unique indices on the table. Now choose one...
|
1158 |
1230 |
{
|
1159 |
|
QString col = QString::fromUtf8( PQgetvalue( pk, i, 0 ) );
|
1160 |
|
QStringList columns = col.split( " ", QString::SkipEmptyParts );
|
1161 |
|
if ( columns.count() == 1 )
|
|
1231 |
// choose which (if more than one) unique index to use
|
|
1232 |
std::vector<std::pair<QString, QString> > suitableKeyColumns;
|
|
1233 |
for ( int i = 0; i < PQntuples( pk ); ++i )
|
1162 |
1234 |
{
|
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 )
|
|
1235 |
QString col = QString::fromUtf8( PQgetvalue( pk, i, 0 ) );
|
|
1236 |
QStringList columns = col.split( " ", QString::SkipEmptyParts );
|
|
1237 |
if ( columns.count() == 1 )
|
1169 |
1238 |
{
|
1170 |
|
QString columnName = QString::fromUtf8( PQgetvalue( types, 0, 0 ) );
|
1171 |
|
QString columnType = QString::fromUtf8( PQgetvalue( types, 0, 1 ) );
|
|
1239 |
// Get the column name and data type
|
|
1240 |
sql = QString( "select attname,pg_type.typname from pg_attribute,pg_type where atttypid=pg_type.oid and attnum=%1 and attrelid=regclass(%2)" )
|
|
1241 |
.arg( col ).arg( quotedValue( mQuery ) );
|
|
1242 |
Result types = connectionRO->PQexec( sql );
|
1172 |
1243 |
|
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 ) );
|
|
1244 |
if ( PQntuples( types ) > 0 )
|
|
1245 |
{
|
|
1246 |
QString columnName = QString::fromUtf8( PQgetvalue( types, 0, 0 ) );
|
|
1247 |
QString columnType = QString::fromUtf8( PQgetvalue( types, 0, 1 ) );
|
|
1248 |
|
|
1249 |
if ( columnType != "int4" )
|
|
1250 |
log.append( tr( "The unique index on column '%1' is unsuitable because Quantum GIS does not currently "
|
|
1251 |
"support non-int4 type columns as a key into the table.\n" ).arg( columnName ) );
|
|
1252 |
else
|
|
1253 |
{
|
|
1254 |
mIsDbPrimaryKey = true;
|
|
1255 |
suitableKeyColumns.push_back( std::make_pair( columnName, columnType ) );
|
|
1256 |
}
|
|
1257 |
}
|
1176 |
1258 |
else
|
1177 |
1259 |
{
|
1178 |
|
mIsDbPrimaryKey = true;
|
1179 |
|
suitableKeyColumns.push_back( std::make_pair( columnName, columnType ) );
|
|
1260 |
//QgsDebugMsg( QString("name and type of %3. column of %1.%2 not found").arg(mSchemaName).arg(mTables).arg(col) );
|
1180 |
1261 |
}
|
1181 |
1262 |
}
|
1182 |
1263 |
else
|
1183 |
1264 |
{
|
1184 |
|
//QgsDebugMsg( QString("name and type of %3. column of %1.%2 not found").arg(mSchemaName).arg(mTables).arg(col) );
|
|
1265 |
sql = QString( "select attname from pg_attribute, pg_type where atttypid=pg_type.oid and attnum in (%1) and attrelid=regclass(%2)::oid" )
|
|
1266 |
.arg( col.replace( " ", "," ) )
|
|
1267 |
.arg( quotedValue( mQuery ) );
|
|
1268 |
|
|
1269 |
Result types = connectionRO->PQexec( sql );
|
|
1270 |
QString colNames;
|
|
1271 |
int numCols = PQntuples( types );
|
|
1272 |
for ( int j = 0; j < numCols; ++j )
|
|
1273 |
{
|
|
1274 |
if ( j == numCols - 1 )
|
|
1275 |
colNames += tr( "and " );
|
|
1276 |
colNames += quotedValue( QString::fromUtf8( PQgetvalue( types, j, 0 ) ) );
|
|
1277 |
if ( j < numCols - 2 )
|
|
1278 |
colNames += ",";
|
|
1279 |
}
|
|
1280 |
|
|
1281 |
log.append( tr( "The unique index based on columns %1 is unsuitable because Quantum GIS does not currently "
|
|
1282 |
"support multiple columns as a key into the table.\n" ).arg( colNames ) );
|
1185 |
1283 |
}
|
1186 |
1284 |
}
|
|
1285 |
|
|
1286 |
// suitableKeyColumns now contains the name of columns (and their
|
|
1287 |
// data type) that
|
|
1288 |
// are suitable for use as a key into the table. If there is
|
|
1289 |
// more than one we need to choose one. For the moment, just
|
|
1290 |
// choose the first in the list.
|
|
1291 |
|
|
1292 |
if ( suitableKeyColumns.size() > 0 )
|
|
1293 |
{
|
|
1294 |
primaryKey = suitableKeyColumns[0].first;
|
|
1295 |
primaryKeyType = suitableKeyColumns[0].second;
|
|
1296 |
}
|
1187 |
1297 |
else
|
1188 |
1298 |
{
|
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 ) );
|
|
1299 |
// If there is an oid on the table, use that instead,
|
|
1300 |
// otherwise give up
|
|
1301 |
sql = QString( "select attname from pg_attribute where attname='oid' and attrelid=regclass(%1)::oid" ).arg( quotedValue( mQuery ) );
|
|
1302 |
Result oidCheck = connectionRO->PQexec( sql );
|
1192 |
1303 |
|
1193 |
|
Result types = connectionRO->PQexec( sql );
|
1194 |
|
QString colNames;
|
1195 |
|
int numCols = PQntuples( types );
|
1196 |
|
for ( int j = 0; j < numCols; ++j )
|
|
1304 |
if ( PQntuples( oidCheck ) != 0 )
|
1197 |
1305 |
{
|
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 += ",";
|
|
1306 |
primaryKey = "oid";
|
|
1307 |
primaryKeyType = "int4";
|
1203 |
1308 |
}
|
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 ) );
|
|
1309 |
else
|
|
1310 |
{
|
|
1311 |
log.prepend( "There were no columns in the table that were suitable "
|
|
1312 |
"as a qgis key into the table (either a column with a "
|
|
1313 |
"unique index and type int4 or a PostgreSQL oid column.\n" );
|
|
1314 |
}
|
1207 |
1315 |
}
|
1208 |
|
}
|
1209 |
1316 |
|
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 )
|
|
1317 |
// Either primaryKey has been set by the above code, or it
|
|
1318 |
// hasn't. If not, present some info to the user to give them some
|
|
1319 |
// idea of why not.
|
|
1320 |
if ( primaryKey.isEmpty() )
|
1229 |
1321 |
{
|
1230 |
|
primaryKey = "oid";
|
1231 |
|
primaryKeyType = "int4";
|
|
1322 |
// Give some info to the user about why things didn't work out.
|
|
1323 |
valid = false;
|
|
1324 |
showMessageBox( tr( "Unable to find a key column" ), log );
|
1232 |
1325 |
}
|
1233 |
1326 |
else
|
1234 |
1327 |
{
|
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" );
|
|
1328 |
mPrimaryKeyDefault = defaultValue( primaryKey ).toString();
|
|
1329 |
if ( mPrimaryKeyDefault.isNull() )
|
|
1330 |
{
|
|
1331 |
mPrimaryKeyDefault = QString( "max(%1)+1 from %2.%3" )
|
|
1332 |
.arg( quotedIdentifier( primaryKey ) )
|
|
1333 |
.arg( quotedIdentifier( mSchemaName ) )
|
|
1334 |
.arg( quotedIdentifier( mTableName ) );
|
|
1335 |
}
|
1238 |
1336 |
}
|
1239 |
1337 |
}
|
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 |
1338 |
}
|
1262 |
1339 |
|
1263 |
1340 |
if ( !primaryKey.isNull() )
|
... | ... | |
1436 |
1513 |
.arg( quotedValue( i->second.column ) );
|
1437 |
1514 |
Result result = connectionRO->PQexec( sql );
|
1438 |
1515 |
|
1439 |
|
if ( PQntuples( result ) > 0 && uniqueData( mSchemaName, mTableName, i->first ) )
|
|
1516 |
if ( PQntuples( result ) > 0 && uniqueData( mQuery, i->first ) )
|
1440 |
1517 |
{
|
1441 |
1518 |
// Got one. Use it.
|
1442 |
1519 |
key = i->first;
|
... | ... | |
1451 |
1528 |
// exists). This is legacy support and could be removed in
|
1452 |
1529 |
// future.
|
1453 |
1530 |
i = suitable.find( "oid" );
|
1454 |
|
if ( i != suitable.end() && uniqueData( mSchemaName, mTableName, i->first ) )
|
|
1531 |
if ( i != suitable.end() && uniqueData( mQuery, i->first ) )
|
1455 |
1532 |
{
|
1456 |
1533 |
key = i->first;
|
1457 |
1534 |
|
... | ... | |
1466 |
1543 |
tableCols::const_iterator i = suitable.begin();
|
1467 |
1544 |
for ( ; i != suitable.end(); ++i )
|
1468 |
1545 |
{
|
1469 |
|
if ( uniqueData( mSchemaName, mTableName, i->first ) )
|
|
1546 |
if ( uniqueData( mQuery, i->first ) )
|
1470 |
1547 |
{
|
1471 |
1548 |
key = i->first;
|
1472 |
1549 |
|
... | ... | |
1503 |
1580 |
return key;
|
1504 |
1581 |
}
|
1505 |
1582 |
|
1506 |
|
bool QgsPostgresProvider::uniqueData( QString schemaName,
|
1507 |
|
QString tableName, QString colName )
|
|
1583 |
bool QgsPostgresProvider::uniqueData( QString query, QString colName )
|
1508 |
1584 |
{
|
1509 |
1585 |
// Check to see if the given column contains unique data
|
1510 |
1586 |
|
1511 |
1587 |
bool isUnique = false;
|
1512 |
1588 |
|
1513 |
|
QString sql = QString( "select count(distinct %1)=count(%1) from %2.%3" )
|
|
1589 |
QString sql = QString( "select count(distinct %1)=count(%1) from %2" )
|
1514 |
1590 |
.arg( quotedIdentifier( colName ) )
|
1515 |
|
.arg( quotedIdentifier( schemaName ) )
|
1516 |
|
.arg( quotedIdentifier( tableName ) );
|
|
1591 |
.arg( mQuery );
|
1517 |
1592 |
|
1518 |
1593 |
if ( !sqlWhereClause.isEmpty() )
|
1519 |
1594 |
{
|
... | ... | |
1780 |
1855 |
{
|
1781 |
1856 |
// get the field name
|
1782 |
1857 |
const QgsField &fld = field( index );
|
1783 |
|
QString sql;
|
1784 |
|
if ( sqlWhereClause.isEmpty() )
|
|
1858 |
QString sql = QString( "select min(%1) from %2" )
|
|
1859 |
.arg( quotedIdentifier( fld.name() ) )
|
|
1860 |
.arg( mQuery );
|
|
1861 |
|
|
1862 |
if ( !sqlWhereClause.isEmpty() )
|
1785 |
1863 |
{
|
1786 |
|
sql = QString( "select min(%1) from %2" )
|
1787 |
|
.arg( quotedIdentifier( fld.name() ) )
|
1788 |
|
.arg( mSchemaTableName );
|
|
1864 |
sql += QString( " where %1" ).arg( sqlWhereClause );
|
1789 |
1865 |
}
|
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 |
|
}
|
|
1866 |
|
1797 |
1867 |
Result rmin = connectionRO->PQexec( sql );
|
1798 |
1868 |
return convertValue( fld.type(), QString::fromUtf8( PQgetvalue( rmin, 0, 0 ) ) );
|
1799 |
1869 |
}
|
... | ... | |
1812 |
1882 |
{
|
1813 |
1883 |
// get the field name
|
1814 |
1884 |
const QgsField &fld = field( index );
|
1815 |
|
QString sql;
|
1816 |
|
if ( sqlWhereClause.isEmpty() )
|
|
1885 |
QString sql = QString( "select distinct %1 from %2" )
|
|
1886 |
.arg( quotedIdentifier( fld.name() ) )
|
|
1887 |
.arg( mQuery );
|
|
1888 |
|
|
1889 |
if ( !sqlWhereClause.isEmpty() )
|
1817 |
1890 |
{
|
1818 |
|
sql = QString( "select distinct %1 from %2 order by %1" )
|
1819 |
|
.arg( quotedIdentifier( fld.name() ) )
|
1820 |
|
.arg( mSchemaTableName );
|
|
1891 |
sql += QString( " where %1" ).arg( sqlWhereClause );
|
1821 |
1892 |
}
|
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 |
1893 |
|
|
1894 |
sql += QString( " order by %1" )
|
|
1895 |
.arg( quotedIdentifier( fld.name() ) );
|
|
1896 |
|
1830 |
1897 |
if ( limit >= 0 )
|
1831 |
1898 |
{
|
1832 |
1899 |
sql += QString( " LIMIT %1" ).arg( limit );
|
... | ... | |
1891 |
1958 |
bool QgsPostgresProvider::parseEnumRange( QStringList& enumValues, const QString& attributeName ) const
|
1892 |
1959 |
{
|
1893 |
1960 |
enumValues.clear();
|
1894 |
|
QString enumRangeSql = QString( "SELECT enum_range(%1) from %2 limit 1" ).arg( quotedIdentifier( attributeName ) ).arg( mSchemaTableName );
|
|
1961 |
QString enumRangeSql = QString( "SELECT enum_range(%1) from %2 limit 1" )
|
|
1962 |
.arg( quotedIdentifier( attributeName ) )
|
|
1963 |
.arg( mQuery );
|
1895 |
1964 |
Result enumRangeRes = connectionRO->PQexec( enumRangeSql );
|
1896 |
1965 |
if ( PQresultStatus( enumRangeRes ) == PGRES_TUPLES_OK && PQntuples( enumRangeRes ) > 0 )
|
1897 |
1966 |
{
|
... | ... | |
1979 |
2048 |
{
|
1980 |
2049 |
// get the field name
|
1981 |
2050 |
const QgsField &fld = field( index );
|
1982 |
|
QString sql;
|
1983 |
|
if ( sqlWhereClause.isEmpty() )
|
|
2051 |
QString sql = QString( "select max(%1) from %2" )
|
|
2052 |
.arg( quotedIdentifier( fld.name() ) )
|
|
2053 |
.arg( mQuery );
|
|
2054 |
|
|
2055 |
if ( !sqlWhereClause.isEmpty() )
|
1984 |
2056 |
{
|
1985 |
|
sql = QString( "select max(%1) from %2" )
|
1986 |
|
.arg( quotedIdentifier( fld.name() ) )
|
1987 |
|
.arg( mSchemaTableName );
|
|
2057 |
sql += QString( " where %1" ).arg( sqlWhereClause );
|
1988 |
2058 |
}
|
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 |
|
}
|
|
2059 |
|
1996 |
2060 |
Result rmax = connectionRO->PQexec( sql );
|
1997 |
2061 |
return convertValue( fld.type(), QString::fromUtf8( PQgetvalue( rmax, 0, 0 ) ) );
|
1998 |
2062 |
}
|
... | ... | |
2151 |
2215 |
if ( flist.size() == 0 )
|
2152 |
2216 |
return true;
|
2153 |
2217 |
|
|
2218 |
if ( isQuery )
|
|
2219 |
return false;
|
|
2220 |
|
2154 |
2221 |
if ( !connectRW() )
|
2155 |
2222 |
return false;
|
2156 |
2223 |
|
... | ... | |
2162 |
2229 |
|
2163 |
2230 |
// Prepare the INSERT statement
|
2164 |
2231 |
QString insert = QString( "INSERT INTO %1(%2" )
|
2165 |
|
.arg( mSchemaTableName )
|
|
2232 |
.arg( mQuery )
|
2166 |
2233 |
.arg( quotedIdentifier( geometryColumn ) ),
|
2167 |
2234 |
values = QString( ") VALUES (GeomFromWKB($1%1,%2)" )
|
2168 |
2235 |
.arg( connectionRW->useWkbHex() ? "" : "::bytea" )
|
... | ... | |
2316 |
2383 |
{
|
2317 |
2384 |
bool returnvalue = true;
|
2318 |
2385 |
|
|
2386 |
if ( isQuery )
|
|
2387 |
return false;
|
|
2388 |
|
2319 |
2389 |
if ( !connectRW() )
|
2320 |
2390 |
return false;
|
2321 |
2391 |
|
... | ... | |
2326 |
2396 |
for ( QgsFeatureIds::const_iterator it = id.begin(); it != id.end(); ++it )
|
2327 |
2397 |
{
|
2328 |
2398 |
QString sql = QString( "DELETE FROM %1 WHERE %2" )
|
2329 |
|
.arg( mSchemaTableName ).arg( whereClause( *it ) );
|
|
2399 |
.arg( mQuery ).arg( whereClause( *it ) );
|
2330 |
2400 |
QgsDebugMsg( "delete sql: " + sql );
|
2331 |
2401 |
|
2332 |
2402 |
//send DELETE statement and do error handling
|
... | ... | |
2354 |
2424 |
{
|
2355 |
2425 |
bool returnvalue = true;
|
2356 |
2426 |
|
|
2427 |
if ( isQuery )
|
|
2428 |
return false;
|
|
2429 |
|
2357 |
2430 |
if ( !connectRW() )
|
2358 |
2431 |
return false;
|
2359 |
2432 |
|
... | ... | |
2374 |
2447 |
}
|
2375 |
2448 |
|
2376 |
2449 |
QString sql = QString( "ALTER TABLE %1 ADD COLUMN %2 %3" )
|
2377 |
|
.arg( mSchemaTableName )
|
|
2450 |
.arg( mQuery )
|
2378 |
2451 |
.arg( quotedIdentifier( iter->name() ) )
|
2379 |
2452 |
.arg( type );
|
2380 |
2453 |
QgsDebugMsg( sql );
|
... | ... | |
2388 |
2461 |
if ( !iter->comment().isEmpty() )
|
2389 |
2462 |
{
|
2390 |
2463 |
sql = QString( "COMMENT ON COLUMN %1.%2 IS %3" )
|
2391 |
|
.arg( mSchemaTableName )
|
|
2464 |
.arg( mQuery )
|
2392 |
2465 |
.arg( quotedIdentifier( iter->name() ) )
|
2393 |
2466 |
.arg( quotedValue( iter->comment() ) );
|
2394 |
2467 |
result = connectionRW->PQexec( sql );
|
... | ... | |
2415 |
2488 |
{
|
2416 |
2489 |
bool returnvalue = true;
|
2417 |
2490 |
|
|
2491 |
if ( !isQuery )
|
|
2492 |
return false;
|
|
2493 |
|
2418 |
2494 |
if ( !connectRW() )
|
2419 |
2495 |
return false;
|
2420 |
2496 |
|
... | ... | |
2430 |
2506 |
|
2431 |
2507 |
QString column = field_it->name();
|
2432 |
2508 |
QString sql = QString( "ALTER TABLE %1 DROP COLUMN %2" )
|
2433 |
|
.arg( mSchemaTableName )
|
|
2509 |
.arg( mQuery )
|
2434 |
2510 |
.arg( quotedIdentifier( column ) );
|
2435 |
2511 |
|
2436 |
2512 |
//send sql statement and do error handling
|
... | ... | |
2460 |
2536 |
{
|
2461 |
2537 |
bool returnvalue = true;
|
2462 |
2538 |
|
|
2539 |
if ( !isQuery )
|
|
2540 |
return false;
|
|
2541 |
|
2463 |
2542 |
if ( !connectRW() )
|
2464 |
2543 |
return false;
|
2465 |
2544 |
|
... | ... | |
2476 |
2555 |
if ( fid < 0 )
|
2477 |
2556 |
continue;
|
2478 |
2557 |
|
2479 |
|
QString sql = QString( "UPDATE %1 SET " ).arg( mSchemaTableName );
|
|
2558 |
QString sql = QString( "UPDATE %1 SET " ).arg( mQuery );
|
2480 |
2559 |
bool first = true;
|
2481 |
2560 |
|
2482 |
2561 |
const QgsAttributeMap& attrs = iter.value();
|
... | ... | |
2541 |
2620 |
{
|
2542 |
2621 |
QgsDebugMsg( "entering." );
|
2543 |
2622 |
|
|
2623 |
if ( !isQuery )
|
|
2624 |
return false;
|
|
2625 |
|
2544 |
2626 |
if ( !connectRW() )
|
2545 |
2627 |
return false;
|
2546 |
2628 |
|
... | ... | |
2552 |
2634 |
connectionRW->PQexecNR( "BEGIN" );
|
2553 |
2635 |
|
2554 |
2636 |
QString update = QString( "UPDATE %1 SET %2=GeomFromWKB($1%3,%4) WHERE %5=$2" )
|
2555 |
|
.arg( mSchemaTableName )
|
|
2637 |
.arg( mQuery )
|
2556 |
2638 |
.arg( quotedIdentifier( geometryColumn ) )
|
2557 |
2639 |
.arg( connectionRW->useWkbHex() ? "" : "::bytea" )
|
2558 |
2640 |
.arg( srid )
|
... | ... | |
2636 |
2718 |
|
2637 |
2719 |
sqlWhereClause = theSQL;
|
2638 |
2720 |
|
2639 |
|
if ( !mIsDbPrimaryKey && !uniqueData( mSchemaName, mTableName, primaryKey ) )
|
|
2721 |
if ( !mIsDbPrimaryKey && !uniqueData( mQuery, primaryKey ) )
|
2640 |
2722 |
{
|
2641 |
2723 |
sqlWhereClause = prevWhere;
|
2642 |
2724 |
return false;
|
... | ... | |
2663 |
2745 |
// a thread the task of getting the full count.
|
2664 |
2746 |
QString sql;
|
2665 |
2747 |
|
2666 |
|
if ( mUseEstimatedMetadata )
|
|
2748 |
if ( !isQuery && mUseEstimatedMetadata )
|
2667 |
2749 |
{
|
2668 |
|
sql = QString( "select reltuples::int from pg_catalog.pg_class where oid=regclass(%1)::oid" ).arg( quotedValue( mSchemaTableName ) );
|
|
2750 |
sql = QString( "select reltuples::int from pg_catalog.pg_class where oid=regclass(%1)::oid" ).arg( quotedValue( mQuery ) );
|
2669 |
2751 |
}
|
2670 |
2752 |
else
|
2671 |
2753 |
{
|
2672 |
|
sql = QString( "select count(*) from %1" ).arg( mSchemaTableName );
|
|
2754 |
sql = QString( "select count(*) from %1" ).arg( mQuery );
|
2673 |
2755 |
|
2674 |
|
if ( sqlWhereClause.length() > 0 )
|
|
2756 |
if ( !sqlWhereClause.isEmpty() )
|
2675 |
2757 |
{
|
2676 |
2758 |
sql += " where " + sqlWhereClause;
|
2677 |
2759 |
}
|
... | ... | |
2696 |
2778 |
QString ext;
|
2697 |
2779 |
|
2698 |
2780 |
// get the extents
|
2699 |
|
if ( mUseEstimatedMetadata || sqlWhereClause.isEmpty() )
|
|
2781 |
if ( !isQuery && ( mUseEstimatedMetadata || sqlWhereClause.isEmpty() ) )
|
2700 |
2782 |
{
|
2701 |
2783 |
// do stats exists?
|
2702 |
2784 |
sql = QString( "SELECT COUNT(*) FROM pg_stats WHERE schemaname=%1 AND tablename=%2 AND attname=%3" )
|
... | ... | |
2727 |
2809 |
{
|
2728 |
2810 |
sql = QString( "select extent(%1) from %2" )
|
2729 |
2811 |
.arg( quotedIdentifier( geometryColumn ) )
|
2730 |
|
.arg( mSchemaTableName );
|
|
2812 |
.arg( mQuery );
|
2731 |
2813 |
|
2732 |
2814 |
if ( !sqlWhereClause.isEmpty() )
|
2733 |
|
sql += QString( "where %1" ).arg( sqlWhereClause );
|
|
2815 |
sql += QString( " where %1" ).arg( sqlWhereClause );
|
2734 |
2816 |
|
2735 |
2817 |
result = connectionRO->PQexec( sql );
|
2736 |
2818 |
if ( PQresultStatus( result ) != PGRES_TUPLES_OK )
|
... | ... | |
2823 |
2905 |
// version 7.4, binary cursors return data in XDR whereas previous versions
|
2824 |
2906 |
// return data in the endian of the server
|
2825 |
2907 |
|
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 ) );
|
|
2908 |
QString oidValue;
|
|
2909 |
QString query;
|
2830 |
2910 |
|
|
2911 |
if ( isQuery )
|
|
2912 |
{
|
|
2913 |
QString sql = QString( "select * from %1 limit 0" ).arg( mQuery );
|
|
2914 |
Result res = connectionRO->PQexec( sql );
|
|
2915 |
|
|
2916 |
// loop through the returned fields to get a valid oid
|
|
2917 |
int i;
|
|
2918 |
for ( i = 0; i < PQnfields( res ); i++ )
|
|
2919 |
{
|
|
2920 |
int tableoid = PQftable( res, i );
|
|
2921 |
if ( tableoid >= 0 )
|
|
2922 |
{
|
|
2923 |
oidValue = QString::number( tableoid );
|
|
2924 |
break;
|
|
2925 |
}
|
|
2926 |
}
|
|
2927 |
|
|
2928 |
if ( i < PQnfields( res ) )
|
|
2929 |
{
|
|
2930 |
// get the table name
|
|
2931 |
res = connectionRO->PQexec( QString( "SELECT relname FROM pg_class WHERE oid=%1" ).arg( oidValue ) );
|
|
2932 |
query = QString::fromUtf8( PQgetvalue( res, 0, 0 ) );
|
|
2933 |
}
|
|
2934 |
else
|
|
2935 |
{
|
|
2936 |
QgsDebugMsg( "no oid found" );
|
|
2937 |
return false;
|
|
2938 |
}
|
|
2939 |
}
|
|
2940 |
else
|
|
2941 |
{
|
|
2942 |
QString firstOid = QString( "select regclass(%1)::oid" ).arg( quotedValue( mQuery ) );
|
|
2943 |
Result oidResult = connectionRO->PQexec( firstOid );
|
|
2944 |
// get the int value from a "normal" select
|
|
2945 |
oidValue = QString::fromUtf8( PQgetvalue( oidResult, 0, 0 ) );
|
|
2946 |
}
|
|
2947 |
|
2831 |
2948 |
QgsDebugMsg( "Creating binary cursor" );
|
2832 |
2949 |
|
2833 |
2950 |
// get the same value using a binary cursor
|
2834 |
|
connectionRO->openCursor( "oidcursor", QString( "select regclass(%1)::oid" ).arg( quotedValue( mSchemaTableName ) ) );
|
|
2951 |
connectionRO->openCursor( "oidcursor", QString( "select regclass(%1)::oid" ).arg( quotedValue( query ) ) );
|
2835 |
2952 |
|
2836 |
2953 |
QgsDebugMsg( "Fetching a record and attempting to get check endian-ness" );
|
2837 |
2954 |
|
... | ... | |
2861 |
2978 |
valid = false;
|
2862 |
2979 |
QStringList log;
|
2863 |
2980 |
|
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 ) );
|
|
2981 |
Result result;
|
|
2982 |
QString sql;
|
2869 |
2983 |
|
2870 |
|
QgsDebugMsg( "Getting geometry column: " + sql );
|
|
2984 |
if ( !isQuery )
|
|
2985 |
{
|
|
2986 |
sql = QString( "select type,srid from geometry_columns"
|
|
2987 |
" where f_table_name=%1 and f_geometry_column=%2 and f_table_schema=%3" )
|
|
2988 |
.arg( quotedValue( mTableName ) )
|
|
2989 |
.arg( quotedValue( geometryColumn ) )
|
|
2990 |
.arg( quotedValue( mSchemaName ) );
|
2871 |
2991 |
|
2872 |
|
Result result = connectionRO->PQexec( sql );
|
|
2992 |
QgsDebugMsg( "Getting geometry column: " + sql );
|
2873 |
2993 |
|
2874 |
|
QgsDebugMsg( "geometry column query returned " + QString::number( PQntuples( result ) ) );
|
|
2994 |
Result result = connectionRO->PQexec( sql );
|
2875 |
2995 |
|
2876 |
|
if ( PQntuples( result ) > 0 )
|
2877 |
|
{
|
2878 |
|
fType = QString::fromUtf8( PQgetvalue( result, 0, 0 ) );
|
2879 |
|
srid = QString::fromUtf8( PQgetvalue( result, 0, 1 ) );
|
|
2996 |
QgsDebugMsg( "geometry column query returned " + QString::number( PQntuples( result ) ) );
|
|
2997 |
|
|
2998 |
if ( PQntuples( result ) > 0 )
|
|
2999 |
{
|
|
3000 |
fType = QString::fromUtf8( PQgetvalue( result, 0, 0 ) );
|
|
3001 |
srid = QString::fromUtf8( PQgetvalue( result, 0, 1 ) );
|
|
3002 |
}
|
2880 |
3003 |
}
|
2881 |
|
else
|
|
3004 |
|
|
3005 |
if ( srid.isEmpty() || fType.isEmpty() )
|
2882 |
3006 |
{
|
2883 |
3007 |
// Didn't find what we need in the geometry_columns table, so
|
2884 |
3008 |
// get stuff from the relevant column instead. This may (will?)
|
2885 |
3009 |
// fail if there is no data in the relevant table.
|
2886 |
|
sql = QString( "select srid(%1),geometrytype(%1) from %2" )
|
|
3010 |
sql = QString( "select srid(%1), geometrytype(%1) from %2" )
|
2887 |
3011 |
.arg( quotedIdentifier( geometryColumn ) )
|
2888 |
|
.arg( mSchemaTableName );
|
|
3012 |
.arg( mQuery );
|
2889 |
3013 |
|
2890 |
3014 |
//it is possible that the where clause restricts the feature type
|
2891 |
3015 |
if ( !sqlWhereClause.isEmpty() )
|
... | ... | |
2921 |
3045 |
{
|
2922 |
3046 |
sql += QString( "(select %1 from %2 where %1 is not null limit %3) as t" )
|
2923 |
3047 |
.arg( quotedIdentifier( geometryColumn ) )
|
2924 |
|
.arg( mSchemaTableName )
|
|
3048 |
.arg( mQuery )
|
2925 |
3049 |
.arg( sGeomTypeSelectLimit );
|
2926 |
3050 |
}
|
2927 |
3051 |
else
|
2928 |
3052 |
{
|
2929 |
|
sql += mSchemaTableName;
|
|
3053 |
sql += mQuery;
|
2930 |
3054 |
}
|
2931 |
3055 |
|
2932 |
|
if ( mUri.sql() != "" )
|
2933 |
|
sql += " where " + mUri.sql();
|
|
3056 |
if ( !sqlWhereClause.isEmpty() )
|
|
3057 |
sql += " where " + sqlWhereClause;
|
2934 |
3058 |
|
2935 |
3059 |
result = connectionRO->PQexec( sql );
|
2936 |
3060 |
|
... | ... | |
2967 |
3091 |
{
|
2968 |
3092 |
showMessageBox( tr( "Unknown geometry type" ),
|
2969 |
3093 |
tr( "Column %1 in %2 has a geometry type of %3, which Quantum GIS does not currently support." )
|
2970 |
|
.arg( geometryColumn ).arg( mSchemaTableName ).arg( fType ) );
|
|
3094 |
.arg( geometryColumn ).arg( mQuery ).arg( fType ) );
|
2971 |
3095 |
valid = false;
|
2972 |
3096 |
}
|
2973 |
3097 |
}
|
... | ... | |
2975 |
3099 |
{
|
2976 |
3100 |
log.prepend( tr( "Quantum GIS was unable to determine the type and srid of column %1 in %2. The database communication log was:\n%3" )
|
2977 |
3101 |
.arg( geometryColumn )
|
2978 |
|
.arg( mSchemaTableName )
|
|
3102 |
.arg( mQuery )
|
2979 |
3103 |
.arg( QString::fromUtf8( PQresultErrorMessage( result ) ) ) );
|
2980 |
3104 |
showMessageBox( tr( "Unable to get feature type and srid" ), log );
|
2981 |
3105 |
}
|
... | ... | |
3040 |
3164 |
QgsDebugMsgLevel( err, 3 );
|
3041 |
3165 |
}
|
3042 |
3166 |
}
|
|
3167 |
else
|
|
3168 |
{
|
|
3169 |
QgsDebugMsgLevel( QString( "Query failed: %1" ).arg( query ), 3 );
|
|
3170 |
}
|
3043 |
3171 |
#endif
|
3044 |
3172 |
|
3045 |
3173 |
return res;
|
... | ... | |
3081 |
3209 |
QString err = QString( "Query: %1 returned %2 [%3]" )
|
3082 |
3210 |
.arg( query )
|
3083 |
3211 |
.arg( errorStatus )
|
3084 |
|
.arg( PQresultErrorMessage( res ) );
|
|
3212 |
.arg( QString::fromUtf8( PQresultErrorMessage( res ) ) );
|
3085 |
3213 |
QgsDebugMsgLevel( err, 3 );
|
3086 |
3214 |
#endif
|
3087 |
3215 |
if ( openCursors )
|
3088 |
3216 |
{
|
3089 |
3217 |
PQexecNR( "ROLLBACK" );
|
3090 |
|
QgsDebugMsg( QString( "Re-starting read-only transaction after errornous statement - state of %1 cursors lost" ).arg( openCursors ) );
|
|
3218 |
|
|
3219 |
QgsPostgresProvider::showMessageBox(
|
|
3220 |
tr( "Query failed" ),
|
|
3221 |
tr( "%1 cursor states lost.\nSQL: %2\nResult: %3 (%4)" )
|
|
3222 |
.arg( openCursors )
|
|
3223 |
.arg( query )
|
|
3224 |
.arg( errorStatus )
|
|
3225 |
.arg( QString::fromUtf8( PQresultErrorMessage( res ) ) ) );
|
|
3226 |
openCursors = 0;
|
|
3227 |
|
3091 |
3228 |
PQexecNR( "BEGIN READ ONLY" );
|
3092 |
3229 |
}
|
3093 |
3230 |
}
|