diff options
Diffstat (limited to 'core/java/android/database/DatabaseUtils.java')
| -rw-r--r-- | core/java/android/database/DatabaseUtils.java | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java index 47567c34baf1..d60e61ac419e 100644 --- a/core/java/android/database/DatabaseUtils.java +++ b/core/java/android/database/DatabaseUtils.java @@ -17,6 +17,7 @@ package android.database; import android.annotation.UnsupportedAppUsage; +import android.annotation.Nullable; import android.content.ContentValues; import android.content.Context; import android.content.OperationApplicationException; @@ -35,6 +36,8 @@ import android.os.ParcelFileDescriptor; import android.text.TextUtils; import android.util.Log; +import com.android.internal.util.ArrayUtils; + import java.io.FileNotFoundException; import java.io.PrintStream; import java.text.Collator; @@ -217,6 +220,92 @@ public class DatabaseUtils { } /** + * Bind the given selection with the given selection arguments. + * <p> + * Internally assumes that '?' is only ever used for arguments, and doesn't + * appear as a literal or escaped value. + * <p> + * This method is typically useful for trusted code that needs to cook up a + * fully-bound selection. + * + * @hide + */ + public static @Nullable String bindSelection(@Nullable String selection, + @Nullable Object... selectionArgs) { + if (selection == null) return null; + // If no arguments provided, so we can't bind anything + if (ArrayUtils.isEmpty(selectionArgs)) return selection; + // If no bindings requested, so we can shortcut + if (selection.indexOf('?') == -1) return selection; + + // Track the chars immediately before and after each bind request, to + // decide if it needs additional whitespace added + char before = ' '; + char after = ' '; + + int argIndex = 0; + final int len = selection.length(); + final StringBuilder res = new StringBuilder(len); + for (int i = 0; i < len; ) { + char c = selection.charAt(i++); + if (c == '?') { + // Assume this bind request is guarded until we find a specific + // trailing character below + after = ' '; + + // Sniff forward to see if the selection is requesting a + // specific argument index + int start = i; + for (; i < len; i++) { + c = selection.charAt(i); + if (c < '0' || c > '9') { + after = c; + break; + } + } + if (start != i) { + argIndex = Integer.parseInt(selection.substring(start, i)) - 1; + } + + // Manually bind the argument into the selection, adding + // whitespace when needed for clarity + final Object arg = selectionArgs[argIndex++]; + if (before != ' ' && before != '=') res.append(' '); + switch (DatabaseUtils.getTypeOfObject(arg)) { + case Cursor.FIELD_TYPE_NULL: + res.append("NULL"); + break; + case Cursor.FIELD_TYPE_INTEGER: + res.append(((Number) arg).longValue()); + break; + case Cursor.FIELD_TYPE_FLOAT: + res.append(((Number) arg).doubleValue()); + break; + case Cursor.FIELD_TYPE_BLOB: + throw new IllegalArgumentException("Blobs not supported"); + case Cursor.FIELD_TYPE_STRING: + default: + if (arg instanceof Boolean) { + // Provide compatibility with legacy applications which may pass + // Boolean values in bind args. + res.append(((Boolean) arg).booleanValue() ? 1 : 0); + } else { + res.append('\''); + res.append(arg.toString()); + res.append('\''); + } + break; + } + if (after != ' ') res.append(' '); + } else { + res.append(c); + before = c; + } + } + return res.toString(); + } + + /** * Returns data type of the given object's value. *<p> * Returned values are |
