@@ -117,8 +117,10 @@ public AirbyteCatalog discover(final JsonNode config) throws Exception {
117
117
}
118
118
119
119
@ Override
120
- public List <CheckedConsumer <JdbcDatabase , Exception >> getCheckOperations (final JsonNode config ) throws Exception {
121
- final List <CheckedConsumer <JdbcDatabase , Exception >> checkOperations = new ArrayList <>(super .getCheckOperations (config ));
120
+ public List <CheckedConsumer <JdbcDatabase , Exception >> getCheckOperations (final JsonNode config )
121
+ throws Exception {
122
+ final List <CheckedConsumer <JdbcDatabase , Exception >> checkOperations = new ArrayList <>(
123
+ super .getCheckOperations (config ));
122
124
123
125
if (isCdc (config )) {
124
126
checkOperations .add (database -> {
@@ -129,21 +131,24 @@ public List<CheckedConsumer<JdbcDatabase, Exception>> getCheckOperations(final J
129
131
ps .setString (2 , PostgresUtils .getPluginValue (config .get ("replication_method" )));
130
132
ps .setString (3 , config .get ("database" ).asText ());
131
133
132
- LOGGER .info ("Attempting to find the named replication slot using the query: " + ps .toString ());
134
+ LOGGER .info (
135
+ "Attempting to find the named replication slot using the query: " + ps .toString ());
133
136
134
137
return ps ;
135
138
}, sourceOperations ::rowToJson ).collect (toList ());
136
139
137
140
if (matchingSlots .size () != 1 ) {
138
- throw new RuntimeException ("Expected exactly one replication slot but found " + matchingSlots .size ()
139
- + ". Please read the docs and add a replication slot to your database." );
141
+ throw new RuntimeException (
142
+ "Expected exactly one replication slot but found " + matchingSlots .size ()
143
+ + ". Please read the docs and add a replication slot to your database." );
140
144
}
141
145
142
146
});
143
147
144
148
checkOperations .add (database -> {
145
149
final List <JsonNode > matchingPublications = database .query (connection -> {
146
- final PreparedStatement ps = connection .prepareStatement ("SELECT * FROM pg_publication WHERE pubname = ?" );
150
+ final PreparedStatement ps = connection
151
+ .prepareStatement ("SELECT * FROM pg_publication WHERE pubname = ?" );
147
152
ps .setString (1 , config .get ("replication_method" ).get ("publication" ).asText ());
148
153
149
154
LOGGER .info ("Attempting to find the publication using the query: " + ps .toString ());
@@ -152,8 +157,9 @@ public List<CheckedConsumer<JdbcDatabase, Exception>> getCheckOperations(final J
152
157
}, sourceOperations ::rowToJson ).collect (toList ());
153
158
154
159
if (matchingPublications .size () != 1 ) {
155
- throw new RuntimeException ("Expected exactly one publication but found " + matchingPublications .size ()
156
- + ". Please read the docs and add a publication to your database." );
160
+ throw new RuntimeException (
161
+ "Expected exactly one publication but found " + matchingPublications .size ()
162
+ + ". Please read the docs and add a publication to your database." );
157
163
}
158
164
159
165
});
@@ -163,7 +169,9 @@ public List<CheckedConsumer<JdbcDatabase, Exception>> getCheckOperations(final J
163
169
}
164
170
165
171
@ Override
166
- public AutoCloseableIterator <AirbyteMessage > read (final JsonNode config , final ConfiguredAirbyteCatalog catalog , final JsonNode state )
172
+ public AutoCloseableIterator <AirbyteMessage > read (final JsonNode config ,
173
+ final ConfiguredAirbyteCatalog catalog ,
174
+ final JsonNode state )
167
175
throws Exception {
168
176
// this check is used to ensure that have the pgoutput slot available so Debezium won't attempt to
169
177
// create it.
@@ -177,7 +185,8 @@ public AutoCloseableIterator<AirbyteMessage> read(final JsonNode config, final C
177
185
}
178
186
179
187
@ Override
180
- public List <AutoCloseableIterator <AirbyteMessage >> getIncrementalIterators (final JdbcDatabase database ,
188
+ public List <AutoCloseableIterator <AirbyteMessage >> getIncrementalIterators (
189
+ final JdbcDatabase database ,
181
190
final ConfiguredAirbyteCatalog catalog ,
182
191
final Map <String , TableInfo <CommonField <JDBCType >>> tableNameToTable ,
183
192
final StateManager stateManager ,
@@ -192,10 +201,13 @@ public List<AutoCloseableIterator<AirbyteMessage>> getIncrementalIterators(final
192
201
*/
193
202
final JsonNode sourceConfig = database .getSourceConfig ();
194
203
if (isCdc (sourceConfig )) {
195
- final AirbyteDebeziumHandler handler = new AirbyteDebeziumHandler (sourceConfig , PostgresCdcTargetPosition .targetPosition (database ),
204
+ final AirbyteDebeziumHandler handler = new AirbyteDebeziumHandler (sourceConfig ,
205
+ PostgresCdcTargetPosition .targetPosition (database ),
196
206
PostgresCdcProperties .getDebeziumProperties (sourceConfig ), catalog , false );
197
- return handler .getIncrementalIterators (new PostgresCdcSavedInfoFetcher (stateManager .getCdcStateManager ().getCdcState ()),
198
- new PostgresCdcStateHandler (stateManager ), new PostgresCdcConnectorMetadataInjector (), emittedAt );
207
+ return handler .getIncrementalIterators (
208
+ new PostgresCdcSavedInfoFetcher (stateManager .getCdcStateManager ().getCdcState ()),
209
+ new PostgresCdcStateHandler (stateManager ), new PostgresCdcConnectorMetadataInjector (),
210
+ emittedAt );
199
211
200
212
} else {
201
213
return super .getIncrementalIterators (database , catalog , tableNameToTable , stateManager , emittedAt );
@@ -228,13 +240,47 @@ private static AirbyteStream removeIncrementalWithoutPk(final AirbyteStream stre
228
240
}
229
241
230
242
@ Override
231
- public Set <JdbcPrivilegeDto > getPrivilegesTableForCurrentUser (final JdbcDatabase database , final String schema ) throws SQLException {
243
+ public Set <JdbcPrivilegeDto > getPrivilegesTableForCurrentUser (final JdbcDatabase database ,
244
+ final String schema )
245
+ throws SQLException {
232
246
return database .query (connection -> {
233
247
final PreparedStatement ps = connection .prepareStatement (
234
- "SELECT DISTINCT table_catalog, table_schema, table_name, privilege_type\n "
235
- + "FROM information_schema.table_privileges\n "
236
- + "WHERE grantee = ? AND privilege_type = 'SELECT'" );
237
- ps .setString (1 , database .getDatabaseConfig ().get ("username" ).asText ());
248
+ """
249
+ SELECT DISTINCT table_catalog,
250
+ table_schema,
251
+ table_name,
252
+ privilege_type
253
+ FROM information_schema.table_privileges
254
+ WHERE grantee = ?
255
+ AND privilege_type = 'SELECT'
256
+ UNION ALL
257
+ SELECT r.rolname AS table_catalog,
258
+ n.nspname AS table_schema,
259
+ c.relname AS table_name,
260
+ -- the initial query is supposed to get a SELECT type. Since we use a UNION query
261
+ -- to get Views that we can read (i.e. select) - then lets fill this columns with SELECT
262
+ -- value to keep the backward-compatibility
263
+ COALESCE ('SELECT') AS privilege_type
264
+ FROM pg_class c
265
+ JOIN pg_namespace n
266
+ ON n.oid = relnamespace
267
+ JOIN pg_roles r
268
+ ON r.oid = relowner,
269
+ Unnest(COALESCE(relacl::text[], Format('{%s=arwdDxt/%s}', rolname, rolname)::text[])) acl,
270
+ Regexp_split_to_array(acl, '=|/') s
271
+ WHERE r.rolname = ?
272
+ AND nspname = 'public'
273
+ -- 'm' means Materialized View
274
+ AND c.relkind = 'm'
275
+ AND (
276
+ -- all grants
277
+ c.relacl IS NULL
278
+ -- read grant
279
+ OR s[2] = 'r');
280
+ """ );
281
+ final String username = database .getDatabaseConfig ().get ("username" ).asText ();
282
+ ps .setString (1 , username );
283
+ ps .setString (2 , username );
238
284
return ps ;
239
285
}, sourceOperations ::rowToJson )
240
286
.collect (toSet ())
0 commit comments