summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/database/DatabaseUtils.java70
-rw-r--r--core/java/android/database/sqlite/flags.aconfig8
-rw-r--r--core/tests/coretests/src/android/database/DatabaseUtilsTest.java6
3 files changed, 78 insertions, 6 deletions
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 2081ced3c484..7aa034966011 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -22,6 +22,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
+import android.database.sqlite.Flags;
import android.database.sqlite.SQLiteAbortException;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
@@ -1609,7 +1610,7 @@ public class DatabaseUtils {
* Comments either start with "--" and run to the end of the line or are C-style block
* comments. The function returns null if a prefix could not be found.
*/
- private static String getSqlStatementPrefixExtended(String sql) {
+ private static String getSqlStatementPrefixExtendedRegex(String sql) {
Matcher m = sPrefixPattern.matcher(sql);
if (m.lookingAt()) {
return m.group(PREFIX_GROUP_NUM).toUpperCase(Locale.ROOT);
@@ -1619,6 +1620,61 @@ public class DatabaseUtils {
}
/**
+ * Return the index of the first character past comments and whitespace. -1 is returned if
+ * a comment is malformed.
+ */
+ private static int getSqlStatementPrefixOffset(String s) {
+ final int limit = s.length() - 2;
+ if (limit < 0) return -1;
+ int i = 0;
+ while (i < limit) {
+ final char c = s.charAt(i);
+ if (c <= ' ') {
+ // This behavior conforms to String.trim(), which is used by the legacy Android
+ // SQL prefix logic. This test is not unicode-aware. Notice that it accepts the
+ // null character as whitespace even though the null character will terminate the
+ // SQL string in native code.
+ i++;
+ } else if (c == '-') {
+ if (s.charAt(i+1) != '-') return i;
+ i = s.indexOf('\n', i+2);
+ if (i < 0) return -1;
+ i++;
+ } else if (c == '/') {
+ if (s.charAt(i+1) != '*') return i;
+ i++;
+ do {
+ i = s.indexOf('*', i+1);
+ if (i < 0) return -1;
+ i++;
+ } while (s.charAt(i) != '/');
+ i++;
+ } else {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Scan past leading comments without using the Java regex routines.
+ */
+ private static String getSqlStatementPrefixExtendedNoRegex(String sql) {
+ int n = getSqlStatementPrefixOffset(sql);
+ if (n < 0) {
+ // Bad comment syntax.
+ return null;
+ }
+ final int end = sql.length();
+ if (n > end) {
+ // Bad scanning. This indicates a programming error.
+ return null;
+ }
+ final int eos = Math.min(n+3, end);
+ return sql.substring(n, eos);
+ }
+
+ /**
* Return the extended statement type for the SQL statement. This is not a public API and it
* can return values that are not publicly visible.
* @hide
@@ -1663,11 +1719,15 @@ public class DatabaseUtils {
* @hide
*/
public static int getSqlStatementTypeExtended(@NonNull String sql) {
- int type = categorizeStatement(getSqlStatementPrefixSimple(sql), sql);
- if (type == STATEMENT_COMMENT) {
- type = categorizeStatement(getSqlStatementPrefixExtended(sql), sql);
+ if (Flags.simpleSqlCommentScanner()) {
+ return categorizeStatement(getSqlStatementPrefixExtendedNoRegex(sql), sql);
+ } else {
+ int type = categorizeStatement(getSqlStatementPrefixSimple(sql), sql);
+ if (type == STATEMENT_COMMENT) {
+ type = categorizeStatement(getSqlStatementPrefixExtendedRegex(sql), sql);
+ }
+ return type;
}
- return type;
}
/**
diff --git a/core/java/android/database/sqlite/flags.aconfig b/core/java/android/database/sqlite/flags.aconfig
index 7ecffaf01549..1f06dfac255a 100644
--- a/core/java/android/database/sqlite/flags.aconfig
+++ b/core/java/android/database/sqlite/flags.aconfig
@@ -16,3 +16,11 @@ flag {
description: "Permit updates to TEMP tables in read-only transactions"
bug: "317993835"
}
+
+flag {
+ name: "simple_sql_comment_scanner"
+ namespace: "system_performance"
+ is_fixed_read_only: true
+ description: "Scan SQL comments by hand instead of with a regex"
+ bug: "329118560"
+}
diff --git a/core/tests/coretests/src/android/database/DatabaseUtilsTest.java b/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
index 2323527e7b4c..c9cb2cc416e8 100644
--- a/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseUtilsTest.java
@@ -78,7 +78,8 @@ public class DatabaseUtilsTest {
final int sel = STATEMENT_SELECT;
assertEquals(sel, getSqlStatementType("SELECT"));
assertEquals(sel, getSqlStatementType(" SELECT"));
- assertEquals(sel, getSqlStatementType(" \n SELECT"));
+ assertEquals(sel, getSqlStatementType(" \n\r\f\t SELECT"));
+ assertEquals(sel, getSqlStatementType(" \n\r\f\t SEL"));
final int upd = STATEMENT_UPDATE;
assertEquals(upd, getSqlStatementType("UPDATE"));
@@ -95,6 +96,9 @@ public class DatabaseUtilsTest {
assertEquals(othr, getSqlStatementType("SE LECT"));
assertEquals(othr, getSqlStatementType("-- cmt\n SE"));
assertEquals(othr, getSqlStatementType("WITH"));
+ assertEquals(othr, getSqlStatementType("-"));
+ assertEquals(othr, getSqlStatementType("--"));
+ assertEquals(othr, getSqlStatementType("*/* foo */ SEL"));
// Verify that leading line-comments are skipped.
assertEquals(sel, getSqlStatementType("-- cmt\n SELECT"));