mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-12-23 08:21:09 +00:00
Enable ANALYZE with no argument/full analyze
This commit is contained in:
parent
8355217064
commit
8a69a238c9
1 changed files with 255 additions and 306 deletions
|
|
@ -23,21 +23,15 @@ pub fn translate_analyze(
|
|||
resolver: &Resolver,
|
||||
mut program: ProgramBuilder,
|
||||
) -> Result<ProgramBuilder> {
|
||||
enum AnalyzeTarget {
|
||||
Table { table: Arc<BTreeTable> },
|
||||
Index { table: Arc<BTreeTable> },
|
||||
}
|
||||
|
||||
let (target_table, target_index) = match target_opt {
|
||||
// Collect all analyze targets up front so we can create/open sqlite_stat1 just once.
|
||||
let analyze_targets: Vec<(Arc<BTreeTable>, Option<Arc<Index>>)> = match target_opt {
|
||||
Some(target) => {
|
||||
let normalized = normalize_ident(target.name.as_str());
|
||||
if let Some(table) = resolver.schema.get_btree_table(&normalized) {
|
||||
(
|
||||
AnalyzeTarget::Table {
|
||||
table: table.clone(),
|
||||
},
|
||||
None,
|
||||
)
|
||||
vec![(
|
||||
table.clone(),
|
||||
None, // analyze the whole table and its indexes
|
||||
)]
|
||||
} else {
|
||||
// Try to find an index by this name.
|
||||
let mut found: Option<(Arc<BTreeTable>, Arc<Index>)> = None;
|
||||
|
|
@ -55,21 +49,27 @@ pub fn translate_analyze(
|
|||
let Some((table, index)) = found else {
|
||||
bail_parse_error!("no such table or index: {}", target.name);
|
||||
};
|
||||
(
|
||||
AnalyzeTarget::Index {
|
||||
table: table.clone(),
|
||||
},
|
||||
Some(index),
|
||||
)
|
||||
vec![(table.clone(), Some(index))]
|
||||
}
|
||||
}
|
||||
None => bail_parse_error!("ANALYZE with no target is not supported"),
|
||||
None => resolver
|
||||
.schema
|
||||
.tables
|
||||
.iter()
|
||||
.filter_map(|(name, table)| {
|
||||
if name.eq_ignore_ascii_case("sqlite_schema")
|
||||
|| name.eq_ignore_ascii_case("sqlite_stat1")
|
||||
{
|
||||
return None;
|
||||
}
|
||||
table.btree().map(|bt| (bt, None))
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let target_table = match &target_table {
|
||||
AnalyzeTarget::Table { table } => table.clone(),
|
||||
AnalyzeTarget::Index { table, .. } => table.clone(),
|
||||
};
|
||||
if analyze_targets.is_empty() {
|
||||
return Ok(program);
|
||||
}
|
||||
|
||||
// This is emitted early because SQLite does, and thus generated VDBE matches a bit closer.
|
||||
let null_reg = program.alloc_register();
|
||||
|
|
@ -87,59 +87,6 @@ pub fn translate_analyze(
|
|||
if let Some(sqlite_stat1) = resolver.schema.get_btree_table("sqlite_stat1") {
|
||||
sqlite_stat1_btreetable = sqlite_stat1.clone();
|
||||
sqlite_stat1_source = RegisterOrLiteral::Literal(sqlite_stat1.root_page);
|
||||
// sqlite_stat1 already exists, so we need to remove any rows
|
||||
// corresponding to the stats for the table which we're about to
|
||||
// ANALYZE. SQLite implements this as a full table scan over sqlite_stat1
|
||||
// deleting any rows where the first column (table_name) is the targeted table.
|
||||
let cursor_id = program.alloc_cursor_id(CursorType::BTreeTable(sqlite_stat1.clone()));
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
cursor_id,
|
||||
root_page: RegisterOrLiteral::Literal(sqlite_stat1.root_page),
|
||||
db: 0,
|
||||
});
|
||||
let after_loop = program.allocate_label();
|
||||
program.emit_insn(Insn::Rewind {
|
||||
cursor_id,
|
||||
pc_if_empty: after_loop,
|
||||
});
|
||||
let loophead = program.allocate_label();
|
||||
program.preassign_label_to_next_insn(loophead);
|
||||
let column_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::Column {
|
||||
cursor_id,
|
||||
column: 0,
|
||||
dest: column_reg,
|
||||
default: None,
|
||||
});
|
||||
let tablename_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::String8 {
|
||||
value: target_table.name.to_string(),
|
||||
dest: tablename_reg,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
// FIXME: The SQLite instruction says p4=BINARY-8 and p5=81. Neither are currently supported in Turso.
|
||||
program.emit_insn(Insn::Ne {
|
||||
lhs: column_reg,
|
||||
rhs: tablename_reg,
|
||||
target_pc: after_loop,
|
||||
flags: Default::default(),
|
||||
collation: None,
|
||||
});
|
||||
let rowid_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::RowId {
|
||||
cursor_id,
|
||||
dest: rowid_reg,
|
||||
});
|
||||
program.emit_insn(Insn::Delete {
|
||||
cursor_id,
|
||||
table_name: "sqlite_stat1".to_string(),
|
||||
is_part_of_update: false,
|
||||
});
|
||||
program.emit_insn(Insn::Next {
|
||||
cursor_id,
|
||||
pc_if_next: loophead,
|
||||
});
|
||||
program.preassign_label_to_next_insn(after_loop);
|
||||
} else {
|
||||
// FIXME: Emit ReadCookie 0 3 2
|
||||
// FIXME: Emit If 3 +2 0
|
||||
|
|
@ -205,11 +152,7 @@ pub fn translate_analyze(
|
|||
});
|
||||
};
|
||||
|
||||
if !target_table.has_rowid {
|
||||
bail_parse_error!("ANALYZE on tables without rowid is not supported");
|
||||
}
|
||||
|
||||
// Count the number of rows in the target table, and insert it into sqlite_stat1.
|
||||
// Count the number of rows in the target table(s), and insert into sqlite_stat1.
|
||||
let sqlite_stat1 = sqlite_stat1_btreetable;
|
||||
let stat_cursor = program.alloc_cursor_id(CursorType::BTreeTable(sqlite_stat1.clone()));
|
||||
program.emit_insn(Insn::OpenWrite {
|
||||
|
|
@ -218,268 +161,274 @@ pub fn translate_analyze(
|
|||
db: 0,
|
||||
});
|
||||
|
||||
// Remove existing stat rows for this target before inserting fresh ones.
|
||||
let rewind_done = program.allocate_label();
|
||||
program.emit_insn(Insn::Rewind {
|
||||
cursor_id: stat_cursor,
|
||||
pc_if_empty: rewind_done,
|
||||
});
|
||||
let loop_start = program.allocate_label();
|
||||
program.preassign_label_to_next_insn(loop_start);
|
||||
for (target_table, target_index) in analyze_targets {
|
||||
if !target_table.has_rowid {
|
||||
bail_parse_error!("ANALYZE on tables without rowid is not supported");
|
||||
}
|
||||
|
||||
let tbl_col_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::Column {
|
||||
cursor_id: stat_cursor,
|
||||
column: 0,
|
||||
dest: tbl_col_reg,
|
||||
default: None,
|
||||
});
|
||||
let target_tbl_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::String8 {
|
||||
value: target_table.name.to_string(),
|
||||
dest: target_tbl_reg,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
// Remove existing stat rows for this target before inserting fresh ones.
|
||||
let rewind_done = program.allocate_label();
|
||||
program.emit_insn(Insn::Rewind {
|
||||
cursor_id: stat_cursor,
|
||||
pc_if_empty: rewind_done,
|
||||
});
|
||||
let loop_start = program.allocate_label();
|
||||
program.preassign_label_to_next_insn(loop_start);
|
||||
|
||||
let skip_label = program.allocate_label();
|
||||
program.emit_insn(Insn::Ne {
|
||||
lhs: tbl_col_reg,
|
||||
rhs: target_tbl_reg,
|
||||
target_pc: skip_label,
|
||||
flags: Default::default(),
|
||||
collation: None,
|
||||
});
|
||||
|
||||
if let Some(idx) = target_index.clone() {
|
||||
let idx_col_reg = program.alloc_register();
|
||||
let tbl_col_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::Column {
|
||||
cursor_id: stat_cursor,
|
||||
column: 1,
|
||||
dest: idx_col_reg,
|
||||
column: 0,
|
||||
dest: tbl_col_reg,
|
||||
default: None,
|
||||
});
|
||||
let target_idx_reg = program.alloc_register();
|
||||
let target_tbl_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::String8 {
|
||||
value: idx.name.to_string(),
|
||||
dest: target_idx_reg,
|
||||
value: target_table.name.to_string(),
|
||||
dest: target_tbl_reg,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
let continue_label = program.allocate_label();
|
||||
|
||||
let skip_label = program.allocate_label();
|
||||
program.emit_insn(Insn::Ne {
|
||||
lhs: idx_col_reg,
|
||||
rhs: target_idx_reg,
|
||||
target_pc: continue_label,
|
||||
lhs: tbl_col_reg,
|
||||
rhs: target_tbl_reg,
|
||||
target_pc: skip_label,
|
||||
flags: Default::default(),
|
||||
collation: None,
|
||||
});
|
||||
let rowid_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::RowId {
|
||||
cursor_id: stat_cursor,
|
||||
dest: rowid_reg,
|
||||
});
|
||||
program.emit_insn(Insn::Delete {
|
||||
cursor_id: stat_cursor,
|
||||
table_name: "sqlite_stat1".to_string(),
|
||||
is_part_of_update: false,
|
||||
});
|
||||
|
||||
if let Some(idx) = target_index.clone() {
|
||||
let idx_col_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::Column {
|
||||
cursor_id: stat_cursor,
|
||||
column: 1,
|
||||
dest: idx_col_reg,
|
||||
default: None,
|
||||
});
|
||||
let target_idx_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::String8 {
|
||||
value: idx.name.to_string(),
|
||||
dest: target_idx_reg,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
let continue_label = program.allocate_label();
|
||||
program.emit_insn(Insn::Ne {
|
||||
lhs: idx_col_reg,
|
||||
rhs: target_idx_reg,
|
||||
target_pc: continue_label,
|
||||
flags: Default::default(),
|
||||
collation: None,
|
||||
});
|
||||
let rowid_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::RowId {
|
||||
cursor_id: stat_cursor,
|
||||
dest: rowid_reg,
|
||||
});
|
||||
program.emit_insn(Insn::Delete {
|
||||
cursor_id: stat_cursor,
|
||||
table_name: "sqlite_stat1".to_string(),
|
||||
is_part_of_update: false,
|
||||
});
|
||||
program.emit_insn(Insn::Next {
|
||||
cursor_id: stat_cursor,
|
||||
pc_if_next: loop_start,
|
||||
});
|
||||
program.preassign_label_to_next_insn(continue_label);
|
||||
} else {
|
||||
let rowid_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::RowId {
|
||||
cursor_id: stat_cursor,
|
||||
dest: rowid_reg,
|
||||
});
|
||||
program.emit_insn(Insn::Delete {
|
||||
cursor_id: stat_cursor,
|
||||
table_name: "sqlite_stat1".to_string(),
|
||||
is_part_of_update: false,
|
||||
});
|
||||
program.emit_insn(Insn::Next {
|
||||
cursor_id: stat_cursor,
|
||||
pc_if_next: loop_start,
|
||||
});
|
||||
}
|
||||
|
||||
program.preassign_label_to_next_insn(skip_label);
|
||||
program.emit_insn(Insn::Next {
|
||||
cursor_id: stat_cursor,
|
||||
pc_if_next: loop_start,
|
||||
});
|
||||
program.preassign_label_to_next_insn(continue_label);
|
||||
} else {
|
||||
program.preassign_label_to_next_insn(rewind_done);
|
||||
|
||||
let target_cursor = program.alloc_cursor_id(CursorType::BTreeTable(target_table.clone()));
|
||||
program.emit_insn(Insn::OpenRead {
|
||||
cursor_id: target_cursor,
|
||||
root_page: target_table.root_page,
|
||||
db: 0,
|
||||
});
|
||||
let rowid_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::RowId {
|
||||
cursor_id: stat_cursor,
|
||||
dest: rowid_reg,
|
||||
});
|
||||
program.emit_insn(Insn::Delete {
|
||||
cursor_id: stat_cursor,
|
||||
table_name: "sqlite_stat1".to_string(),
|
||||
is_part_of_update: false,
|
||||
});
|
||||
program.emit_insn(Insn::Next {
|
||||
cursor_id: stat_cursor,
|
||||
pc_if_next: loop_start,
|
||||
});
|
||||
}
|
||||
|
||||
program.preassign_label_to_next_insn(skip_label);
|
||||
program.emit_insn(Insn::Next {
|
||||
cursor_id: stat_cursor,
|
||||
pc_if_next: loop_start,
|
||||
});
|
||||
program.preassign_label_to_next_insn(rewind_done);
|
||||
|
||||
let target_cursor = program.alloc_cursor_id(CursorType::BTreeTable(target_table.clone()));
|
||||
program.emit_insn(Insn::OpenRead {
|
||||
cursor_id: target_cursor,
|
||||
root_page: target_table.root_page,
|
||||
db: 0,
|
||||
});
|
||||
let rowid_reg = program.alloc_register();
|
||||
let tablename_reg = program.alloc_register();
|
||||
let indexname_reg = program.alloc_register();
|
||||
let stat_text_reg = program.alloc_register();
|
||||
let record_reg = program.alloc_register();
|
||||
let count_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::String8 {
|
||||
value: target_table.name.to_string(),
|
||||
dest: tablename_reg,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
program.emit_insn(Insn::Count {
|
||||
cursor_id: target_cursor,
|
||||
target_reg: count_reg,
|
||||
exact: true,
|
||||
});
|
||||
let after_insert = program.allocate_label();
|
||||
program.emit_insn(Insn::IfNot {
|
||||
reg: count_reg,
|
||||
target_pc: after_insert,
|
||||
jump_if_null: false,
|
||||
});
|
||||
program.emit_insn(Insn::Null {
|
||||
dest: indexname_reg,
|
||||
dest_end: None,
|
||||
});
|
||||
// stat = CAST(count AS TEXT)
|
||||
program.emit_insn(Insn::Copy {
|
||||
src_reg: count_reg,
|
||||
dst_reg: stat_text_reg,
|
||||
extra_amount: 0,
|
||||
});
|
||||
program.emit_insn(Insn::Cast {
|
||||
reg: stat_text_reg,
|
||||
affinity: Affinity::Text,
|
||||
});
|
||||
program.emit_insn(Insn::MakeRecord {
|
||||
start_reg: tablename_reg,
|
||||
count: 3,
|
||||
dest_reg: record_reg,
|
||||
index_name: None,
|
||||
affinity_str: None,
|
||||
});
|
||||
program.emit_insn(Insn::NewRowid {
|
||||
cursor: stat_cursor,
|
||||
rowid_reg,
|
||||
prev_largest_reg: 0,
|
||||
});
|
||||
// FIXME: SQLite sets OPFLAG_APPEND on the insert, but that's not supported in turso right now.
|
||||
// SQLite doesn't emit the table name, but like... why not?
|
||||
program.emit_insn(Insn::Insert {
|
||||
cursor: stat_cursor,
|
||||
key_reg: rowid_reg,
|
||||
record_reg,
|
||||
flag: Default::default(),
|
||||
table_name: "sqlite_stat1".to_string(),
|
||||
});
|
||||
program.preassign_label_to_next_insn(after_insert);
|
||||
// Emit index stats for this table (or for a single index target).
|
||||
let indexes: Vec<Arc<Index>> = match target_index {
|
||||
Some(idx) => vec![idx],
|
||||
None => resolver
|
||||
.schema
|
||||
.get_indices(&target_table.name)
|
||||
.filter(|idx| idx.index_method.is_none()) // skip virtual/custom for now
|
||||
.cloned()
|
||||
.collect(),
|
||||
};
|
||||
|
||||
if !indexes.is_empty() {
|
||||
let space_reg = program.alloc_register();
|
||||
let tablename_reg = program.alloc_register();
|
||||
let indexname_reg = program.alloc_register();
|
||||
let stat_text_reg = program.alloc_register();
|
||||
let record_reg = program.alloc_register();
|
||||
let count_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::String8 {
|
||||
value: " ".to_string(),
|
||||
dest: space_reg,
|
||||
value: target_table.name.to_string(),
|
||||
dest: tablename_reg,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
program.emit_insn(Insn::Count {
|
||||
cursor_id: target_cursor,
|
||||
target_reg: count_reg,
|
||||
exact: true,
|
||||
});
|
||||
let after_insert = program.allocate_label();
|
||||
program.emit_insn(Insn::IfNot {
|
||||
reg: count_reg,
|
||||
target_pc: after_insert,
|
||||
jump_if_null: false,
|
||||
});
|
||||
program.emit_insn(Insn::Null {
|
||||
dest: indexname_reg,
|
||||
dest_end: None,
|
||||
});
|
||||
// stat = CAST(count AS TEXT)
|
||||
program.emit_insn(Insn::Copy {
|
||||
src_reg: count_reg,
|
||||
dst_reg: stat_text_reg,
|
||||
extra_amount: 0,
|
||||
});
|
||||
program.emit_insn(Insn::Cast {
|
||||
reg: stat_text_reg,
|
||||
affinity: Affinity::Text,
|
||||
});
|
||||
program.emit_insn(Insn::MakeRecord {
|
||||
start_reg: tablename_reg,
|
||||
count: 3,
|
||||
dest_reg: record_reg,
|
||||
index_name: None,
|
||||
affinity_str: None,
|
||||
});
|
||||
program.emit_insn(Insn::NewRowid {
|
||||
cursor: stat_cursor,
|
||||
rowid_reg,
|
||||
prev_largest_reg: 0,
|
||||
});
|
||||
// FIXME: SQLite sets OPFLAG_APPEND on the insert, but that's not supported in turso right now.
|
||||
// SQLite doesn't emit the table name, but like... why not?
|
||||
program.emit_insn(Insn::Insert {
|
||||
cursor: stat_cursor,
|
||||
key_reg: rowid_reg,
|
||||
record_reg,
|
||||
flag: Default::default(),
|
||||
table_name: "sqlite_stat1".to_string(),
|
||||
});
|
||||
program.preassign_label_to_next_insn(after_insert);
|
||||
// Emit index stats for this table (or for a single index target).
|
||||
let indexes: Vec<Arc<Index>> = match target_index {
|
||||
Some(idx) => vec![idx],
|
||||
None => resolver
|
||||
.schema
|
||||
.get_indices(&target_table.name)
|
||||
.filter(|idx| idx.index_method.is_none()) // skip custom for now
|
||||
.cloned()
|
||||
.collect(),
|
||||
};
|
||||
|
||||
for index in indexes {
|
||||
let idx_cursor = program.alloc_cursor_id(CursorType::BTreeIndex(index.clone()));
|
||||
program.emit_insn(Insn::OpenRead {
|
||||
cursor_id: idx_cursor,
|
||||
root_page: index.root_page,
|
||||
db: 0,
|
||||
});
|
||||
|
||||
let idx_count_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::Count {
|
||||
cursor_id: idx_cursor,
|
||||
target_reg: idx_count_reg,
|
||||
exact: true,
|
||||
});
|
||||
|
||||
let idx_tablename_reg = program.alloc_register();
|
||||
let idx_name_reg = program.alloc_register();
|
||||
let idx_stat_reg = program.alloc_register();
|
||||
let idx_record_reg = program.alloc_register();
|
||||
|
||||
if !indexes.is_empty() {
|
||||
let space_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::String8 {
|
||||
value: target_table.name.to_string(),
|
||||
dest: idx_tablename_reg,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
program.emit_insn(Insn::String8 {
|
||||
value: index.name.to_string(),
|
||||
dest: idx_name_reg,
|
||||
value: " ".to_string(),
|
||||
dest: space_reg,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
|
||||
// idx_stat_reg starts as CAST(count AS TEXT)
|
||||
program.emit_insn(Insn::Copy {
|
||||
src_reg: idx_count_reg,
|
||||
dst_reg: idx_stat_reg,
|
||||
extra_amount: 0,
|
||||
});
|
||||
program.emit_insn(Insn::Cast {
|
||||
reg: idx_stat_reg,
|
||||
affinity: Affinity::Text,
|
||||
});
|
||||
for index in indexes {
|
||||
let idx_cursor = program.alloc_cursor_id(CursorType::BTreeIndex(index.clone()));
|
||||
program.emit_insn(Insn::OpenRead {
|
||||
cursor_id: idx_cursor,
|
||||
root_page: index.root_page,
|
||||
db: 0,
|
||||
});
|
||||
|
||||
// Append one entry per indexed column; naive fallback uses the same count value.
|
||||
for _ in index.columns.iter() {
|
||||
let part_reg = program.alloc_register();
|
||||
let idx_count_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::Count {
|
||||
cursor_id: idx_cursor,
|
||||
target_reg: idx_count_reg,
|
||||
exact: true,
|
||||
});
|
||||
|
||||
let idx_tablename_reg = program.alloc_register();
|
||||
let idx_name_reg = program.alloc_register();
|
||||
let idx_stat_reg = program.alloc_register();
|
||||
let idx_record_reg = program.alloc_register();
|
||||
|
||||
program.emit_insn(Insn::String8 {
|
||||
value: target_table.name.to_string(),
|
||||
dest: idx_tablename_reg,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
program.emit_insn(Insn::String8 {
|
||||
value: index.name.to_string(),
|
||||
dest: idx_name_reg,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
|
||||
// idx_stat_reg starts as CAST(count AS TEXT)
|
||||
program.emit_insn(Insn::Copy {
|
||||
src_reg: idx_count_reg,
|
||||
dst_reg: part_reg,
|
||||
dst_reg: idx_stat_reg,
|
||||
extra_amount: 0,
|
||||
});
|
||||
program.emit_insn(Insn::Cast {
|
||||
reg: part_reg,
|
||||
reg: idx_stat_reg,
|
||||
affinity: Affinity::Text,
|
||||
});
|
||||
program.emit_insn(Insn::Concat {
|
||||
lhs: idx_stat_reg,
|
||||
rhs: space_reg,
|
||||
dest: idx_stat_reg,
|
||||
|
||||
// Append one entry per indexed column; naive fallback uses the same count value.
|
||||
for _ in index.columns.iter() {
|
||||
let part_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::Copy {
|
||||
src_reg: idx_count_reg,
|
||||
dst_reg: part_reg,
|
||||
extra_amount: 0,
|
||||
});
|
||||
program.emit_insn(Insn::Cast {
|
||||
reg: part_reg,
|
||||
affinity: Affinity::Text,
|
||||
});
|
||||
program.emit_insn(Insn::Concat {
|
||||
lhs: idx_stat_reg,
|
||||
rhs: space_reg,
|
||||
dest: idx_stat_reg,
|
||||
});
|
||||
program.emit_insn(Insn::Concat {
|
||||
lhs: idx_stat_reg,
|
||||
rhs: part_reg,
|
||||
dest: idx_stat_reg,
|
||||
});
|
||||
}
|
||||
|
||||
program.emit_insn(Insn::MakeRecord {
|
||||
start_reg: idx_tablename_reg,
|
||||
count: 3,
|
||||
dest_reg: idx_record_reg,
|
||||
index_name: None,
|
||||
affinity_str: None,
|
||||
});
|
||||
program.emit_insn(Insn::Concat {
|
||||
lhs: idx_stat_reg,
|
||||
rhs: part_reg,
|
||||
dest: idx_stat_reg,
|
||||
let idx_rowid_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::NewRowid {
|
||||
cursor: stat_cursor,
|
||||
rowid_reg: idx_rowid_reg,
|
||||
prev_largest_reg: 0,
|
||||
});
|
||||
program.emit_insn(Insn::Insert {
|
||||
cursor: stat_cursor,
|
||||
key_reg: idx_rowid_reg,
|
||||
record_reg: idx_record_reg,
|
||||
flag: Default::default(),
|
||||
table_name: "sqlite_stat1".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
program.emit_insn(Insn::MakeRecord {
|
||||
start_reg: idx_tablename_reg,
|
||||
count: 3,
|
||||
dest_reg: idx_record_reg,
|
||||
index_name: None,
|
||||
affinity_str: None,
|
||||
});
|
||||
let idx_rowid_reg = program.alloc_register();
|
||||
program.emit_insn(Insn::NewRowid {
|
||||
cursor: stat_cursor,
|
||||
rowid_reg: idx_rowid_reg,
|
||||
prev_largest_reg: 0,
|
||||
});
|
||||
program.emit_insn(Insn::Insert {
|
||||
cursor: stat_cursor,
|
||||
key_reg: idx_rowid_reg,
|
||||
record_reg: idx_record_reg,
|
||||
flag: Default::default(),
|
||||
table_name: "sqlite_stat1".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue