Skip to content
27 changes: 27 additions & 0 deletions src/main/java/io/supertokens/storage/postgresql/LockFailure.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2020, VRAI Labs and/or its affiliates. All rights reserved.
*
* This software is licensed under the Apache License, Version 2.0 (the
* "License") as published by the Apache Software Foundation.
*
* You may not use this file except in compliance with the License. You may
* obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

package io.supertokens.storage.postgresql;

public class LockFailure extends Exception {
public LockFailure() {
super("Failed to acquire advisory lock");
}

public LockFailure(String message) {
super(message);
}
}
139 changes: 99 additions & 40 deletions src/main/java/io/supertokens/storage/postgresql/Start.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,13 @@ public String getBulkImportUsersTable() {
return addSchemaAndPrefixToTableName("bulk_import_users");
}

public String getRecipeUserTenantsTable() {
return addSchemaAndPrefixToTableName("recipe_user_tenants");
}

public String getPrimaryUserTenantsTable() {
return addSchemaAndPrefixToTableName("primary_user_tenants");
}

private String addSchemaAndPrefixToTableName(String tableName) {
return addSchemaToTableName(postgresql_table_names_prefix + tableName);
Expand Down
1,154 changes: 1,154 additions & 0 deletions src/main/java/io/supertokens/storage/postgresql/queries/AccountInfoQueries.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@

package io.supertokens.storage.postgresql.queries;

import static java.lang.System.currentTimeMillis;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import io.supertokens.pluginInterface.ACCOUNT_INFO_TYPE;
import static io.supertokens.pluginInterface.RECIPE_ID.EMAIL_PASSWORD;
import io.supertokens.pluginInterface.RowMapper;
import io.supertokens.pluginInterface.authRecipe.AuthRecipeUserInfo;
import io.supertokens.pluginInterface.authRecipe.LoginMethod;
Expand All @@ -27,20 +42,13 @@
import io.supertokens.pluginInterface.multitenancy.AppIdentifier;
import io.supertokens.pluginInterface.multitenancy.TenantIdentifier;
import io.supertokens.storage.postgresql.PreparedStatementValueSetter;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.execute;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.executeBatch;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.update;
import io.supertokens.storage.postgresql.Start;
import io.supertokens.storage.postgresql.config.Config;
import io.supertokens.storage.postgresql.utils.Utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

import static io.supertokens.pluginInterface.RECIPE_ID.EMAIL_PASSWORD;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.*;
import static io.supertokens.storage.postgresql.config.Config.getConfig;
import static java.lang.System.currentTimeMillis;
import io.supertokens.storage.postgresql.utils.Utils;

public class EmailPasswordQueries {
static String getQueryToCreateUsersTable(Start start) {
Expand Down Expand Up @@ -309,6 +317,11 @@ public static AuthRecipeUserInfo signUp(Start start, TenantIdentifier tenantIden
});
}

{ // recipe_user_tenants
AccountInfoQueries.addRecipeUserAccountInfo_Transaction(start, sqlCon, tenantIdentifier, userId,
EMAIL_PASSWORD.toString(), ACCOUNT_INFO_TYPE.EMAIL, "", "", email);
}

{ // emailpassword_users
String QUERY = "INSERT INTO " + getConfig(start).getEmailPasswordUsersTable()
+ "(app_id, user_id, email, password_hash, time_joined)" + " VALUES(?, ?, ?, ?, ?)";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,23 @@ public static void createTablesIfNotExists(Start start, Connection con) throws S
update(con, SAMLQueries.getQueryToCreateSAMLClaimsExpiresAtIndex(start), NO_OP_SETTER);
}

if (!doesTableExists(start, con, Config.getConfig(start).getRecipeUserTenantsTable())) {
getInstance(start).addState(CREATING_NEW_TABLE, null);
update(con, AccountInfoQueries.getQueryToCreateRecipeUserTenantsTable(start), NO_OP_SETTER);

// indexes
update(con, AccountInfoQueries.getQueryToCreateTenantIndexForRecipeUserTenantsTable(start), NO_OP_SETTER);
update(con, AccountInfoQueries.getQueryToCreateAccountInfoIndexForRecipeUserTenantsTable(start), NO_OP_SETTER);
}

if (!doesTableExists(start, con, Config.getConfig(start).getPrimaryUserTenantsTable())) {
getInstance(start).addState(CREATING_NEW_TABLE, null);
update(con, AccountInfoQueries.getQueryToCreatePrimaryUserTenantsTable(start), NO_OP_SETTER);

// indexes
update(con, AccountInfoQueries.getQueryToCreatePrimaryUserIndexForPrimaryUserTenantsTable(start), NO_OP_SETTER);
}

} catch (Exception e) {
if (e.getMessage().contains("schema") && e.getMessage().contains("does not exist")
&& numberOfRetries < 1) {
Expand Down Expand Up @@ -779,7 +796,9 @@ public static void deleteAllTables(Start start) throws SQLException, StorageQuer
+ getConfig(start).getKeyValueTable() + ","
+ getConfig(start).getAppIdToUserIdTable() + ","
+ getConfig(start).getUserIdMappingTable() + ","
+ getConfig(start).getRecipeUserTenantsTable() + ","
+ getConfig(start).getUsersTable() + ","
+ getConfig(start).getPrimaryUserTenantsTable() + ","
+ getConfig(start).getAccessTokenSigningKeysTable() + ","
+ getConfig(start).getTenantFirstFactorsTable() + ","
+ getConfig(start).getTenantRequiredSecondaryFactorsTable() + ","
Expand Down Expand Up @@ -875,8 +894,12 @@ public static KeyValueInfo getKeyValue(Start start, TenantIdentifier tenantIdent
public static KeyValueInfo getKeyValue_Transaction(Start start, Connection con, TenantIdentifier tenantIdentifier,
String key)
throws SQLException, StorageQueryException {

io.supertokens.storage.postgresql.queries.Utils.takeAdvisoryLock(
con, tenantIdentifier.getAppId() + "~" + tenantIdentifier.getTenantId() + "~" + key);

String QUERY = "SELECT value, created_at_time FROM " + getConfig(start).getKeyValueTable()
+ " WHERE app_id = ? AND tenant_id = ? AND name = ? FOR UPDATE";
+ " WHERE app_id = ? AND tenant_id = ? AND name = ?";

return execute(con, QUERY, pst -> {
pst.setString(1, tenantIdentifier.getAppId());
Expand Down Expand Up @@ -1929,7 +1952,6 @@ private static List<AuthRecipeUserInfo> getPrimaryUserInfoForUserIds_Transaction
// for app_id
pst.setString(index, appIdentifier.getAppId());
pst.setString(index+1, appIdentifier.getAppId());
// System.out.println(pst);
}, result -> {
List<AllAuthRecipeUsersResultHolder> parsedResult = new ArrayList<>();
while (result.next()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ public static void overwriteTenantConfig(Start start, TenantConfig tenantConfig)
Connection sqlCon = (Connection) con.getConnection();
{
try {
{
io.supertokens.storage.postgresql.queries.Utils.takeAdvisoryLock(
sqlCon, tenantConfig.tenantIdentifier.getConnectionUriDomain() + "~" + tenantConfig.tenantIdentifier.getAppId() + "~" + tenantConfig.tenantIdentifier.getTenantId());
}
Comment on lines +246 to +249
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this? What do we want to achieve with this here?

{
String QUERY = "DELETE FROM " + getConfig(start).getTenantConfigsTable()
+ " WHERE connection_uri_domain = ? AND app_id = ? AND tenant_id = ?;";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@

package io.supertokens.storage.postgresql.queries;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import io.supertokens.pluginInterface.ACCOUNT_INFO_TYPE;
import static io.supertokens.pluginInterface.RECIPE_ID.PASSWORDLESS;
import io.supertokens.pluginInterface.RowMapper;
import io.supertokens.pluginInterface.authRecipe.AuthRecipeUserInfo;
import io.supertokens.pluginInterface.authRecipe.LoginMethod;
Expand All @@ -30,21 +47,13 @@
import io.supertokens.pluginInterface.sqlStorage.SQLStorage.TransactionIsolationLevel;
import io.supertokens.storage.postgresql.ConnectionPool;
import io.supertokens.storage.postgresql.PreparedStatementValueSetter;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.execute;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.executeBatch;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.update;
import io.supertokens.storage.postgresql.Start;
import io.supertokens.storage.postgresql.config.Config;
import io.supertokens.storage.postgresql.utils.Utils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

import static io.supertokens.pluginInterface.RECIPE_ID.PASSWORDLESS;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.*;
import static io.supertokens.storage.postgresql.config.Config.getConfig;
import io.supertokens.storage.postgresql.utils.Utils;

public class PasswordlessQueries {
public static String getQueryToCreateUsersTable(Start start) {
Expand Down Expand Up @@ -444,6 +453,24 @@ public static AuthRecipeUserInfo createUser(Start start, TenantIdentifier tenant
});
}

{ // recipe_user_tenants
ACCOUNT_INFO_TYPE accountInfoType;
String accountInfoValue;

if (email != null) {
accountInfoType = ACCOUNT_INFO_TYPE.EMAIL;
accountInfoValue = email;
} else if (phoneNumber != null) {
accountInfoType = ACCOUNT_INFO_TYPE.PHONE_NUMBER;
accountInfoValue = phoneNumber;
} else {
throw new IllegalArgumentException("Either email or phoneNumber must be provided");
}

AccountInfoQueries.addRecipeUserAccountInfo_Transaction(start, sqlCon, tenantIdentifier, id,
PASSWORDLESS.toString(), accountInfoType, "", "", accountInfoValue);
}

{ // passwordless_users
String QUERY = "INSERT INTO " + getConfig(start).getPasswordlessUsersTable()
+ "(app_id, user_id, email, phone_number, time_joined)" + " VALUES(?, ?, ?, ?, ?)";
Expand All @@ -468,6 +495,7 @@ public static AuthRecipeUserInfo createUser(Start start, TenantIdentifier tenant
pst.setString(5, phoneNumber);
});
}

UserInfoPartial userInfo = new UserInfoPartial(id, email, phoneNumber, timeJoined);
fillUserInfoWithTenantIds_transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), userInfo);
fillUserInfoWithVerified_transaction(start, sqlCon, tenantIdentifier.toAppIdentifier(), userInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@

package io.supertokens.storage.postgresql.queries;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import io.supertokens.pluginInterface.ACCOUNT_INFO_TYPE;
import static io.supertokens.pluginInterface.RECIPE_ID.THIRD_PARTY;
import io.supertokens.pluginInterface.RowMapper;
import io.supertokens.pluginInterface.authRecipe.AuthRecipeUserInfo;
import io.supertokens.pluginInterface.authRecipe.LoginMethod;
Expand All @@ -27,19 +41,13 @@
import io.supertokens.pluginInterface.thirdparty.ThirdPartyImportUser;
import io.supertokens.storage.postgresql.ConnectionPool;
import io.supertokens.storage.postgresql.PreparedStatementValueSetter;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.execute;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.executeBatch;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.update;
import io.supertokens.storage.postgresql.Start;
import io.supertokens.storage.postgresql.config.Config;
import io.supertokens.storage.postgresql.utils.Utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

import static io.supertokens.pluginInterface.RECIPE_ID.THIRD_PARTY;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.*;
import static io.supertokens.storage.postgresql.config.Config.getConfig;
import io.supertokens.storage.postgresql.utils.Utils;

public class ThirdPartyQueries {

Expand Down Expand Up @@ -136,6 +144,17 @@ public static AuthRecipeUserInfo signUp(Start start, TenantIdentifier tenantIden
});
}

{ // recipe_user_tenants
// Insert row for email
AccountInfoQueries.addRecipeUserAccountInfo_Transaction(start, sqlCon, tenantIdentifier, id,
THIRD_PARTY.toString(), ACCOUNT_INFO_TYPE.EMAIL, thirdParty.id, thirdParty.userId, email);

// Insert row for third party id
AccountInfoQueries.addRecipeUserAccountInfo_Transaction(start, sqlCon, tenantIdentifier, id,
THIRD_PARTY.toString(), ACCOUNT_INFO_TYPE.THIRD_PARTY, "", "",
thirdParty.id + "::" + thirdParty.userId);
}

{ // thirdparty_users
String QUERY = "INSERT INTO " + getConfig(start).getThirdPartyUsersTable()
+ "(app_id, third_party_id, third_party_user_id, user_id, email, time_joined)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,27 @@

package io.supertokens.storage.postgresql.queries;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import io.supertokens.pluginInterface.exceptions.StorageQueryException;
import io.supertokens.pluginInterface.exceptions.StorageTransactionLogicException;
import io.supertokens.pluginInterface.multitenancy.AppIdentifier;
import io.supertokens.storage.postgresql.PreparedStatementValueSetter;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.execute;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.executeBatch;
import static io.supertokens.storage.postgresql.QueryExecutorTemplate.update;
import io.supertokens.storage.postgresql.Start;
import io.supertokens.storage.postgresql.config.Config;
import io.supertokens.storage.postgresql.utils.Utils;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static io.supertokens.storage.postgresql.QueryExecutorTemplate.*;
import static io.supertokens.storage.postgresql.config.Config.getConfig;
import io.supertokens.storage.postgresql.utils.Utils;

public class UserMetadataQueries {

Expand Down Expand Up @@ -121,6 +123,7 @@ public static void setMultipleUsersMetadatas_Transaction(Start start, Connection
public static JsonObject getUserMetadata_Transaction(Start start, Connection con, AppIdentifier appIdentifier,
String userId)
throws SQLException, StorageQueryException {
io.supertokens.storage.postgresql.queries.Utils.takeAdvisoryLock(con, appIdentifier.getAppId() + "~" + userId);
String QUERY = "SELECT user_metadata FROM " + getConfig(start).getUserMetadataTable()
+ " WHERE app_id = ? AND user_id = ? FOR UPDATE";
return execute(con, QUERY, pst -> {
Expand Down
Loading
Loading