方法超出编译器指令限制
Method exceeds compiler instruction limit
在我写这个问题之前,我搜索了所有建议的答案,“Whosebug”向我展示了但没有适合我的情况。
我的问题:
我编写了 Room migration 以从 table 复制旧数据并将其添加到另一个 table,我需要指定查询中的所有列。我有大约 130 列。
database.execSQL("INSERT INTO newTable(col1, ..n) SELECT col1, .... coln FROM oldTable")
当我执行迁移时,出现此错误:
method exceeds compiler instruction limit: 16602 in androidx.room.RoomOpenHelper$ValidationResult
谢谢你的帮助。
运行 使用 150 列(151 包括 id 列)的测试,因此 :-
2022-05-11 06:29:50.050 16308-16308/a.a.so72188145javaroommaxcolumns D/INSERTSQL: INSERT INTO newtable (id,col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12,col13,col14,col15,col16,col17,col18,col19,col20,col21,col22,col23,col24,col25,col26,col27,col28,col29,col30,col31,col32,col33,col34,col35,col36,col37,col38,col39,col40,col41,col42,col43,col44,col45,col46,col47,col48,col49,col50,col51,col52,col53,col54,col55,col56,col57,col58,col59,col60,col61,col62,col63,col64,col65,col66,col67,col68,col69,col70,col71,col72,col73,col74,col75,col76,col77,col78,col79,col80,col81,col82,col83,col84,col85,col86,col87,col88,col89,col90,col91,col92,col93,col94,col95,col96,col97,col98,col99,col100,col101,col102,col103,col104,col105,col106,col107,col108,col109,col110,col111,col112,col113,col114,col115,col116,col117,col118,col119,col120,col121,col122,col123,col124,col125,col126,col127,col128,col129,col130,col131,col132,col133,col134,col135,col136,col137,col138,col139,col140,col141,col142,col143,col144,col145,col146,col147,col148,col149,col150) SELECT id,col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12,col13,col14,col15,col16,col17,col18,col19,col20,col21,col22,col23,col24,col25,col26,col27,col28,col29,col30,col31,col32,col33,col34,col35,col36,col37,col38,col39,col40,col41,col42,col43,col44,col45,col46,col47,col48,col49,col50,col51,col52,col53,col54,col55,col56,col57,col58,col59,col60,col61,col62,col63,col64,col65,col66,col67,col68,col69,col70,col71,col72,col73,col74,col75,col76,col77,col78,col79,col80,col81,col82,col83,col84,col85,col86,col87,col88,col89,col90,col91,col92,col93,col94,col95,col96,col97,col98,col99,col100,col101,col102,col103,col104,col105,col106,col107,col108,col109,col110,col111,col112,col113,col114,col115,col116,col117,col118,col119,col120,col121,col122,col123,col124,col125,col126,col127,col128,col129,col130,col131,col132,col133,col134,col135,col136,col137,col138,col139,col140,col141,col142,col143,col144,col145,col146,col147,col148,col149,col150 FROM oldtable;
工作正常(Room 2.5.0-aplha01 和 Android 30 模拟器)。我怀疑问题可能不是列数而是 SQL.
中的其他地方
- 上面的SQL是从日志中提取出来的,完全按照当时使用的方式输出到日志中(见下面的测试代码)。
A work-around 如果您有可以为空的列并且它们的数量足以规避此问题。有一个 INSERT 插入可管理数量的列,允许其他列默认为空值,然后进行 1 个或多个更新以应用后续值来覆盖空值。
另一个 work-around 可能是将所有列 SELECT * ....
提取到 Cursor 中,然后从 Cursor 构建一个 ContentValues
(基于每行)并使用 SupportSQliteDatabase
的insert
方法。大致如下:-
Cursor csr = database.query("SELECT * FROM oldtable");
database.beginTransaction();
ContentValues cv = new ContentValues();
while (csr.moveToNext()) {
cv.clear();
for (int i=0; i < csr.getColumnCount(); i++) {
if (!csr.getColumnName(i).equals("col133")) { //<<<<< skip col133 as an example
cv.put(csr.getColumnName(i),csr.getString(i));
}
}
database.insert("newTable", SQLiteDatabase.CONFLICT_IGNORE,cv);
}
database.setTransactionSuccessful();
database.endTransaction();
用于测试的完整代码
- 请注意,两者之间的唯一变化是版本号。所以最初代码是 运行(卸载应用程序后)版本 1(因此没有迁移)。要测试它只是一个问题,然后将版本更改为 2.
@Entity
注解classOldTable:-
@Entity
class OldTable {
@PrimaryKey
Long id=null;
String col1;
String col2;
String col3;
.... (i.e. all missing numbers)
String col147;
String col148;
String col149;
String col150;
}
@Dao注解接口(实际没有用到)AllDao
@Dao
interface AllDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
long insert(OldTable oldTable);
}
@Database 注解 class TheDatabase :-
@Database(entities = {OldTable.class},version = MainActivity.DATABASE_VERSION,exportSchema = false)
abstract class TheDatabase extends RoomDatabase {
abstract AllDao getAllDao();
private static volatile TheDatabase INSTANCE = null;
static TheDatabase getINSTANCE(Context context) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context,TheDatabase.class,MainActivity.DATABASE_NAME)
.allowMainThreadQueries()
.addMigrations(MIGRATION_1_2)
.build();
}
return INSTANCE;
}
static Migration MIGRATION_1_2 = new Migration(1,2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
StringBuilder sb = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
ArrayList<String> columns = new ArrayList<>();
for (int i=0; i < MainActivity.column_count;i++) {
columns.add("col" + (i+1));
if (i>0) {
sb.append(",");
sb2.append(",");
}
sb.append(columns.get(i));
sb2.append(columns.get(i)).append(" TEXT");
}
String columnsAsCSV = sb.toString();
String columnDefs = sb2.toString();
database.execSQL("DROP TABLE IF EXISTS newtable");
database.execSQL("CREATE TABLE IF NOT EXISTS newtable (id INTEGER PRIMARY KEY," + columnDefs + ");");
String insertSQL = "INSERT INTO newtable (id,"+columnsAsCSV+") SELECT id,"+columnsAsCSV+" FROM oldtable;";
Log.d("INSERTSQL",insertSQL);
database.execSQL(insertSQL);
}
};
}
最后把它们放在一起 MainActivity :-
public class MainActivity extends AppCompatActivity {
public static final String DATABASE_NAME = "the_database.db";
public static final int DATABASE_VERSION = 2;
public static final int column_count = 150;
private ArrayList<String> column_names = new ArrayList<>();
private String allColumnsAsCSV = "";
TheDatabase db;
AllDao dao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BuildColumns();
db = TheDatabase.getINSTANCE(this);
dao = db.getAllDao();
SupportSQLiteDatabase supdb = db.getOpenHelper().getWritableDatabase();
StringBuilder sb = new StringBuilder();
for (int i=0;i < 100; i++) {
sb = new StringBuilder();
sb.append("INSERT INTO oldtable (").append(allColumnsAsCSV).append(") VALUES(");
for(int ii=0;ii<column_count;ii++) {
if (ii > 0) {
sb.append(",");
}
sb.append("'").append(column_names.get(ii)).append(i).append(ii).append("'");
}
sb.append(")");
supdb.execSQL(sb.toString());
}
}
void BuildColumns() {
column_names.clear();
allColumnsAsCSV = "";
StringBuilder sb = new StringBuilder();
for (int i=0; i < column_count; i++) {
column_names.add("col" + (i+1));
if (i>0) {
sb.append(",");
}
sb.append(column_names.get(i));
}
allColumnsAsCSV = sb.toString();
}
}
在我写这个问题之前,我搜索了所有建议的答案,“Whosebug”向我展示了但没有适合我的情况。
我的问题: 我编写了 Room migration 以从 table 复制旧数据并将其添加到另一个 table,我需要指定查询中的所有列。我有大约 130 列。
database.execSQL("INSERT INTO newTable(col1, ..n) SELECT col1, .... coln FROM oldTable")
当我执行迁移时,出现此错误:
method exceeds compiler instruction limit: 16602 in androidx.room.RoomOpenHelper$ValidationResult
谢谢你的帮助。
运行 使用 150 列(151 包括 id 列)的测试,因此 :-
2022-05-11 06:29:50.050 16308-16308/a.a.so72188145javaroommaxcolumns D/INSERTSQL: INSERT INTO newtable (id,col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12,col13,col14,col15,col16,col17,col18,col19,col20,col21,col22,col23,col24,col25,col26,col27,col28,col29,col30,col31,col32,col33,col34,col35,col36,col37,col38,col39,col40,col41,col42,col43,col44,col45,col46,col47,col48,col49,col50,col51,col52,col53,col54,col55,col56,col57,col58,col59,col60,col61,col62,col63,col64,col65,col66,col67,col68,col69,col70,col71,col72,col73,col74,col75,col76,col77,col78,col79,col80,col81,col82,col83,col84,col85,col86,col87,col88,col89,col90,col91,col92,col93,col94,col95,col96,col97,col98,col99,col100,col101,col102,col103,col104,col105,col106,col107,col108,col109,col110,col111,col112,col113,col114,col115,col116,col117,col118,col119,col120,col121,col122,col123,col124,col125,col126,col127,col128,col129,col130,col131,col132,col133,col134,col135,col136,col137,col138,col139,col140,col141,col142,col143,col144,col145,col146,col147,col148,col149,col150) SELECT id,col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12,col13,col14,col15,col16,col17,col18,col19,col20,col21,col22,col23,col24,col25,col26,col27,col28,col29,col30,col31,col32,col33,col34,col35,col36,col37,col38,col39,col40,col41,col42,col43,col44,col45,col46,col47,col48,col49,col50,col51,col52,col53,col54,col55,col56,col57,col58,col59,col60,col61,col62,col63,col64,col65,col66,col67,col68,col69,col70,col71,col72,col73,col74,col75,col76,col77,col78,col79,col80,col81,col82,col83,col84,col85,col86,col87,col88,col89,col90,col91,col92,col93,col94,col95,col96,col97,col98,col99,col100,col101,col102,col103,col104,col105,col106,col107,col108,col109,col110,col111,col112,col113,col114,col115,col116,col117,col118,col119,col120,col121,col122,col123,col124,col125,col126,col127,col128,col129,col130,col131,col132,col133,col134,col135,col136,col137,col138,col139,col140,col141,col142,col143,col144,col145,col146,col147,col148,col149,col150 FROM oldtable;
工作正常(Room 2.5.0-aplha01 和 Android 30 模拟器)。我怀疑问题可能不是列数而是 SQL.
中的其他地方- 上面的SQL是从日志中提取出来的,完全按照当时使用的方式输出到日志中(见下面的测试代码)。
A work-around 如果您有可以为空的列并且它们的数量足以规避此问题。有一个 INSERT 插入可管理数量的列,允许其他列默认为空值,然后进行 1 个或多个更新以应用后续值来覆盖空值。
另一个 work-around 可能是将所有列 SELECT * ....
提取到 Cursor 中,然后从 Cursor 构建一个 ContentValues
(基于每行)并使用 SupportSQliteDatabase
的insert
方法。大致如下:-
Cursor csr = database.query("SELECT * FROM oldtable");
database.beginTransaction();
ContentValues cv = new ContentValues();
while (csr.moveToNext()) {
cv.clear();
for (int i=0; i < csr.getColumnCount(); i++) {
if (!csr.getColumnName(i).equals("col133")) { //<<<<< skip col133 as an example
cv.put(csr.getColumnName(i),csr.getString(i));
}
}
database.insert("newTable", SQLiteDatabase.CONFLICT_IGNORE,cv);
}
database.setTransactionSuccessful();
database.endTransaction();
用于测试的完整代码
- 请注意,两者之间的唯一变化是版本号。所以最初代码是 运行(卸载应用程序后)版本 1(因此没有迁移)。要测试它只是一个问题,然后将版本更改为 2.
@Entity
注解classOldTable:-
@Entity
class OldTable {
@PrimaryKey
Long id=null;
String col1;
String col2;
String col3;
.... (i.e. all missing numbers)
String col147;
String col148;
String col149;
String col150;
}
@Dao注解接口(实际没有用到)AllDao
@Dao
interface AllDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
long insert(OldTable oldTable);
}
@Database 注解 class TheDatabase :-
@Database(entities = {OldTable.class},version = MainActivity.DATABASE_VERSION,exportSchema = false)
abstract class TheDatabase extends RoomDatabase {
abstract AllDao getAllDao();
private static volatile TheDatabase INSTANCE = null;
static TheDatabase getINSTANCE(Context context) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context,TheDatabase.class,MainActivity.DATABASE_NAME)
.allowMainThreadQueries()
.addMigrations(MIGRATION_1_2)
.build();
}
return INSTANCE;
}
static Migration MIGRATION_1_2 = new Migration(1,2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
StringBuilder sb = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
ArrayList<String> columns = new ArrayList<>();
for (int i=0; i < MainActivity.column_count;i++) {
columns.add("col" + (i+1));
if (i>0) {
sb.append(",");
sb2.append(",");
}
sb.append(columns.get(i));
sb2.append(columns.get(i)).append(" TEXT");
}
String columnsAsCSV = sb.toString();
String columnDefs = sb2.toString();
database.execSQL("DROP TABLE IF EXISTS newtable");
database.execSQL("CREATE TABLE IF NOT EXISTS newtable (id INTEGER PRIMARY KEY," + columnDefs + ");");
String insertSQL = "INSERT INTO newtable (id,"+columnsAsCSV+") SELECT id,"+columnsAsCSV+" FROM oldtable;";
Log.d("INSERTSQL",insertSQL);
database.execSQL(insertSQL);
}
};
}
最后把它们放在一起 MainActivity :-
public class MainActivity extends AppCompatActivity {
public static final String DATABASE_NAME = "the_database.db";
public static final int DATABASE_VERSION = 2;
public static final int column_count = 150;
private ArrayList<String> column_names = new ArrayList<>();
private String allColumnsAsCSV = "";
TheDatabase db;
AllDao dao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BuildColumns();
db = TheDatabase.getINSTANCE(this);
dao = db.getAllDao();
SupportSQLiteDatabase supdb = db.getOpenHelper().getWritableDatabase();
StringBuilder sb = new StringBuilder();
for (int i=0;i < 100; i++) {
sb = new StringBuilder();
sb.append("INSERT INTO oldtable (").append(allColumnsAsCSV).append(") VALUES(");
for(int ii=0;ii<column_count;ii++) {
if (ii > 0) {
sb.append(",");
}
sb.append("'").append(column_names.get(ii)).append(i).append(ii).append("'");
}
sb.append(")");
supdb.execSQL(sb.toString());
}
}
void BuildColumns() {
column_names.clear();
allColumnsAsCSV = "";
StringBuilder sb = new StringBuilder();
for (int i=0; i < column_count; i++) {
column_names.add("col" + (i+1));
if (i>0) {
sb.append(",");
}
sb.append(column_names.get(i));
}
allColumnsAsCSV = sb.toString();
}
}