fix and improve sql escaping

This commit is contained in:
dignifiedquire
2019-07-13 22:46:36 +02:00
parent 0742bb222d
commit 03a9b62a8a
4 changed files with 177 additions and 137 deletions

View File

@@ -260,14 +260,15 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id(
if sql::execute(
context,
&context.sql,
"INSERT INTO chats (type, name, param, blocked, grpid) VALUES(?, ?, ?, ?, ?)",
params![
format!(
"INSERT INTO chats (type, name, param, blocked, grpid) VALUES({}, '{}', '{}', {}, '{}')",
100,
as_str(chat_name),
if contact_id == 1 { "K=1" } else { "" },
create_blocked,
as_str((*contact).addr),
],
),
params![],
) {
chat_id = sql::get_rowid(
context,
@@ -280,8 +281,8 @@ pub unsafe fn dc_create_or_lookup_nchat_by_contact_id(
sql::execute(
context,
&context.sql,
"INSERT INTO chats_contacts (chat_id, contact_id) VALUES(?, ?)",
params![chat_id, contact_id],
format!("INSERT INTO chats_contacts (chat_id, contact_id) VALUES({}, {})", chat_id, contact_id),
params![],
);
}
}
@@ -1766,8 +1767,12 @@ pub unsafe fn dc_set_chat_name(
if sql::execute(
context,
&context.sql,
"UPDATE chats SET name=? WHERE id={};",
params![as_str(new_name), chat_id as i32],
format!(
"UPDATE chats SET name='{}' WHERE id={};",
as_str(new_name),
chat_id as i32
),
params![],
) {
if dc_param_get_int((*chat).param, 'U' as i32, 0i32) == 0i32 {
(*msg).type_0 = 10i32;
@@ -1909,8 +1914,11 @@ pub unsafe fn dc_forward_msgs(
context
.sql
.query_map(
"SELECT id FROM msgs WHERE id IN(?) ORDER BY timestamp,id",
params![as_str(idsstr)],
format!(
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
as_str(idsstr)
),
params![],
|row| row.get::<_, i32>(0),
|ids| {
for id in ids {

View File

@@ -27,19 +27,14 @@ pub unsafe fn dc_get_chatlist<'a>(
query_str: *const libc::c_char,
query_id: uint32_t,
) -> *mut dc_chatlist_t<'a> {
let mut success: libc::c_int = 0i32;
let obj: *mut dc_chatlist_t = dc_chatlist_new(context);
let obj = dc_chatlist_new(context);
if !(0 == dc_chatlist_load_from_db(obj, listflags, query_str, query_id)) {
success = 1i32
if 0 != dc_chatlist_load_from_db(obj, listflags, query_str, query_id) {
return obj;
}
if 0 != success {
return obj;
} else {
dc_chatlist_unref(obj);
return 0 as *mut dc_chatlist_t;
};
dc_chatlist_unref(obj);
return 0 as *mut dc_chatlist_t;
}
/**
@@ -122,8 +117,6 @@ unsafe fn dc_chatlist_load_from_db(
query__: *const libc::c_char,
query_contact_id: u32,
) -> libc::c_int {
//clock_t start = clock();
if chatlist.is_null() || (*chatlist).magic != 0xc4a71157u32 {
return 0;
}
@@ -142,15 +135,27 @@ unsafe fn dc_chatlist_load_from_db(
// for the deaddrop, however, they should really be hidden, however, _currently_ the deaddrop is not
// shown at all permanent in the chatlist.
let process_fn = |row: &rusqlite::Row| {
dc_array_add_id((*chatlist).chatNlastmsg_ids, row.get(0)?);
dc_array_add_id((*chatlist).chatNlastmsg_ids, row.get(1)?);
let process_row = |row: &rusqlite::Row| Ok((row.get(0)?, row.get(1)?));
let process_rows = |rows: rusqlite::MappedRows<_>| {
for row in rows {
let (id1, id2) = row?;
dc_array_add_id((*chatlist).chatNlastmsg_ids, id1);
dc_array_add_id((*chatlist).chatNlastmsg_ids, id2);
}
Ok(())
};
let success =
if query_contact_id != 0 {
(*chatlist).context.sql.query_map(
// nb: the query currently shows messages from blocked contacts in groups.
// however, for normal-groups, this is okay as the message is also returned by dc_get_chat_msgs()
// (otherwise it would be hard to follow conversations, wa and tg do the same)
// for the deaddrop, however, they should really be hidden, however, _currently_ the deaddrop is not
// shown at all permanent in the chatlist.
let success = if query_contact_id != 0 {
// show chats shared with a given contact
(*chatlist).context.sql.query_map(
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \
@@ -159,74 +164,67 @@ unsafe fn dc_chatlist_load_from_db(
AND c.blocked=0 AND c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?) \
GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![query_contact_id as i32],
process_fn,
|res| res.collect::<rusqlite::Result<Vec<_>>>().map_err(Into::into),
process_row,
process_rows,
)
} else if 0 != listflags & 0x1 {
} else if 0 != listflags & 0x1 {
// show archived chats
(*chatlist).context.sql.query_map(
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \
FROM msgs WHERE chat_id=c.id \
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.archived=1 GROUP BY c.id \
ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![],
process_row,
process_rows,
)
} else if query__.is_null() {
// show normal chatlist
if 0 == listflags & 0x2 {
let last_deaddrop_fresh_msg_id = get_last_deaddrop_fresh_msg((*chatlist).context);
if last_deaddrop_fresh_msg_id > 0 {
dc_array_add_id((*chatlist).chatNlastmsg_ids, 1);
dc_array_add_id((*chatlist).chatNlastmsg_ids, last_deaddrop_fresh_msg_id);
}
add_archived_link_item = 1;
}
(*chatlist).context.sql.query_map(
"SELECT c.id, m.id FROM chats c \
LEFT JOIN msgs m \
ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \
FROM msgs WHERE chat_id=c.id \
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.archived=0 \
GROUP BY c.id \
ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![],
process_row,
process_rows,
)
} else {
let query = to_string(query__).trim().to_string();
if query.is_empty() {
return 1;
} else {
let strLikeCmd = format!("%{}%", query);
(*chatlist).context.sql.query_map(
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \
FROM msgs WHERE chat_id=c.id \
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.archived=1 GROUP BY c.id \
ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![],
process_fn,
|res| {
res.collect::<rusqlite::Result<Vec<_>>>()
.map_err(Into::into)
},
AND c.blocked=0 AND c.name LIKE ? \
GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![strLikeCmd],
process_row,
process_rows,
)
} else if query__.is_null() {
if 0 == listflags & 0x2 {
let last_deaddrop_fresh_msg_id = get_last_deaddrop_fresh_msg((*chatlist).context);
if last_deaddrop_fresh_msg_id > 0 {
dc_array_add_id((*chatlist).chatNlastmsg_ids, 1);
dc_array_add_id((*chatlist).chatNlastmsg_ids, last_deaddrop_fresh_msg_id);
}
add_archived_link_item = 1;
}
(*chatlist).context.sql.query_map(
"SELECT c.id, m.id FROM chats c \
LEFT JOIN msgs m \
ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \
FROM msgs WHERE chat_id=c.id \
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.archived=0 \
GROUP BY c.id \
ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![],
process_fn,
|res| {
res.collect::<rusqlite::Result<Vec<_>>>()
.map_err(Into::into)
},
)
} else {
let query = to_string(query__).trim().to_string();
if query.is_empty() {
return 1;
} else {
let strLikeCmd = format!("%{}%", query);
(*chatlist).context.sql.query_map(
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \
FROM msgs WHERE chat_id=c.id \
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.name LIKE ? \
GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![strLikeCmd],
process_fn,
|res| {
res.collect::<rusqlite::Result<Vec<_>>>()
.map_err(Into::into)
},
)
}
};
}
};
if 0 != add_archived_link_item && dc_get_archived_cnt((*chatlist).context) > 0 {
if dc_array_get_cnt((*chatlist).chatNlastmsg_ids) == 0 && 0 != listflags & 0x4 {
@@ -236,9 +234,18 @@ unsafe fn dc_chatlist_load_from_db(
dc_array_add_id((*chatlist).chatNlastmsg_ids, 6 as uint32_t);
dc_array_add_id((*chatlist).chatNlastmsg_ids, 0 as uint32_t);
}
(*chatlist).cnt = dc_array_get_cnt((*chatlist).chatNlastmsg_ids).wrapping_div(2);
(*chatlist).cnt = dc_array_get_cnt((*chatlist).chatNlastmsg_ids) / 2;
success.is_ok() as libc::c_int
match success {
Ok(_) => 1,
Err(err) => {
error!(
(*chatlist).context,
0, "chatlist: failed to load from database: {:?}", err
);
0
}
}
}
// Context functions to work with chatlist

View File

@@ -1361,9 +1361,12 @@ unsafe fn create_or_lookup_adhoc_group(
if dc_array_get_cnt(chat_ids) > 0 {
chat_ids_str = dc_array_get_string(chat_ids, b",\x00" as *const u8 as *const _);
let res = context.sql.query_row(
"SELECT c.id, c.blocked FROM chats c \
LEFT JOIN msgs m ON m.chat_id=c.id WHERE c.id IN(?) ORDER BY m.timestamp DESC, m.id DESC LIMIT 1;",
params![as_str(chat_ids_str)],
format!(
"SELECT c.id, c.blocked FROM chats c \
LEFT JOIN msgs m ON m.chat_id=c.id WHERE c.id IN({}) ORDER BY m.timestamp DESC, m.id DESC LIMIT 1;",
as_str(chat_ids_str),
),
params![],
|row| {
Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?))
}
@@ -1477,8 +1480,11 @@ unsafe fn create_adhoc_grp_id(context: &Context, member_ids: *mut dc_array_t) ->
let members = context
.sql
.query_map(
"SELECT addr FROM contacts WHERE id IN(?) AND id!=1",
params![as_str(member_ids_str)],
format!(
"SELECT addr FROM contacts WHERE id IN({}) AND id!=1",
as_str(member_ids_str)
),
params![],
|row| row.get::<_, String>(0),
|rows| {
let mut addrs = rows.collect::<Result<Vec<_>, _>>()?;
@@ -1535,8 +1541,11 @@ unsafe fn search_chat_ids_by_contact_ids(
dc_array_get_string(contact_ids, b",\x00" as *const u8 as *const libc::c_char);
context.sql.query_map(
"SELECT DISTINCT cc.chat_id, cc.contact_id FROM chats_contacts cc LEFT JOIN chats c ON c.id=cc.chat_id WHERE cc.chat_id IN(SELECT chat_id FROM chats_contacts WHERE contact_id IN(?)) AND c.type=120 AND cc.contact_id!=1 ORDER BY cc.chat_id, cc.contact_id;",
params![as_str(contact_ids_str)],
format!(
"SELECT DISTINCT cc.chat_id, cc.contact_id FROM chats_contacts cc LEFT JOIN chats c ON c.id=cc.chat_id WHERE cc.chat_id IN(SELECT chat_id FROM chats_contacts WHERE contact_id IN({})) AND c.type=120 AND cc.contact_id!=1 ORDER BY cc.chat_id, cc.contact_id;",
as_str(contact_ids_str)
),
params![],
|row| Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?)),
|rows| {
let mut last_chat_id = 0;
@@ -1634,9 +1643,12 @@ unsafe fn check_verified_properties(
let ok = context
.sql
.query_map(
"SELECT c.addr, LENGTH(ps.verified_key_fingerprint) FROM contacts c \
LEFT JOIN acpeerstates ps ON c.addr=ps.addr WHERE c.id IN(?) ",
params![&to_ids_str],
format!(
"SELECT c.addr, LENGTH(ps.verified_key_fingerprint) FROM contacts c \
LEFT JOIN acpeerstates ps ON c.addr=ps.addr WHERE c.id IN({}) ",
&to_ids_str,
),
params![],
|row| Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1)?)),
|rows| {
for row in rows {

View File

@@ -98,7 +98,13 @@ impl Sql {
/// 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
/// result of that function.
pub fn query_map<T, P, F, G, H>(&self, sql: &str, params: P, f: F, mut g: G) -> Result<H>
pub fn query_map<T, P, F, G, H>(
&self,
sql: impl AsRef<str>,
params: P,
f: F,
mut g: G,
) -> Result<H>
where
P: IntoIterator,
P::Item: rusqlite::ToSql,
@@ -106,7 +112,8 @@ impl Sql {
G: FnMut(rusqlite::MappedRows<F>) -> Result<H>,
{
self.with_conn(|conn| {
let mut stmt = conn.prepare(sql)?;
eprintln!("query_map {}", sql.as_ref());
let mut stmt = conn.prepare(sql.as_ref())?;
let res = stmt.query_map(params, f)?;
g(res)
})
@@ -126,13 +133,13 @@ impl Sql {
})
}
pub fn query_row<T, P, F>(&self, sql: &str, params: P, f: F) -> Result<T>
pub fn query_row<T, P, F>(&self, sql: impl AsRef<str>, params: P, f: F) -> Result<T>
where
P: IntoIterator,
P::Item: rusqlite::ToSql,
F: FnOnce(&rusqlite::Row) -> rusqlite::Result<T>,
{
self.with_conn(|conn| conn.query_row(sql, params, f).map_err(Into::into))
self.with_conn(|conn| conn.query_row(sql.as_ref(), params, f).map_err(Into::into))
}
pub fn table_exists(&self, name: impl AsRef<str>) -> bool {
@@ -210,12 +217,12 @@ fn open(
sql.execute(
"CREATE TABLE contacts (\
id INTEGER PRIMARY KEY AUTOINCREMENT, \
name TEXT DEFAULT \'\', \
addr TEXT DEFAULT \'\' COLLATE NOCASE, \
name TEXT DEFAULT '', \
addr TEXT DEFAULT '' COLLATE NOCASE, \
origin INTEGER DEFAULT 0, \
blocked INTEGER DEFAULT 0, \
last_seen INTEGER DEFAULT 0, \
param TEXT DEFAULT \'\');",
param TEXT DEFAULT '');",
params![],
)?;
sql.execute(
@@ -228,21 +235,21 @@ fn open(
)?;
sql.execute(
"INSERT INTO contacts (id,name,origin) VALUES \
(1,\'self\',262144), (2,\'device\',262144), (3,\'rsvd\',262144), \
(4,\'rsvd\',262144), (5,\'rsvd\',262144), (6,\'rsvd\',262144), \
(7,\'rsvd\',262144), (8,\'rsvd\',262144), (9,\'rsvd\',262144);",
(1,'self',262144), (2,'device',262144), (3,'rsvd',262144), \
(4,'rsvd',262144), (5,'rsvd',262144), (6,'rsvd',262144), \
(7,'rsvd',262144), (8,'rsvd',262144), (9,'rsvd',262144);",
params![],
)?;
sql.execute(
"CREATE TABLE chats (\
id INTEGER PRIMARY KEY AUTOINCREMENT, \
type INTEGER DEFAULT 0, \
name TEXT DEFAULT \'\', \
name TEXT DEFAULT '', \
draft_timestamp INTEGER DEFAULT 0, \
draft_txt TEXT DEFAULT \'\', \
draft_txt TEXT DEFAULT '', \
blocked INTEGER DEFAULT 0, \
grpid TEXT DEFAULT \'\', \
param TEXT DEFAULT \'\');",
grpid TEXT DEFAULT '', \
param TEXT DEFAULT '');",
params![],
)?;
sql.execute("CREATE INDEX chats_index1 ON chats (grpid);", params![])?;
@@ -256,16 +263,16 @@ fn open(
)?;
sql.execute(
"INSERT INTO chats (id,type,name) VALUES \
(1,120,\'deaddrop\'), (2,120,\'rsvd\'), (3,120,\'trash\'), \
(4,120,\'msgs_in_creation\'), (5,120,\'starred\'), (6,120,\'archivedlink\'), \
(7,100,\'rsvd\'), (8,100,\'rsvd\'), (9,100,\'rsvd\');",
(1,120,'deaddrop'), (2,120,'rsvd'), (3,120,'trash'), \
(4,120,'msgs_in_creation'), (5,120,'starred'), (6,120,'archivedlink'), \
(7,100,'rsvd'), (8,100,'rsvd'), (9,100,'rsvd');",
params![],
)?;
sql.execute(
"CREATE TABLE msgs (\
id INTEGER PRIMARY KEY AUTOINCREMENT, \
rfc724_mid TEXT DEFAULT \'\', \
server_folder TEXT DEFAULT \'\', \
rfc724_mid TEXT DEFAULT '', \
server_folder TEXT DEFAULT '', \
server_uid INTEGER DEFAULT 0, \
chat_id INTEGER DEFAULT 0, \
from_id INTEGER DEFAULT 0, \
@@ -275,9 +282,9 @@ fn open(
state INTEGER DEFAULT 0, \
msgrmsg INTEGER DEFAULT 1, \
bytes INTEGER DEFAULT 0, \
txt TEXT DEFAULT \'\', \
txt_raw TEXT DEFAULT \'\', \
param TEXT DEFAULT \'\');",
txt TEXT DEFAULT '', \
txt_raw TEXT DEFAULT '', \
param TEXT DEFAULT '');",
params![],
)?;
sql.execute("CREATE INDEX msgs_index1 ON msgs (rfc724_mid);", params![])?;
@@ -286,9 +293,9 @@ fn open(
sql.execute("CREATE INDEX msgs_index4 ON msgs (state);", params![])?;
sql.execute(
"INSERT INTO msgs (id,msgrmsg,txt) VALUES \
(1,0,\'marker1\'), (2,0,\'rsvd\'), (3,0,\'rsvd\'), \
(4,0,\'rsvd\'), (5,0,\'rsvd\'), (6,0,\'rsvd\'), (7,0,\'rsvd\'), \
(8,0,\'rsvd\'), (9,0,\'daymarker\');",
(1,0,'marker1'), (2,0,'rsvd'), (3,0,'rsvd'), \
(4,0,'rsvd'), (5,0,'rsvd'), (6,0,'rsvd'), (7,0,'rsvd'), \
(8,0,'rsvd'), (9,0,'daymarker');",
params![],
)?;
sql.execute(
@@ -298,7 +305,7 @@ fn open(
desired_timestamp INTEGER DEFAULT 0, \
action INTEGER, \
foreign_id INTEGER, \
param TEXT DEFAULT \'\');",
param TEXT DEFAULT '');",
params![],
)?;
sql.execute(
@@ -338,7 +345,7 @@ fn open(
if dbversion < 1 {
sql.execute(
"CREATE TABLE leftgrps ( id INTEGER PRIMARY KEY, grpid TEXT DEFAULT \'\');",
"CREATE TABLE leftgrps ( id INTEGER PRIMARY KEY, grpid TEXT DEFAULT '');",
params![],
)?;
sql.execute(
@@ -350,7 +357,7 @@ fn open(
}
if dbversion < 2 {
sql.execute(
"ALTER TABLE contacts ADD COLUMN authname TEXT DEFAULT \'\';",
"ALTER TABLE contacts ADD COLUMN authname TEXT DEFAULT '';",
params![],
)?;
dbversion = 2;
@@ -360,7 +367,7 @@ fn open(
sql.execute(
"CREATE TABLE keypairs (\
id INTEGER PRIMARY KEY, \
addr TEXT DEFAULT \'\' COLLATE NOCASE, \
addr TEXT DEFAULT '' COLLATE NOCASE, \
is_default INTEGER DEFAULT 0, \
private_key, \
public_key, \
@@ -374,7 +381,7 @@ fn open(
sql.execute(
"CREATE TABLE acpeerstates (\
id INTEGER PRIMARY KEY, \
addr TEXT DEFAULT \'\' COLLATE NOCASE, \
addr TEXT DEFAULT '' COLLATE NOCASE, \
last_seen INTEGER DEFAULT 0, \
last_seen_autocrypt INTEGER DEFAULT 0, \
public_key, \
@@ -450,11 +457,11 @@ fn open(
params![],
)?;
sql.execute(
"ALTER TABLE acpeerstates ADD COLUMN public_key_fingerprint TEXT DEFAULT \'\';",
"ALTER TABLE acpeerstates ADD COLUMN public_key_fingerprint TEXT DEFAULT '';",
params![],
)?;
sql.execute(
"ALTER TABLE acpeerstates ADD COLUMN gossip_key_fingerprint TEXT DEFAULT \'\';",
"ALTER TABLE acpeerstates ADD COLUMN gossip_key_fingerprint TEXT DEFAULT '';",
params![],
)?;
sql.execute(
@@ -471,7 +478,7 @@ fn open(
}
if dbversion < 39 {
sql.execute(
"CREATE TABLE tokens ( id INTEGER PRIMARY KEY, namespc INTEGER DEFAULT 0, foreign_id INTEGER DEFAULT 0, token TEXT DEFAULT \'\', timestamp INTEGER DEFAULT 0);",
"CREATE TABLE tokens ( id INTEGER PRIMARY KEY, namespc INTEGER DEFAULT 0, foreign_id INTEGER DEFAULT 0, token TEXT DEFAULT '', timestamp INTEGER DEFAULT 0);",
params![]
)?;
sql.execute(
@@ -479,7 +486,7 @@ fn open(
params![],
)?;
sql.execute(
"ALTER TABLE acpeerstates ADD COLUMN verified_key_fingerprint TEXT DEFAULT \'\';",
"ALTER TABLE acpeerstates ADD COLUMN verified_key_fingerprint TEXT DEFAULT '';",
params![],
)?;
sql.execute(
@@ -513,7 +520,7 @@ fn open(
set_config_int(context, sql, "dbversion", 41);
}
if dbversion < 42 {
sql.execute("UPDATE msgs SET txt=\'\' WHERE type!=10", params![])?;
sql.execute("UPDATE msgs SET txt='' WHERE type!=10", params![])?;
dbversion = 42;
set_config_int(context, sql, "dbversion", 42);
}
@@ -661,7 +668,7 @@ fn open(
let repl_from = dc_ensure_no_slash_safe(&repl_from);
sql.execute(
&format!(
"UPDATE msgs SET param=replace(param, \'f={}/\', \'f=$BLOBDIR/\')",
"UPDATE msgs SET param=replace(param, 'f={}/', 'f=$BLOBDIR/')",
repl_from
),
NO_PARAMS,
@@ -669,7 +676,7 @@ fn open(
sql.execute(
&format!(
"UPDATE chats SET param=replace(param, \'i={}/\', \'i=$BLOBDIR/\');",
"UPDATE chats SET param=replace(param, 'i={}/', 'i=$BLOBDIR/');",
repl_from
),
NO_PARAMS,
@@ -762,7 +769,13 @@ where
match sql.execute(querystr.as_ref(), params) {
Ok(_) => true,
Err(err) => {
error!(context, 0, "execute failed: {:?}", err);
error!(
context,
0,
"execute failed: {:?} for {}",
err,
querystr.as_ref()
);
false
}
}