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

On Android, allow PRAGMA statements that assign when invoked via exec #99

Merged
merged 2 commits into from
Aug 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 37 additions & 4 deletions android/src/main/java/dog/craftz/sqlite_2/RNSqlite2Module.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,10 @@ public void run() {
String sql = sqlQuery.getString(0);
ReadableArray queryArgs = sqlQuery.getArray(1);
try {
if (isSelectOrPragmaQuery(sql)) {
if (isSelectQuery(sql)) {
results[i] = doSelectInBackgroundAndPossiblyThrow(sql, queryArgs, db);
} else if (isPragmaQuery(sql)) {
results[i] = doPragmaInBackgroundAndPossiblyThrow(sql, queryArgs, db);
} else { // update/insert/delete
if (readOnly) {
results[i] = new SQLitePLuginResult(EMPTY_ROWS, EMPTY_COLUMNS, 0, 0, new ReadOnlyException());
Expand Down Expand Up @@ -165,6 +167,35 @@ private SQLitePLuginResult doUpdateInBackgroundAndPossiblyThrow(String sql, Read
}
}

private SQLitePLuginResult doPragmaInBackgroundAndPossiblyThrow(String sql, ReadableArray queryArgs, SQLiteDatabase db) {
debug("\"all\" query: %s", sql);
Cursor cursor = null;
try {
String[] bindArgs = convertParamsToStringArray(queryArgs);
cursor = db.rawQuery(sql, bindArgs);
int numRows = cursor.getCount();
if (numRows == 0) {
return EMPTY_RESULT;
}
int numColumns = cursor.getColumnCount();
Object[][] rows = new Object[numRows][];
String[] columnNames = cursor.getColumnNames();
for (int i = 0; cursor.moveToNext(); i++) {
Object[] row = new Object[numColumns];
for (int j = 0; j < numColumns; j++) {
row[j] = getValueFromCursor(cursor, j, cursor.getType(j));
}
rows[i] = row;
}
debug("returning %d rows", numRows);
return new SQLitePLuginResult(rows, columnNames, 0, 0, null);
} finally {
if (cursor != null) {
cursor.close();
}
}
}

// do a select operation
private SQLitePLuginResult doSelectInBackgroundAndPossiblyThrow(String sql, ReadableArray queryArgs, SQLiteDatabase db) {
debug("\"all\" query: %s", sql);
Expand Down Expand Up @@ -286,9 +317,11 @@ private static WritableNativeArray convertPluginResultToArray(SQLitePLuginResult
}


private static boolean isSelectOrPragmaQuery(String str) {
return startsWithCaseInsensitive(str, "select") ||
(startsWithCaseInsensitive(str, "pragma") && !str.contains("="));
private static boolean isSelectQuery(String str) {
return startsWithCaseInsensitive(str, "select");
}
private static boolean isPragmaQuery(String str) {
return startsWithCaseInsensitive(str, "pragma");
}
private static boolean isInsert(String str) {
return startsWithCaseInsensitive(str, "insert");
Expand Down
100 changes: 95 additions & 5 deletions test/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,23 @@ import {

import SQLite from 'react-native-sqlite-2'

function databaseName(name) {
return name + '.' + Math.floor(Math.random() * 100000)
}

const database_name = 'test.db'
const database_version = '1.0'
const database_displayname = 'SQLite Test Database'
const database_size = 200000
let db

function exposedPromise() {
let resolveLoading
const p = new Promise((resolve) => (resolveLoading = resolve))
p.resolve = resolveLoading
return p
}

export default class ReactNativeSQLite2Test extends Component {
constructor(props) {
super(props)
Expand Down Expand Up @@ -67,7 +78,65 @@ export default class ReactNativeSQLite2Test extends Component {
this.addLog('Database DELETED')
}

populateDatabase(db) {
assigningPragma(db) {
new Promise((resolve) => {
let sql = "PRAGMA journal_mode = WAL"
db._db.exec([{sql: sql, args: []}], false, (_, result) => {
let journal_mode = result[0].rows[0].journal_mode
if (journal_mode == "wal") {
this.addLog("✅ " + sql)
} else {
this.addLog("❌ " + sql)
console.log(result, journal_mode)
}
resolve()
})
})
}

queryingPragma(db, isWal) {
new Promise((resolve) => {
let sql = "PRAGMA journal_mode"
db._db.exec([{sql: sql, args: []}], false, (_, result) => {
journal_mode = result[0].rows[0].journal_mode
Copy link
Owner

Choose a reason for hiding this comment

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

Add const or it causes ReferenceError

// Default journal_modes differ on Android & iOS
if (!isWal && journal_mode != "wal" ||
isWal && journal_mode == "wal") {
this.addLog("✅ " + sql)
} else {
this.addLog("❌ " + sql)
console.log(result, journal_mode)
}
resolve()
})
})
}

buildPragmaSchema(db) {
new Promise((resolve) => {
db._db.exec([{sql: "CREATE TABLE Version(version_id INTEGER PRIMARY KEY NOT NULL);", args: []}], false, (_, result) => {
resolve()
})
})
}

assigningParenthesisPragma(db) {
new Promise((resolve) => {
let sql = "PRAGMA main.wal_checkpoint(FULL)"
db._db.exec([{sql: sql, args: []}], false, (_, result) => {
row = result[0].rows[0]
Copy link
Owner

Choose a reason for hiding this comment

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

Add const or it causes ReferenceError

if (row.busy == 0 && row.checkpointed != -1 && row.log != -1) {
this.addLog("✅ " + sql)
} else {
this.addLog("❌ " + sql)
console.log(result, row)
}
resolve()
})
})
}

populateDatabase(db, p) {
this.addLog('Database integrity check')
const prepareDB = () => {
db.transaction(this.populateDB, this.errorCB, () => {
Expand All @@ -77,6 +146,7 @@ export default class ReactNativeSQLite2Test extends Component {
this.addLog('Processing completed.')
db.transaction(this.cleanupTables, this.errorCB, () => {
this.closeDatabase()
p.resolve()
})
})
})
Expand Down Expand Up @@ -243,7 +313,7 @@ export default class ReactNativeSQLite2Test extends Component {
tx.executeSql('DROP TABLE IF EXISTS Departments;')
}

loadAndQueryDB() {
async loadAndQueryDB() {
this.addLog('Opening database ...')
db = SQLite.openDatabase(
database_name,
Expand All @@ -253,7 +323,26 @@ export default class ReactNativeSQLite2Test extends Component {
this.openCB,
this.errorCB
)
this.populateDatabase(db)
const p = exposedPromise()
this.populateDatabase(db, p)
await p
}

async pragmaTests() {
this.addLog('Open separate DB and run PRAGMA tests')
db = SQLite.openDatabase(
databaseName(database_name),
database_version,
database_displayname,
database_size,
this.openCB,
this.errorCB
)
await this.queryingPragma(db, false)
await this.assigningPragma(db)
await this.queryingPragma(db, true)
await this.buildPragmaSchema(db)
await this.assigningParenthesisPragma(db)
}

closeDatabase = () => {
Expand All @@ -264,11 +353,12 @@ export default class ReactNativeSQLite2Test extends Component {
}
}

runDemo() {
async runDemo() {
this.setState({
progress: ['Starting SQLite Callback Demo']
})
this.loadAndQueryDB()
await this.loadAndQueryDB()
this.pragmaTests();
}

renderProgressEntry = entry => {
Expand Down