452 lines
18 KiB
Java
452 lines
18 KiB
Java
package androidx.room.util;
|
|
|
|
import android.database.Cursor;
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.annotation.RestrictTo;
|
|
import androidx.room.ColumnInfo;
|
|
import androidx.sqlite.db.SupportSQLiteDatabase;
|
|
import c.d.b.a.a;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.TreeMap;
|
|
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
|
|
public class TableInfo {
|
|
public static final int CREATED_FROM_DATABASE = 2;
|
|
public static final int CREATED_FROM_ENTITY = 1;
|
|
public static final int CREATED_FROM_UNKNOWN = 0;
|
|
public final Map<String, Column> columns;
|
|
public final Set<ForeignKey> foreignKeys;
|
|
@Nullable
|
|
public final Set<Index> indices;
|
|
public final String name;
|
|
|
|
public static class Column {
|
|
@ColumnInfo.SQLiteTypeAffinity
|
|
public final int affinity;
|
|
public final String defaultValue;
|
|
private final int mCreatedFrom;
|
|
public final String name;
|
|
public final boolean notNull;
|
|
public final int primaryKeyPosition;
|
|
public final String type;
|
|
|
|
@Deprecated
|
|
public Column(String str, String str2, boolean z2, int i) {
|
|
this(str, str2, z2, i, null, 0);
|
|
}
|
|
|
|
public Column(String str, String str2, boolean z2, int i, String str3, int i2) {
|
|
this.name = str;
|
|
this.type = str2;
|
|
this.notNull = z2;
|
|
this.primaryKeyPosition = i;
|
|
this.affinity = findAffinity(str2);
|
|
this.defaultValue = str3;
|
|
this.mCreatedFrom = i2;
|
|
}
|
|
|
|
@ColumnInfo.SQLiteTypeAffinity
|
|
private static int findAffinity(@Nullable String str) {
|
|
if (str == null) {
|
|
return 5;
|
|
}
|
|
String upperCase = str.toUpperCase(Locale.US);
|
|
if (upperCase.contains("INT")) {
|
|
return 3;
|
|
}
|
|
if (upperCase.contains("CHAR") || upperCase.contains("CLOB") || upperCase.contains("TEXT")) {
|
|
return 2;
|
|
}
|
|
if (upperCase.contains("BLOB")) {
|
|
return 5;
|
|
}
|
|
return (upperCase.contains("REAL") || upperCase.contains("FLOA") || upperCase.contains("DOUB")) ? 4 : 1;
|
|
}
|
|
|
|
public boolean equals(Object obj) {
|
|
String str;
|
|
String str2;
|
|
String str3;
|
|
if (this == obj) {
|
|
return true;
|
|
}
|
|
if (obj == null || getClass() != obj.getClass()) {
|
|
return false;
|
|
}
|
|
Column column = (Column) obj;
|
|
if (this.primaryKeyPosition != column.primaryKeyPosition || !this.name.equals(column.name) || this.notNull != column.notNull) {
|
|
return false;
|
|
}
|
|
if (this.mCreatedFrom == 1 && column.mCreatedFrom == 2 && (str3 = this.defaultValue) != null && !str3.equals(column.defaultValue)) {
|
|
return false;
|
|
}
|
|
if (this.mCreatedFrom == 2 && column.mCreatedFrom == 1 && (str2 = column.defaultValue) != null && !str2.equals(this.defaultValue)) {
|
|
return false;
|
|
}
|
|
int i = this.mCreatedFrom;
|
|
return (i == 0 || i != column.mCreatedFrom || ((str = this.defaultValue) == null ? column.defaultValue == null : str.equals(column.defaultValue))) && this.affinity == column.affinity;
|
|
}
|
|
|
|
public int hashCode() {
|
|
return (((((this.name.hashCode() * 31) + this.affinity) * 31) + (this.notNull ? 1231 : 1237)) * 31) + this.primaryKeyPosition;
|
|
}
|
|
|
|
public boolean isPrimaryKey() {
|
|
return this.primaryKeyPosition > 0;
|
|
}
|
|
|
|
public String toString() {
|
|
StringBuilder L = a.L("Column{name='");
|
|
L.append(this.name);
|
|
L.append('\'');
|
|
L.append(", type='");
|
|
L.append(this.type);
|
|
L.append('\'');
|
|
L.append(", affinity='");
|
|
L.append(this.affinity);
|
|
L.append('\'');
|
|
L.append(", notNull=");
|
|
L.append(this.notNull);
|
|
L.append(", primaryKeyPosition=");
|
|
L.append(this.primaryKeyPosition);
|
|
L.append(", defaultValue='");
|
|
L.append(this.defaultValue);
|
|
L.append('\'');
|
|
L.append('}');
|
|
return L.toString();
|
|
}
|
|
}
|
|
|
|
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
|
|
public static class ForeignKey {
|
|
@NonNull
|
|
public final List<String> columnNames;
|
|
@NonNull
|
|
public final String onDelete;
|
|
@NonNull
|
|
public final String onUpdate;
|
|
@NonNull
|
|
public final List<String> referenceColumnNames;
|
|
@NonNull
|
|
public final String referenceTable;
|
|
|
|
public ForeignKey(@NonNull String str, @NonNull String str2, @NonNull String str3, @NonNull List<String> list, @NonNull List<String> list2) {
|
|
this.referenceTable = str;
|
|
this.onDelete = str2;
|
|
this.onUpdate = str3;
|
|
this.columnNames = Collections.unmodifiableList(list);
|
|
this.referenceColumnNames = Collections.unmodifiableList(list2);
|
|
}
|
|
|
|
public boolean equals(Object obj) {
|
|
if (this == obj) {
|
|
return true;
|
|
}
|
|
if (obj == null || getClass() != obj.getClass()) {
|
|
return false;
|
|
}
|
|
ForeignKey foreignKey = (ForeignKey) obj;
|
|
if (this.referenceTable.equals(foreignKey.referenceTable) && this.onDelete.equals(foreignKey.onDelete) && this.onUpdate.equals(foreignKey.onUpdate) && this.columnNames.equals(foreignKey.columnNames)) {
|
|
return this.referenceColumnNames.equals(foreignKey.referenceColumnNames);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public int hashCode() {
|
|
int m = a.m(this.onUpdate, a.m(this.onDelete, this.referenceTable.hashCode() * 31, 31), 31);
|
|
return this.referenceColumnNames.hashCode() + ((this.columnNames.hashCode() + m) * 31);
|
|
}
|
|
|
|
public String toString() {
|
|
StringBuilder L = a.L("ForeignKey{referenceTable='");
|
|
L.append(this.referenceTable);
|
|
L.append('\'');
|
|
L.append(", onDelete='");
|
|
L.append(this.onDelete);
|
|
L.append('\'');
|
|
L.append(", onUpdate='");
|
|
L.append(this.onUpdate);
|
|
L.append('\'');
|
|
L.append(", columnNames=");
|
|
L.append(this.columnNames);
|
|
L.append(", referenceColumnNames=");
|
|
L.append(this.referenceColumnNames);
|
|
L.append('}');
|
|
return L.toString();
|
|
}
|
|
}
|
|
|
|
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
|
|
public static class ForeignKeyWithSequence implements Comparable<ForeignKeyWithSequence> {
|
|
public final String mFrom;
|
|
public final int mId;
|
|
public final int mSequence;
|
|
public final String mTo;
|
|
|
|
public ForeignKeyWithSequence(int i, int i2, String str, String str2) {
|
|
this.mId = i;
|
|
this.mSequence = i2;
|
|
this.mFrom = str;
|
|
this.mTo = str2;
|
|
}
|
|
|
|
public int compareTo(@NonNull ForeignKeyWithSequence foreignKeyWithSequence) {
|
|
int i = this.mId - foreignKeyWithSequence.mId;
|
|
return i == 0 ? this.mSequence - foreignKeyWithSequence.mSequence : i;
|
|
}
|
|
}
|
|
|
|
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
|
|
public static class Index {
|
|
public static final String DEFAULT_PREFIX = "index_";
|
|
public final List<String> columns;
|
|
public final String name;
|
|
public final boolean unique;
|
|
|
|
public Index(String str, boolean z2, List<String> list) {
|
|
this.name = str;
|
|
this.unique = z2;
|
|
this.columns = list;
|
|
}
|
|
|
|
public boolean equals(Object obj) {
|
|
if (this == obj) {
|
|
return true;
|
|
}
|
|
if (obj == null || getClass() != obj.getClass()) {
|
|
return false;
|
|
}
|
|
Index index = (Index) obj;
|
|
if (this.unique == index.unique && this.columns.equals(index.columns)) {
|
|
return this.name.startsWith("index_") ? index.name.startsWith("index_") : this.name.equals(index.name);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public int hashCode() {
|
|
return this.columns.hashCode() + ((((this.name.startsWith("index_") ? -1184239155 : this.name.hashCode()) * 31) + (this.unique ? 1 : 0)) * 31);
|
|
}
|
|
|
|
public String toString() {
|
|
StringBuilder L = a.L("Index{name='");
|
|
L.append(this.name);
|
|
L.append('\'');
|
|
L.append(", unique=");
|
|
L.append(this.unique);
|
|
L.append(", columns=");
|
|
L.append(this.columns);
|
|
L.append('}');
|
|
return L.toString();
|
|
}
|
|
}
|
|
|
|
public TableInfo(String str, Map<String, Column> map, Set<ForeignKey> set) {
|
|
this(str, map, set, Collections.emptySet());
|
|
}
|
|
|
|
public TableInfo(String str, Map<String, Column> map, Set<ForeignKey> set, Set<Index> set2) {
|
|
this.name = str;
|
|
this.columns = Collections.unmodifiableMap(map);
|
|
this.foreignKeys = Collections.unmodifiableSet(set);
|
|
this.indices = set2 == null ? null : Collections.unmodifiableSet(set2);
|
|
}
|
|
|
|
public static TableInfo read(SupportSQLiteDatabase supportSQLiteDatabase, String str) {
|
|
return new TableInfo(str, readColumns(supportSQLiteDatabase, str), readForeignKeys(supportSQLiteDatabase, str), readIndices(supportSQLiteDatabase, str));
|
|
}
|
|
|
|
private static Map<String, Column> readColumns(SupportSQLiteDatabase supportSQLiteDatabase, String str) {
|
|
Cursor query = supportSQLiteDatabase.query("PRAGMA table_info(`" + str + "`)");
|
|
HashMap hashMap = new HashMap();
|
|
try {
|
|
if (query.getColumnCount() > 0) {
|
|
int columnIndex = query.getColumnIndex("name");
|
|
int columnIndex2 = query.getColumnIndex("type");
|
|
int columnIndex3 = query.getColumnIndex("notnull");
|
|
int columnIndex4 = query.getColumnIndex("pk");
|
|
int columnIndex5 = query.getColumnIndex("dflt_value");
|
|
while (query.moveToNext()) {
|
|
String string = query.getString(columnIndex);
|
|
hashMap.put(string, new Column(string, query.getString(columnIndex2), query.getInt(columnIndex3) != 0, query.getInt(columnIndex4), query.getString(columnIndex5), 2));
|
|
}
|
|
}
|
|
return hashMap;
|
|
} finally {
|
|
query.close();
|
|
}
|
|
}
|
|
|
|
private static List<ForeignKeyWithSequence> readForeignKeyFieldMappings(Cursor cursor) {
|
|
int columnIndex = cursor.getColumnIndex("id");
|
|
int columnIndex2 = cursor.getColumnIndex("seq");
|
|
int columnIndex3 = cursor.getColumnIndex("from");
|
|
int columnIndex4 = cursor.getColumnIndex("to");
|
|
int count = cursor.getCount();
|
|
ArrayList arrayList = new ArrayList();
|
|
for (int i = 0; i < count; i++) {
|
|
cursor.moveToPosition(i);
|
|
arrayList.add(new ForeignKeyWithSequence(cursor.getInt(columnIndex), cursor.getInt(columnIndex2), cursor.getString(columnIndex3), cursor.getString(columnIndex4)));
|
|
}
|
|
Collections.sort(arrayList);
|
|
return arrayList;
|
|
}
|
|
|
|
private static Set<ForeignKey> readForeignKeys(SupportSQLiteDatabase supportSQLiteDatabase, String str) {
|
|
HashSet hashSet = new HashSet();
|
|
Cursor query = supportSQLiteDatabase.query("PRAGMA foreign_key_list(`" + str + "`)");
|
|
try {
|
|
int columnIndex = query.getColumnIndex("id");
|
|
int columnIndex2 = query.getColumnIndex("seq");
|
|
int columnIndex3 = query.getColumnIndex("table");
|
|
int columnIndex4 = query.getColumnIndex("on_delete");
|
|
int columnIndex5 = query.getColumnIndex("on_update");
|
|
List<ForeignKeyWithSequence> readForeignKeyFieldMappings = readForeignKeyFieldMappings(query);
|
|
int count = query.getCount();
|
|
for (int i = 0; i < count; i++) {
|
|
query.moveToPosition(i);
|
|
if (query.getInt(columnIndex2) == 0) {
|
|
int i2 = query.getInt(columnIndex);
|
|
ArrayList arrayList = new ArrayList();
|
|
ArrayList arrayList2 = new ArrayList();
|
|
for (ForeignKeyWithSequence foreignKeyWithSequence : readForeignKeyFieldMappings) {
|
|
if (foreignKeyWithSequence.mId == i2) {
|
|
arrayList.add(foreignKeyWithSequence.mFrom);
|
|
arrayList2.add(foreignKeyWithSequence.mTo);
|
|
}
|
|
}
|
|
hashSet.add(new ForeignKey(query.getString(columnIndex3), query.getString(columnIndex4), query.getString(columnIndex5), arrayList, arrayList2));
|
|
}
|
|
}
|
|
return hashSet;
|
|
} finally {
|
|
query.close();
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
private static Index readIndex(SupportSQLiteDatabase supportSQLiteDatabase, String str, boolean z2) {
|
|
Cursor query = supportSQLiteDatabase.query("PRAGMA index_xinfo(`" + str + "`)");
|
|
try {
|
|
int columnIndex = query.getColumnIndex("seqno");
|
|
int columnIndex2 = query.getColumnIndex("cid");
|
|
int columnIndex3 = query.getColumnIndex("name");
|
|
if (!(columnIndex == -1 || columnIndex2 == -1)) {
|
|
if (columnIndex3 != -1) {
|
|
TreeMap treeMap = new TreeMap();
|
|
while (query.moveToNext()) {
|
|
if (query.getInt(columnIndex2) >= 0) {
|
|
int i = query.getInt(columnIndex);
|
|
treeMap.put(Integer.valueOf(i), query.getString(columnIndex3));
|
|
}
|
|
}
|
|
ArrayList arrayList = new ArrayList(treeMap.size());
|
|
arrayList.addAll(treeMap.values());
|
|
Index index = new Index(str, z2, arrayList);
|
|
query.close();
|
|
return index;
|
|
}
|
|
}
|
|
return null;
|
|
} finally {
|
|
query.close();
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
private static Set<Index> readIndices(SupportSQLiteDatabase supportSQLiteDatabase, String str) {
|
|
Cursor query = supportSQLiteDatabase.query("PRAGMA index_list(`" + str + "`)");
|
|
try {
|
|
int columnIndex = query.getColumnIndex("name");
|
|
int columnIndex2 = query.getColumnIndex("origin");
|
|
int columnIndex3 = query.getColumnIndex("unique");
|
|
if (!(columnIndex == -1 || columnIndex2 == -1)) {
|
|
if (columnIndex3 != -1) {
|
|
HashSet hashSet = new HashSet();
|
|
while (query.moveToNext()) {
|
|
if ("c".equals(query.getString(columnIndex2))) {
|
|
String string = query.getString(columnIndex);
|
|
boolean z2 = true;
|
|
if (query.getInt(columnIndex3) != 1) {
|
|
z2 = false;
|
|
}
|
|
Index readIndex = readIndex(supportSQLiteDatabase, string, z2);
|
|
if (readIndex == null) {
|
|
query.close();
|
|
return null;
|
|
}
|
|
hashSet.add(readIndex);
|
|
}
|
|
}
|
|
query.close();
|
|
return hashSet;
|
|
}
|
|
}
|
|
return null;
|
|
} finally {
|
|
query.close();
|
|
}
|
|
}
|
|
|
|
public boolean equals(Object obj) {
|
|
Set<Index> set;
|
|
if (this == obj) {
|
|
return true;
|
|
}
|
|
if (obj == null || getClass() != obj.getClass()) {
|
|
return false;
|
|
}
|
|
TableInfo tableInfo = (TableInfo) obj;
|
|
String str = this.name;
|
|
if (str == null ? tableInfo.name != null : !str.equals(tableInfo.name)) {
|
|
return false;
|
|
}
|
|
Map<String, Column> map = this.columns;
|
|
if (map == null ? tableInfo.columns != null : !map.equals(tableInfo.columns)) {
|
|
return false;
|
|
}
|
|
Set<ForeignKey> set2 = this.foreignKeys;
|
|
if (set2 == null ? tableInfo.foreignKeys != null : !set2.equals(tableInfo.foreignKeys)) {
|
|
return false;
|
|
}
|
|
Set<Index> set3 = this.indices;
|
|
if (set3 == null || (set = tableInfo.indices) == null) {
|
|
return true;
|
|
}
|
|
return set3.equals(set);
|
|
}
|
|
|
|
public int hashCode() {
|
|
String str = this.name;
|
|
int i = 0;
|
|
int hashCode = (str != null ? str.hashCode() : 0) * 31;
|
|
Map<String, Column> map = this.columns;
|
|
int hashCode2 = (hashCode + (map != null ? map.hashCode() : 0)) * 31;
|
|
Set<ForeignKey> set = this.foreignKeys;
|
|
if (set != null) {
|
|
i = set.hashCode();
|
|
}
|
|
return hashCode2 + i;
|
|
}
|
|
|
|
public String toString() {
|
|
StringBuilder L = a.L("TableInfo{name='");
|
|
L.append(this.name);
|
|
L.append('\'');
|
|
L.append(", columns=");
|
|
L.append(this.columns);
|
|
L.append(", foreignKeys=");
|
|
L.append(this.foreignKeys);
|
|
L.append(", indices=");
|
|
L.append(this.indices);
|
|
L.append('}');
|
|
return L.toString();
|
|
}
|
|
}
|