1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.providers.contacts.database;
18 
19 import android.annotation.Nullable;
20 import android.database.Cursor;
21 import android.database.DatabaseUtils;
22 import android.util.Log;
23 
24 import com.android.providers.contacts.util.NeededForTesting;
25 
26 /**
27  * Static methods for database operations.
28  */
29 public class MoreDatabaseUtils {
30 
31     /**
32      * Builds a CREATE INDEX ddl statement for a given table and field.
33      *
34      * @param table The table name.
35      * @param field The field to index.
36      * @return The create index sql statement.
37      */
buildCreateIndexSql(String table, String field)38     public static String buildCreateIndexSql(String table, String field) {
39         return "CREATE INDEX " + buildIndexName(table, field) + " ON " + table
40                 + "(" + field + ")";
41     }
42 
43     /**
44      * Builds a DROP INDEX ddl statement for a given table and field.
45      *
46      * @param table The table name that was originally used to create the index.
47      * @param field The field that was originally used to create the index.
48      * @return The drop index sql statement.
49      */
50     @NeededForTesting
buildDropIndexSql(String table, String field)51     public static String buildDropIndexSql(String table, String field) {
52         return "DROP INDEX IF EXISTS " + buildIndexName(table, field);
53     }
54 
55     /**
56      * The index is created with a name using the following convention:
57      * <p>
58      * [table name]_[field name]_index
59      */
buildIndexName(String table, String field)60     public static String buildIndexName(String table, String field) {
61         return table + "_" + field + "_index";
62     }
63 
64     /**
65      * Build a bind arg where clause.
66      * <p>
67      * e.g. Calling this method with value of 4 results in:
68      * <p>
69      * "?,?,?,?"
70      *
71      * @param numArgs The number of arguments.
72      * @return A string that can be used for bind args in a sql where clause.
73      */
74     @NeededForTesting
buildBindArgString(int numArgs)75     public static String buildBindArgString(int numArgs) {
76         final StringBuilder sb = new StringBuilder();
77         String delimiter = "";
78         for (int i = 0; i < numArgs; i++) {
79             sb.append(delimiter).append("?");
80             delimiter = ",";
81         }
82         return sb.toString();
83     }
84 
85     /** Debug utility that dumps a cursor on logcat. */
dumpCursor(String logTag, String name, Cursor c)86     public static final void dumpCursor(String logTag, String name, Cursor c) {
87         Log.d(logTag, "Dumping cursor " + name + " containing " + c.getCount() + " rows");
88 
89         // Dump the column names.
90         final StringBuilder sb = new StringBuilder();
91         for (int i = 0; i < c.getColumnCount(); i++) {
92             if (sb.length() > 0) sb.append(" ");
93             sb.append(c.getColumnName(i));
94         }
95         Log.d(logTag, sb.toString());
96 
97         // Dump the values.
98         c.moveToPosition(-1);
99         while (c.moveToNext()) {
100             sb.setLength(0);
101             sb.append("row#");
102             sb.append(c.getPosition());
103 
104             for (int i = 0; i < c.getColumnCount(); i++) {
105                 sb.append(" ");
106 
107                 String s = c.getString(i);
108                 sb.append(s == null ? "{null}" : s.replaceAll("\\s", "{space}"));
109             }
110             Log.d(logTag, sb.toString());
111         }
112     }
113 
114     /**
115      * Same as {@link DatabaseUtils#sqlEscapeString(String)} but handles a null argument by
116      * returning the string "NULL".
117      *
118      * @return the SQL-escaped string or "NULL" if the argument is null.
119      */
120     @Nullable
sqlEscapeNullableString(@ullable String s)121     public static String sqlEscapeNullableString(@Nullable String s) {
122         return s == null
123                 ? "NULL"
124                 : DatabaseUtils.sqlEscapeString(s);
125     }
126 
127     /**
128      * Same as {@link DatabaseUtils#appendEscapedSQLString(StringBuilder, String)} but handles a
129      * null argument by appending the literal string "NULL".
130      */
131     @Nullable
appendEscapedSQLStringOrLiteralNull(StringBuilder sb, @Nullable String s)132     public static void appendEscapedSQLStringOrLiteralNull(StringBuilder sb, @Nullable String s) {
133         if (s == null) {
134             sb.append("NULL");
135         } else {
136             DatabaseUtils.appendEscapedSQLString(sb, s);
137         }
138     }
139 }
140