fix last prepares

This commit is contained in:
dignifiedquire
2019-07-10 18:31:41 +02:00
parent 9dda90dd5d
commit a0acfca255
5 changed files with 353 additions and 366 deletions

View File

@@ -1010,81 +1010,82 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
); );
} else { } else {
let dir_handle = dir_handle.unwrap(); let dir_handle = dir_handle.unwrap();
let mut stmt = dc_sqlite3_prepare(
context,
&sql,
"INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);"
).expect("bad sql state");
let mut processed_files_cnt = 0; sql.prepare(
for entry in dir_handle { "INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);",
if entry.is_err() { move |mut stmt| {
current_block = 2631791190359682872; let mut processed_files_cnt = 0;
break; for entry in dir_handle {
} if entry.is_err() {
let entry = entry.unwrap(); current_block = 2631791190359682872;
if context break;
.running_state }
.clone() let entry = entry.unwrap();
.read() if context
.unwrap() .running_state
.shall_stop_ongoing .clone()
{ .read()
delete_dest_file = 1; .unwrap()
current_block = 11487273724841241105; .shall_stop_ongoing
break;
} else {
processed_files_cnt += 1;
let mut permille =
processed_files_cnt * 1000 / total_files_cnt;
if permille < 10 {
permille = 10;
}
if permille > 990 {
permille = 990;
}
context.call_cb(
Event::IMEX_PROGRESS,
permille as uintptr_t,
0 as uintptr_t,
);
let name_f = entry.file_name();
let name = name_f.to_string_lossy();
if name.starts_with("delta-chat") && name.ends_with(".bak")
{
continue;
} else {
info!(context, 0, "EXPORTing filename={}", name);
let curr_pathNfilename = format!(
"{}/{}",
as_str(context.get_blobdir()),
name
);
if let Some(buf) =
dc_read_file_safe(context, &curr_pathNfilename)
{ {
if buf.is_empty() { delete_dest_file = 1;
continue; current_block = 11487273724841241105;
} break;
if stmt.execute(params![name, buf]).is_err() {
error!(
context,
0,
"Disk full? Cannot add file \"{}\" to backup.",
&curr_pathNfilename,
);
/* this is not recoverable! writing to the sqlite database should work! */
current_block = 11487273724841241105;
break;
}
} else { } else {
continue; processed_files_cnt += 1;
let mut permille =
processed_files_cnt * 1000 / total_files_cnt;
if permille < 10 {
permille = 10;
}
if permille > 990 {
permille = 990;
}
context.call_cb(
Event::IMEX_PROGRESS,
permille as uintptr_t,
0 as uintptr_t,
);
let name_f = entry.file_name();
let name = name_f.to_string_lossy();
if name.starts_with("delta-chat") && name.ends_with(".bak")
{
continue;
} else {
info!(context, 0, "EXPORTing filename={}", name);
let curr_pathNfilename = format!(
"{}/{}",
as_str(context.get_blobdir()),
name
);
if let Some(buf) =
dc_read_file_safe(context, &curr_pathNfilename)
{
if buf.is_empty() {
continue;
}
if stmt.execute(params![name, buf]).is_err() {
error!(
context,
0,
"Disk full? Cannot add file \"{}\" to backup.",
&curr_pathNfilename,
);
/* this is not recoverable! writing to the sqlite database should work! */
current_block = 11487273724841241105;
break;
}
} else {
continue;
}
}
} }
} }
Ok(())
} }
} ).unwrap();
} }
} else { } else {
info!(context, 0, "Backup: No files to copy.",); info!(context, 0, "Backup: No files to copy.",);

View File

@@ -409,71 +409,52 @@ pub unsafe fn dc_save_locations(
return 0; return 0;
} }
let stmt_test = dc_sqlite3_prepare( context
context, .sql
&context.sql, .prepare2(
"SELECT id FROM locations WHERE timestamp=? AND from_id=?", "SELECT id FROM locations WHERE timestamp=? AND from_id=?",
); "INSERT INTO locations\
let stmt_insert = dc_sqlite3_prepare( (timestamp, from_id, chat_id, latitude, longitude, accuracy, independent) \
context, VALUES (?,?,?,?,?,?,?);",
&context.sql, |mut stmt_test, mut stmt_insert, conn| {
"INSERT INTO locations\ let mut newest_timestamp = 0;
(timestamp, from_id, chat_id, latitude, longitude, accuracy, independent) \ let mut newest_location_id = 0;
VALUES (?,?,?,?,?,?,?);",
);
if stmt_test.is_none() || stmt_insert.is_none() { for i in 0..dc_array_get_cnt(locations) {
return 0; let location = dc_array_get_ptr(locations, i as size_t) as *mut dc_location_t;
}
let mut stmt_test = stmt_test.unwrap(); let exists =
let mut stmt_insert = stmt_insert.unwrap(); stmt_test.exists(params![(*location).timestamp, contact_id as i32])?;
let mut newest_timestamp = 0; if 0 != independent || !exists {
let mut newest_location_id = 0; stmt_insert.execute(params![
(*location).timestamp,
contact_id as i32,
chat_id as i32,
(*location).latitude,
(*location).longitude,
(*location).accuracy,
independent,
])?;
for i in 0..dc_array_get_cnt(locations) { if (*location).timestamp > newest_timestamp {
// TODO: do I need to reset? newest_timestamp = (*location).timestamp;
newest_location_id = get_rowid2(
let location = dc_array_get_ptr(locations, i as size_t) as *mut dc_location_t; context,
conn,
let exists = stmt_test "locations",
.exists(params![(*location).timestamp, contact_id as i32]) "timestamp",
.unwrap_or_default(); (*location).timestamp,
"from_id",
if 0 != independent || !exists { contact_id as i32,
// TODO: do I need to reset? );
if stmt_insert }
.execute(params![ }
(*location).timestamp, }
contact_id as i32, Ok(newest_location_id)
chat_id as i32, },
(*location).latitude, )
(*location).longitude, .unwrap_or_default()
(*location).accuracy,
independent,
])
.is_err()
{
return 0;
}
if (*location).timestamp > newest_timestamp {
newest_timestamp = (*location).timestamp;
newest_location_id = dc_sqlite3_get_rowid2(
context,
&context.sql,
"locations",
"timestamp",
(*location).timestamp,
"from_id",
contact_id as i32,
);
}
}
}
newest_location_id
} }
pub unsafe fn dc_kml_parse( pub unsafe fn dc_kml_parse(
@@ -677,9 +658,7 @@ pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: *mu
} }
}, },
|rows| { |rows| {
let stmt_locations = dc_sqlite3_prepare( context.sql.prepare(
context,
&context.sql,
"SELECT id \ "SELECT id \
FROM locations \ FROM locations \
WHERE from_id=? \ WHERE from_id=? \
@@ -687,44 +666,40 @@ pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: *mu
AND timestamp>? \ AND timestamp>? \
AND independent=0 \ AND independent=0 \
ORDER BY timestamp;", ORDER BY timestamp;",
); |mut stmt_locations| {
if stmt_locations.is_none() { for (chat_id, locations_send_begin, locations_last_sent) in
// TODO: handle error rows.filter_map(|r| match r {
return Ok(()); Ok(Some(v)) => Some(v),
} _ => None,
let mut stmt_locations = stmt_locations.unwrap(); })
{
for (chat_id, locations_send_begin, locations_last_sent) in // TODO: do I need to reset?
rows.filter_map(|r| match r { if !stmt_locations
Ok(Some(v)) => Some(v), .exists(params![1, locations_send_begin, locations_last_sent,])
_ => None, .unwrap_or_default()
}) {
{ // if there is no new location, there's nothing to send.
// TODO: do I need to reset? // however, maybe we want to bypass this test eg. 15 minutes
if !stmt_locations continue;
.exists(params![1, locations_send_begin, locations_last_sent,]) }
.unwrap_or_default() // pending locations are attached automatically to every message,
{ // so also to this empty text message.
// if there is no new location, there's nothing to send. // DC_CMD_LOCATION is only needed to create a nicer subject.
// however, maybe we want to bypass this test eg. 15 minutes //
continue; // for optimisation and to avoid flooding the sending queue,
} // we could sending these messages only if we're really online.
// pending locations are attached automatically to every message, // the easiest way to determine this, is to check for an empty message queue.
// so also to this empty text message. // (might not be 100%, however, as positions are sent combined later
// DC_CMD_LOCATION is only needed to create a nicer subject. // and dc_set_location() is typically called periodically, this is ok)
// let mut msg = dc_msg_new(context, 10);
// for optimisation and to avoid flooding the sending queue, (*msg).hidden = 1;
// we could sending these messages only if we're really online. dc_param_set_int((*msg).param, 'S' as i32, 9);
// the easiest way to determine this, is to check for an empty message queue. dc_send_msg(context, chat_id as u32, msg);
// (might not be 100%, however, as positions are sent combined later dc_msg_unref(msg);
// and dc_set_location() is typically called periodically, this is ok) }
let mut msg = dc_msg_new(context, 10); Ok(())
(*msg).hidden = 1; },
dc_param_set_int((*msg).param, 'S' as i32, 9); )
dc_send_msg(context, chat_id as u32, msg);
dc_msg_unref(msg);
}
Ok(())
}, },
) )
.unwrap(); // TODO: Better error handling .unwrap(); // TODO: Better error handling

View File

@@ -524,54 +524,50 @@ pub fn dc_update_msg_chat_id(context: &Context, msg_id: u32, chat_id: u32) -> bo
) )
} }
pub unsafe fn dc_markseen_msgs(context: &Context, msg_ids: *const u32, msg_cnt: usize) { pub fn dc_markseen_msgs(context: &Context, msg_ids: *const u32, msg_cnt: usize) -> bool {
if msg_ids.is_null() || msg_cnt <= 0 { if msg_ids.is_null() || msg_cnt <= 0 {
return; return false;
} }
let stmt = dc_sqlite3_prepare( context.sql.prepare(
context, &context.sql, "SELECT m.state, c.blocked FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id WHERE m.id=? AND m.chat_id>9",
"SELECT m.state, c.blocked FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id WHERE m.id=? AND m.chat_id>9" |mut stmt| {
); let mut send_event = false;
if stmt.is_none() { for i in 0..msg_cnt {
// TODO: error handling // TODO: do I need to reset?
return; let id = unsafe { *msg_ids.offset(i as isize) };
} if let Ok((curr_state, curr_blocked)) = stmt
.query_row(params![id as i32], |row| {
Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?))
})
{
if curr_blocked == 0 {
if curr_state == 10 || curr_state == 13 {
dc_update_msg_state(context, id, 16);
info!(context, 0, "Seen message #{}.", id);
let mut stmt = stmt.unwrap(); unsafe { dc_job_add(
let mut send_event = false; context,
130,
for i in 0..msg_cnt { id as i32,
// TODO: do I need to reset? 0 as *const libc::c_char,
if let Ok((curr_state, curr_blocked)) = stmt 0,
.query_row(params![*msg_ids.offset(i as isize) as i32], |row| { ) };
Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?)) send_event = true;
}) }
{ } else if curr_state == 10 {
if curr_blocked == 0 { dc_update_msg_state(context, id, 13);
if curr_state == 10 || curr_state == 13 { send_event = true;
dc_update_msg_state(context, *msg_ids.offset(i as isize), 16); }
info!(context, 0, "Seen message #{}.", *msg_ids.offset(i as isize),);
dc_job_add(
context,
130,
*msg_ids.offset(i as isize) as libc::c_int,
0 as *const libc::c_char,
0,
);
send_event = true;
} }
} else if curr_state == 10 {
dc_update_msg_state(context, *msg_ids.offset(i as isize), 13);
send_event = true;
} }
}
}
if send_event { if send_event {
context.call_cb(Event::MSGS_CHANGED, 0, 0); context.call_cb(Event::MSGS_CHANGED, 0, 0);
} }
Ok(())
}
).is_ok()
} }
pub fn dc_update_msg_state(context: &Context, msg_id: uint32_t, state: libc::c_int) -> bool { pub fn dc_update_msg_state(context: &Context, msg_id: uint32_t, state: libc::c_int) -> bool {
@@ -592,26 +588,15 @@ pub fn dc_star_msgs(
if msg_ids.is_null() || msg_cnt <= 0 || star != 0 && star != 1 { if msg_ids.is_null() || msg_cnt <= 0 || star != 0 && star != 1 {
return false; return false;
} }
let stmt = dc_sqlite3_prepare( context
context, .sql
&context.sql, .prepare("UPDATE msgs SET starred=? WHERE id=?;", |mut stmt| {
"UPDATE msgs SET starred=? WHERE id=?;", for i in 0..msg_cnt {
); stmt.execute(params![star, unsafe { *msg_ids.offset(i as isize) as i32 }])?;
if stmt.is_none() { }
return false; Ok(())
} })
.is_ok()
let mut stmt = stmt.unwrap();
for i in 0..msg_cnt {
if stmt
.execute(params![star, unsafe { *msg_ids.offset(i as isize) as i32 }])
.is_err()
{
return false;
}
}
true
} }
pub unsafe fn dc_get_msg<'a>(context: &'a Context, msg_id: uint32_t) -> *mut dc_msg_t<'a> { pub unsafe fn dc_get_msg<'a>(context: &'a Context, msg_id: uint32_t) -> *mut dc_msg_t<'a> {

View File

@@ -489,122 +489,121 @@ pub unsafe fn dc_receive_imf(
} }
icnt = carray_count(mime_parser.parts) as size_t; icnt = carray_count(mime_parser.parts) as size_t;
let mut stmt = dc_sqlite3_prepare( context.sql.prepare(
context,
&context.sql,
"INSERT INTO msgs \ "INSERT INTO msgs \
(rfc724_mid, server_folder, server_uid, chat_id, from_id, to_id, timestamp, \ (rfc724_mid, server_folder, server_uid, chat_id, from_id, to_id, timestamp, \
timestamp_sent, timestamp_rcvd, type, state, msgrmsg, txt, txt_raw, param, \ timestamp_sent, timestamp_rcvd, type, state, msgrmsg, txt, txt_raw, param, \
bytes, hidden, mime_headers, mime_in_reply_to, mime_references) \ bytes, hidden, mime_headers, mime_in_reply_to, mime_references) \
VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?);" VALUES (?,?,?,?,?,?, ?,?,?,?,?,?, ?,?,?,?,?,?, ?,?);",
).unwrap(); |mut stmt| {
i = 0; let mut i = 0;
loop { loop {
if !(i < icnt) { if !(i < icnt) {
current_block = 2756754640271984560; current_block = 2756754640271984560;
break; break;
}
let part: *mut dc_mimepart_t =
carray_get(mime_parser.parts, i as libc::c_uint)
as *mut dc_mimepart_t;
if !(0 != (*part).is_meta) {
if !mime_parser.location_kml.is_null()
&& icnt == 1
&& !(*part).msg.is_null()
&& (strcmp(
(*part).msg,
b"-location-\x00" as *const u8 as *const libc::c_char,
) == 0
|| *(*part).msg.offset(0isize) as libc::c_int == 0)
{
hidden = 1;
if state == 10 {
state = 13
} }
} let part = carray_get(mime_parser.parts, i as libc::c_uint) as *mut dc_mimepart_t;
if (*part).type_0 == 10 { if !(0 != (*part).is_meta) {
txt_raw = dc_mprintf( if !mime_parser.location_kml.is_null()
b"%s\n\n%s\x00" as *const u8 as *const libc::c_char, && icnt == 1
if !mime_parser.subject.is_null() { && !(*part).msg.is_null()
mime_parser.subject && (strcmp(
(*part).msg,
b"-location-\x00" as *const u8 as *const libc::c_char,
) == 0
|| *(*part).msg.offset(0isize) as libc::c_int == 0)
{
hidden = 1;
if state == 10 {
state = 13
}
}
if (*part).type_0 == 10 {
txt_raw = dc_mprintf(
b"%s\n\n%s\x00" as *const u8 as *const libc::c_char,
if !mime_parser.subject.is_null() {
mime_parser.subject
} else {
b"\x00" as *const u8 as *const libc::c_char
},
(*part).msg_raw,
)
}
if 0 != mime_parser.is_system_message {
dc_param_set_int(
(*part).param,
'S' as i32,
mime_parser.is_system_message,
);
}
let res = stmt.execute(params![
as_str(rfc724_mid),
server_folder.as_ref(),
server_uid as libc::c_int,
chat_id as libc::c_int,
from_id as libc::c_int,
to_id as libc::c_int,
sort_timestamp,
sent_timestamp,
rcvd_timestamp,
(*part).type_0,
state,
msgrmsg,
if !(*part).msg.is_null() {
as_str((*part).msg)
} else {
""
},
if !txt_raw.is_null() {
as_str(txt_raw)
} else {
""
},
as_str((*(*part).param).packed),
(*part).bytes,
hidden,
if 0 != save_mime_headers {
Some(as_str(imf_raw_not_terminated))
} else {
None
},
as_str(mime_in_reply_to),
as_str(mime_references),
]);
if res.is_err() {
info!(context, 0, "Cannot write DB.",);
/* i/o error - there is nothing more we can do - in other cases, we try to write at least an empty record */
current_block = 16282941964262048061;
break;
} else { } else {
b"\x00" as *const u8 as *const libc::c_char free(txt_raw as *mut libc::c_void);
}, txt_raw = 0 as *mut libc::c_char;
(*part).msg_raw, insert_msg_id = dc_sqlite3_get_rowid(
) context,
} &context.sql,
if 0 != mime_parser.is_system_message { "msgs",
dc_param_set_int( "rfc724_mid",
(*part).param, as_str(rfc724_mid),
'S' as i32, );
mime_parser.is_system_message, carray_add(
); created_db_entries,
} chat_id as uintptr_t as *mut libc::c_void,
0 as *mut libc::c_uint,
let res = stmt.execute(params![ );
as_str(rfc724_mid), carray_add(
server_folder.as_ref(), created_db_entries,
server_uid as libc::c_int, insert_msg_id as uintptr_t as *mut libc::c_void,
chat_id as libc::c_int, 0 as *mut libc::c_uint,
from_id as libc::c_int, );
to_id as libc::c_int, }
sort_timestamp, }
sent_timestamp, i = i.wrapping_add(1)
rcvd_timestamp,
(*part).type_0,
state,
msgrmsg,
if !(*part).msg.is_null() {
as_str((*part).msg)
} else {
""
},
if !txt_raw.is_null() {
as_str(txt_raw)
} else {
""
},
as_str((*(*part).param).packed),
(*part).bytes,
hidden,
if 0 != save_mime_headers {
Some(as_str(imf_raw_not_terminated))
} else {
None
},
as_str(mime_in_reply_to),
as_str(mime_references),
]);
if res.is_err() {
info!(context, 0, "Cannot write DB.",);
/* i/o error - there is nothing more we can do - in other cases, we try to write at least an empty record */
current_block = 16282941964262048061;
break;
} else {
free(txt_raw as *mut libc::c_void);
txt_raw = 0 as *mut libc::c_char;
insert_msg_id = dc_sqlite3_get_rowid(
context,
&context.sql,
"msgs",
"rfc724_mid",
as_str(rfc724_mid),
);
carray_add(
created_db_entries,
chat_id as uintptr_t as *mut libc::c_void,
0 as *mut libc::c_uint,
);
carray_add(
created_db_entries,
insert_msg_id as uintptr_t as *mut libc::c_void,
0 as *mut libc::c_uint,
);
} }
Ok(())
} }
i = i.wrapping_add(1) ).unwrap(); // TODO: better error handling
}
match current_block { match current_block {
16282941964262048061 => {} 16282941964262048061 => {}
_ => { _ => {

View File

@@ -60,6 +60,32 @@ impl SQLite {
self.connection.read().unwrap() self.connection.read().unwrap()
} }
pub fn prepare<G, H>(&self, sql: &str, g: G) -> Result<H>
where
G: FnOnce(Statement<'_>) -> Result<H>,
{
let conn_lock = self.connection.read().unwrap();
let conn = conn_lock.as_ref().expect("database closed");
let stmt = conn.prepare(sql)?;
let res = g(stmt)?;
Ok(res)
}
pub fn prepare2<G, H>(&self, sql1: &str, sql2: &str, g: G) -> Result<H>
where
G: FnOnce(Statement<'_>, Statement<'_>, &Connection) -> Result<H>,
{
let conn_lock = self.connection.read().unwrap();
let conn = conn_lock.as_ref().expect("database closed");
let stmt1 = conn.prepare(sql1)?;
let stmt2 = conn.prepare(sql2)?;
let res = g(stmt1, stmt2, conn)?;
Ok(res)
}
/// Prepares and executes the statement and maps a function over the resulting rows. /// Prepares and executes the statement and maps a function over the resulting rows.
/// Then executes the second function over the returned iterator and returns the /// Then executes the second function over the returned iterator and returns the
/// result of that function. /// result of that function.
@@ -883,16 +909,6 @@ pub fn dc_sqlite3_set_config(
1 1
} }
// TODO: Remove the option from the return type
pub fn dc_sqlite3_prepare<'a>(
_context: &Context,
_sql: &'a SQLite,
_querystr: &'a str,
) -> Option<Statement<'a>> {
// TODO: remove once it is not used anymore
unimplemented!()
}
pub fn dc_sqlite3_get_config( pub fn dc_sqlite3_get_config(
context: &Context, context: &Context,
sql: &SQLite, sql: &SQLite,
@@ -1047,28 +1063,39 @@ pub fn dc_sqlite3_get_rowid2(
field2: impl AsRef<str>, field2: impl AsRef<str>,
value2: i32, value2: i32,
) -> u32 { ) -> u32 {
// same as dc_sqlite3_get_rowid() with a key over two columns
if let Some(conn) = &*sql.connection.read().unwrap() { if let Some(conn) = &*sql.connection.read().unwrap() {
match conn.query_row( get_rowid2(context, conn, table, field, value, field2, value2)
&format!(
"SELECT id FROM ? WHERE {}=? AND {}=? ORDER BY id DESC",
field.as_ref(),
field2.as_ref(),
),
params![table.as_ref(), value, value2],
|row| row.get::<_, u32>(0),
) {
Ok(id) => id,
Err(err) => {
error!(context, 0, "sql: Failed to retrieve rowid2: {}", err);
0
}
}
} else { } else {
0 0
} }
} }
pub fn get_rowid2(
context: &Context,
conn: &Connection,
table: impl AsRef<str>,
field: impl AsRef<str>,
value: i64,
field2: impl AsRef<str>,
value2: i32,
) -> u32 {
match conn.query_row(
&format!(
"SELECT id FROM ? WHERE {}=? AND {}=? ORDER BY id DESC",
field.as_ref(),
field2.as_ref(),
),
params![table.as_ref(), value, value2],
|row| row.get::<_, u32>(0),
) {
Ok(id) => id,
Err(err) => {
error!(context, 0, "sql: Failed to retrieve rowid2: {}", err);
0
}
}
}
pub fn dc_housekeeping(context: &Context) { pub fn dc_housekeeping(context: &Context) {
let mut files_in_use = HashSet::new(); let mut files_in_use = HashSet::new();
let mut unreferenced_count = 0; let mut unreferenced_count = 0;