Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expo SDK 50 - SQLite causes issues on Android #28297

Open
pavattt opened this issue Apr 18, 2024 · 7 comments
Open

Expo SDK 50 - SQLite causes issues on Android #28297

pavattt opened this issue Apr 18, 2024 · 7 comments
Labels
Android needs review Issue is ready to be reviewed by a maintainer SQLite

Comments

@pavattt
Copy link

pavattt commented Apr 18, 2024

Minimal reproducible example

https://github.com/pavattt/expo-50-android-bug

What platform(s) does this occur on?

Android

Did you reproduce this issue in a development build?

Yes

Summary

On Android after upgrade from Expo sdk 49 to 50, Sqlite doesn't call success or error callbacks. Also it causes SecureStore.getItemAsync not to resolve or reject promise.

Environment

expo-env-info 1.2.0 environment info:
System:
OS: macOS 14.4.1
Shell: 5.9 - /bin/zsh
Binaries:
Node: 18.18.2 - ~/.nvm/versions/node/v18.18.2/bin/node
Yarn: 1.22.22 - ~/.nvm/versions/node/v18.18.2/bin/yarn
npm: 10.5.0 - ~/.nvm/versions/node/v18.18.2/bin/npm
Watchman: 2024.04.01.00 - /opt/homebrew/bin/watchman
Managers:
CocoaPods: 1.14.3 - /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 23.4, iOS 17.4, macOS 14.4, tvOS 17.4, visionOS 1.1, watchOS 10.4
IDEs:
Android Studio: 2023.1 AI-231.9392.1.2311.11330709
Xcode: 15.3/15E204a - /usr/bin/xcodebuild
npmPackages:
expo: ^50.0.17 => 50.0.17
react: 18.2.0 => 18.2.0
react-native: 0.73.6 => 0.73.6
npmGlobalPackages:
eas-cli: 7.6.2
Expo Workflow: managed

Expo Doctor Diagnostics

✔ Check Expo config for common issues
✔ Check package.json for common issues
✔ Check native tooling versions
✔ Check dependencies for packages that should not be installed directly
✔ Check for common project setup issues
✔ Check npm/ yarn versions
✔ Check for issues with metro config
✔ Check Expo config (app.json/ app.config.js) schema
✔ Check for legacy global CLI installed locally
✔ Check that native modules do not use incompatible support packages
✔ Check that native modules use compatible support package versions for installed Expo SDK
✔ Check that packages match versions required by installed Expo SDK

Didn't find any issues with the project!

@pavattt pavattt added the needs validation Issue needs to be validated label Apr 18, 2024
@expo-bot expo-bot added needs review Issue is ready to be reviewed by a maintainer and removed needs validation Issue needs to be validated labels Apr 18, 2024
@pavattt
Copy link
Author

pavattt commented Apr 24, 2024

I noticed using singleton pattern and reusing the existing database connection solves the issue.

Closing the database connection and reopening it causes the same issue.

@LabLamb
Copy link

LabLamb commented Apr 25, 2024

I have the same problem.

@gpurbia
Copy link

gpurbia commented Apr 29, 2024

having same issue for android, @pavattt are is this working at your end or found any solution ?

@LabLamb
Copy link

LabLamb commented Apr 29, 2024

I changed to using expo SQLite next but the function calls are different.

@pavattt
Copy link
Author

pavattt commented Apr 29, 2024

@gpurbia I'm just avoiding opening/closing the database more than once. I added something like this in my code:

let db = null;

export default async function getDb() {
    if (null === db) {
        db = SQLite.openDatabase('db_name.db');
    }
    return db;
}

And then anywhere I need db I just call

const db = await getDb();

@AlexPanich
Copy link

Executing a transactionAsync in parallel results in a hang. I use queue for patching this method

let db;
let transactionAsyncOriginal: (
	asyncCallback: SQLite.SQLTransactionAsyncCallback,
	readOnly?: boolean,
) => Promise<void>;

const queue = new Queue<() => Promise<void>>();
export function getDB() {
	if (!db) {
		db = SQLite.openDatabase('db_name.db');
	}
	if (Platform.OS !== 'android') {
		return db;
	}
	if (!transactionAsyncOriginal) {
		transactionAsyncOriginal = db.transactionAsync;
	}
	db.transactionAsync = (transaction, readOnly) =>
		new Promise((resolve) =>
			queue.add(async () => {
				await transactionAsyncOriginal(transaction, readOnly);
				resolve();
			}),
		);
	return db;
}

where simple queue

export default class Queue<T extends () => Promise<void>> {
	private queue: T[] = [];
	private lock = false;

	add(task: T) {
		this.queue.push(task);
		if (!this.lock) {
			this.lock = true;
			this.run();
		}
	}

	run = async () => {
		const nextTask = this.queue.shift();
		if (nextTask) {
			await nextTask();
		}

		if (this.queue.length) {
			this.run();
		} else {
			this.lock = false;
		}
	};
}

@gpurbia
Copy link

gpurbia commented May 7, 2024

@pavattt with singleton approach (initialise DB only one time), working as expected in both IOS and android.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Android needs review Issue is ready to be reviewed by a maintainer SQLite
Projects
None yet
Development

No branches or pull requests

6 participants