@@ -1046,10 +1046,9 @@ public void signUpMultipleViaBulkImport_Transaction(TransactionConnection connec
10461046 try {
10471047 Connection sqlConnection = (Connection ) connection .getConnection ();
10481048 EmailPasswordQueries .signUpMultipleForBulkImport_Transaction (this , sqlConnection , users );
1049- } catch (StorageQueryException | SQLException | StorageTransactionLogicException e ) {
1049+ } catch (StorageQueryException | StorageTransactionLogicException e ) {
10501050 Throwable actual = e .getCause ();
1051- if (actual instanceof BatchUpdateException ) {
1052- BatchUpdateException batchUpdateException = (BatchUpdateException ) actual ;
1051+ if (actual instanceof BatchUpdateException batchUpdateException ) {
10531052 Map <String , Exception > errorByPosition = new HashMap <>();
10541053 SQLException nextException = batchUpdateException .getNextException ();
10551054 while (nextException != null ) {
@@ -1271,6 +1270,15 @@ public void updateIsEmailVerified_Transaction(AppIdentifier appIdentifier, Trans
12711270 }
12721271 }
12731272
1273+ /**
1274+ * Update the isEmailVerified column for multiple users in the email verification table. This method is used in the
1275+ * Bulk Migration process.
1276+ * Important note: this method expects a Map of email to userId, but if there is an error in the batch processing,
1277+ * it will throw a BulkImportBatchInsertException with a map of userid to Exception, based on the position of the
1278+ * erroneous item in the batch.
1279+ * This means, that the underlying map implementation must be one that preserves iteration order (LinkedHashMap
1280+ * is a good choice) and this is the responsibility of the caller to ensure that the passed map is such.
1281+ */
12741282 @ Override
12751283 public void updateMultipleIsEmailVerified_Transaction (AppIdentifier appIdentifier , TransactionConnection con ,
12761284 Map <String , String > emailToUserId , boolean isEmailVerified )
@@ -1280,23 +1288,35 @@ public void updateMultipleIsEmailVerified_Transaction(AppIdentifier appIdentifie
12801288 EmailVerificationQueries .updateMultipleUsersIsEmailVerified_Transaction (this , sqlCon , appIdentifier ,
12811289 emailToUserId , isEmailVerified );
12821290 } catch (SQLException e ) {
1283- if (e instanceof PSQLException ) {
1284- PostgreSQLConfig config = Config .getConfig (this );
1285- ServerErrorMessage serverMessage = ((PSQLException ) e ).getServerErrorMessage ();
1291+ if (e instanceof BatchUpdateException batchUpdateException ) {
1292+ SQLException nextException = batchUpdateException .getNextException ();
1293+ Map <String , Exception > errorByPosition = new HashMap <>();
1294+ while (nextException != null ) {
12861295
1287- if (isForeignKeyConstraintError (serverMessage , config .getEmailVerificationTable (), "app_id" )) {
1288- throw new TenantOrAppNotFoundException (appIdentifier );
1289- }
1290- }
1296+ if (nextException instanceof PSQLException ) {
1297+ PostgreSQLConfig config = Config .getConfig (this );
1298+ ServerErrorMessage serverMessage = ((PSQLException ) nextException ).getServerErrorMessage ();
12911299
1292- boolean isPSQLPrimKeyError = e instanceof PSQLException && isPrimaryKeyError (
1293- ((PSQLException ) e ).getServerErrorMessage (),
1294- Config .getConfig (this ).getEmailVerificationTable ());
1300+ int position = getErroneousEntryPosition (batchUpdateException );
1301+ String userid = ((Map .Entry <String , String >) emailToUserId .entrySet ().toArray ()[position ]).getKey ();
1302+ if (isNullConstraintError (serverMessage , config .getEmailVerificationTable (), "email" )) {
1303+ errorByPosition .put (userid , new NullPointerException ("email is null" ));
1304+ } else if (isPrimaryKeyError (serverMessage , config .getEmailVerificationTable ())) {
1305+ errorByPosition .put (userid ,
1306+ new DuplicateEmailException ());
1307+ }
1308+ if (isForeignKeyConstraintError (serverMessage , config .getEmailVerificationTable (),
1309+ "app_id" )) {
1310+ throw new TenantOrAppNotFoundException (appIdentifier );
1311+ }
1312+ }
12951313
1296- if (!isEmailVerified || !isPSQLPrimKeyError ) {
1314+ nextException = nextException .getNextException ();
1315+ }
1316+ throw new StorageQueryException (
1317+ new BulkImportBatchInsertException ("emailverification errors" , errorByPosition ));
1318+ }
12971319 throw new StorageQueryException (e );
1298- }
1299- // we do not throw an error since the email is already verified
13001320 }
13011321 }
13021322
@@ -1499,9 +1519,7 @@ public void importThirdPartyUsers_Transaction(TransactionConnection con,
14991519 Connection sqlCon = (Connection ) con .getConnection ();
15001520 ThirdPartyQueries .importUser_Transaction (this , sqlCon , usersToImport );
15011521 } catch (SQLException e ) {
1502- Throwable actual = e .getCause ();
1503- if (actual instanceof BatchUpdateException ) {
1504- BatchUpdateException batchUpdateException = (BatchUpdateException ) actual ;
1522+ if (e instanceof BatchUpdateException batchUpdateException ) {
15051523 Map <String , Exception > errorByPosition = new HashMap <>();
15061524 SQLException nextException = batchUpdateException .getNextException ();
15071525 while (nextException != null ) {
@@ -1769,6 +1787,13 @@ private boolean isForeignKeyConstraintError(ServerErrorMessage serverMessage, St
17691787 && serverMessage .getConstraint ().equals (tableName + "_" + columnName + "_fkey" );
17701788 }
17711789
1790+ private boolean isNullConstraintError (ServerErrorMessage serverMessage , String tableName , String columnName ) {
1791+ String [] tableNameParts = tableName .split ("\\ ." );
1792+ tableName = tableNameParts [tableNameParts .length - 1 ];
1793+ return serverMessage .getSQLState ().equals ("23502" )
1794+ && serverMessage .getMessage ().contains ("null value in column \" " + columnName + "\" of relation \" " + tableName + "\" violates not-null constraint" );
1795+ }
1796+
17721797 private boolean isPrimaryKeyError (ServerErrorMessage serverMessage , String tableName ) {
17731798 String [] tableNameParts = tableName .split ("\\ ." );
17741799 tableName = tableNameParts [tableNameParts .length - 1 ];
@@ -2098,50 +2123,46 @@ public void importPasswordlessUsers_Transaction(TransactionConnection con,
20982123 Connection sqlCon = (Connection ) con .getConnection ();
20992124 PasswordlessQueries .importUsers_Transaction (sqlCon , this , users );
21002125 } catch (SQLException e ) {
2101- if (e instanceof BatchUpdateException ) {
2102- Throwable actual = e .getCause ();
2103- if (actual instanceof BatchUpdateException ) {
2104- BatchUpdateException batchUpdateException = (BatchUpdateException ) actual ;
2105- Map <String , Exception > errorByPosition = new HashMap <>();
2106- SQLException nextException = batchUpdateException .getNextException ();
2107- while (nextException != null ) {
2126+ if (e instanceof BatchUpdateException batchUpdateException ) {
2127+ Map <String , Exception > errorByPosition = new HashMap <>();
2128+ SQLException nextException = batchUpdateException .getNextException ();
2129+ while (nextException != null ) {
21082130
2109- if (nextException instanceof PSQLException ) {
2110- PostgreSQLConfig config = Config .getConfig (this );
2111- ServerErrorMessage serverMessage = ((PSQLException ) nextException ).getServerErrorMessage ();
2131+ if (nextException instanceof PSQLException ) {
2132+ PostgreSQLConfig config = Config .getConfig (this );
2133+ ServerErrorMessage serverMessage = ((PSQLException ) nextException ).getServerErrorMessage ();
21122134
2113- int position = getErroneousEntryPosition (batchUpdateException );
2135+ int position = getErroneousEntryPosition (batchUpdateException );
21142136
2115- if (isPrimaryKeyError (serverMessage , config .getPasswordlessUsersTable ())
2116- || isPrimaryKeyError (serverMessage , config .getUsersTable ())
2117- || isPrimaryKeyError (serverMessage , config .getPasswordlessUserToTenantTable ())
2118- || isPrimaryKeyError (serverMessage , config .getAppIdToUserIdTable ())) {
2119- errorByPosition .put (users .get (position ).userId , new DuplicateUserIdException ());
2120- }
2121- if (isUniqueConstraintError (serverMessage , config .getPasswordlessUserToTenantTable (),
2122- "email" )) {
2123- errorByPosition .put (users .get (position ).userId , new DuplicateEmailException ());
2137+ if (isPrimaryKeyError (serverMessage , config .getPasswordlessUsersTable ())
2138+ || isPrimaryKeyError (serverMessage , config .getUsersTable ())
2139+ || isPrimaryKeyError (serverMessage , config .getPasswordlessUserToTenantTable ())
2140+ || isPrimaryKeyError (serverMessage , config .getAppIdToUserIdTable ())) {
2141+ errorByPosition .put (users .get (position ).userId , new DuplicateUserIdException ());
2142+ }
2143+ if (isUniqueConstraintError (serverMessage , config .getPasswordlessUserToTenantTable (),
2144+ "email" )) {
2145+ errorByPosition .put (users .get (position ).userId , new DuplicateEmailException ());
21242146
2125- } else if (isUniqueConstraintError (serverMessage , config .getPasswordlessUserToTenantTable (),
2126- "phone_number" )) {
2127- errorByPosition .put (users .get (position ).userId , new DuplicatePhoneNumberException ());
2147+ } else if (isUniqueConstraintError (serverMessage , config .getPasswordlessUserToTenantTable (),
2148+ "phone_number" )) {
2149+ errorByPosition .put (users .get (position ).userId , new DuplicatePhoneNumberException ());
21282150
2129- } else if (isForeignKeyConstraintError (serverMessage , config .getAppIdToUserIdTable (),
2130- "app_id" )) {
2131- throw new TenantOrAppNotFoundException (users .get (position ).tenantIdentifier .toAppIdentifier ());
2151+ } else if (isForeignKeyConstraintError (serverMessage , config .getAppIdToUserIdTable (),
2152+ "app_id" )) {
2153+ throw new TenantOrAppNotFoundException (users .get (position ).tenantIdentifier .toAppIdentifier ());
21322154
2133- } else if (isForeignKeyConstraintError (serverMessage , config .getUsersTable (),
2134- "tenant_id" )) {
2135- throw new TenantOrAppNotFoundException (users .get (position ).tenantIdentifier .toAppIdentifier ());
2136- }
2155+ } else if (isForeignKeyConstraintError (serverMessage , config .getUsersTable (),
2156+ "tenant_id" )) {
2157+ throw new TenantOrAppNotFoundException (users .get (position ).tenantIdentifier .toAppIdentifier ());
21372158 }
2138- nextException = nextException .getNextException ();
21392159 }
2140- throw new StorageQueryException (
2141- new BulkImportBatchInsertException ("passwordless errors" , errorByPosition ));
2160+ nextException = nextException .getNextException ();
21422161 }
2143- throw new StorageQueryException (e );
2162+ throw new StorageQueryException (
2163+ new BulkImportBatchInsertException ("passwordless errors" , errorByPosition ));
21442164 }
2165+ throw new StorageQueryException (e );
21452166 }
21462167 }
21472168
@@ -3627,8 +3648,7 @@ public void addBulkImportUsers(AppIdentifier appIdentifier, List<BulkImportUser>
36273648 try {
36283649 BulkImportQueries .insertBulkImportUsers_Transaction (this , (Connection ) con .getConnection (), appIdentifier , users );
36293650 } catch (SQLException e ) {
3630- if (e instanceof BatchUpdateException ) {
3631- BatchUpdateException batchUpdateException = (BatchUpdateException ) e ;
3651+ if (e instanceof BatchUpdateException batchUpdateException ) {
36323652 SQLException nextException = batchUpdateException .getNextException ();
36333653 if (nextException instanceof PSQLException ){
36343654 ServerErrorMessage serverErrorMessage = ((PSQLException ) nextException ).getServerErrorMessage ();
@@ -3756,6 +3776,7 @@ public List<String> deleteBulkImportUsers(AppIdentifier appIdentifier, @Nonnull
37563776 try {
37573777 return BulkImportQueries .deleteBulkImportUsers (this , appIdentifier , bulkImportUserIds );
37583778 } catch (SQLException e ) {
3779+ Logging .error (this , "Error deleting bulk import users" , true , e );
37593780 throw new StorageQueryException (e );
37603781 }
37613782 }
0 commit comments