Skip to content
This repository has been archived by the owner on Oct 18, 2023. It is now read-only.

Commit

Permalink
sqld: Add extended_code support
Browse files Browse the repository at this point in the history
  • Loading branch information
LucioFranco committed Oct 13, 2023
1 parent dc1b59d commit 24addb5
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 18 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sqld-libsql-bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl<W: WalHook> Connection<W> {
///
/// # Safety
/// The caller is responsible for the returned pointer.
pub unsafe fn handle(&mut self) -> *mut sqlite3 {
pub unsafe fn handle(&self) -> *mut sqlite3 {
self.conn.handle()
}
}
2 changes: 1 addition & 1 deletion sqld/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ hyper-rustls = { git = "https://github.com/rustls/hyper-rustls.git", rev = "163b
rustls-pemfile = "1.0.3"
rustls = "0.21.7"
async-stream = "0.3.5"
libsql = { git = "https://github.com/tursodatabase/libsql.git", rev = "6f5d54374d91f78510870a653af46f385dd67fac", optional = true }
libsql = { git = "https://github.com/tursodatabase/libsql", rev = "8847ca05c", optional = true }
metrics = "0.21.1"
metrics-exporter-prometheus = "0.12.1"

Expand Down
1 change: 1 addition & 0 deletions sqld/proto/proxy.proto
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ message Error {

ErrorCode code = 1;
string message = 2;
int32 extended_code = 3;
}

message ResultRows {
Expand Down
12 changes: 10 additions & 2 deletions sqld/src/connection/libsql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ impl<W: WalHook> Connection<W> {
current_frame_no_receiver: watch::Receiver<Option<FrameNo>>,
state: Arc<TxnState<W>>,
) -> Result<Self> {
let mut conn = open_conn(
let conn = open_conn(
path,
wal_methods,
hook_ctx,
Expand Down Expand Up @@ -519,7 +519,14 @@ impl<W: WalHook> Connection<W> {
match self.execute_query(&step.query, builder) {
// builder error interupt the execution of query. we should exit immediately.
Err(e @ Error::BuilderError(_)) => return Err(e),
Err(e) => {
Err(mut e) => {
if let Error::RusqliteError(err) = e {
let extended_code =
unsafe { rusqlite::ffi::sqlite3_extended_errcode(self.conn.handle()) };

e = Error::RusqliteErrorExtended(err, extended_code as i32);
};

builder.step_error(e)?;
enabled = false;
(0, None)
Expand Down Expand Up @@ -570,6 +577,7 @@ impl<W: WalHook> Connection<W> {
.map_err(Error::LibSqlInvalidQueryParams)?;

let mut qresult = stmt.raw_query();

builder.begin_rows()?;
while let Some(row) = qresult.next()? {
builder.begin_row()?;
Expand Down
3 changes: 3 additions & 0 deletions sqld/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub enum Error {
IOError(#[from] std::io::Error),
#[error(transparent)]
RusqliteError(#[from] rusqlite::Error),
#[error("{0}")]
RusqliteErrorExtended(rusqlite::Error, i32),
#[error("Failed to execute query via RPC. Error code: {}, message: {}", .0.code, .0.message)]
RpcQueryError(crate::rpc::proxy::rpc::Error),
#[error("Failed to execute queries via RPC protocol: `{0}`")]
Expand Down Expand Up @@ -106,6 +108,7 @@ impl IntoResponse for Error {
LibSqlTxBusy => self.format_err(StatusCode::TOO_MANY_REQUESTS),
IOError(_) => self.format_err(StatusCode::INTERNAL_SERVER_ERROR),
RusqliteError(_) => self.format_err(StatusCode::INTERNAL_SERVER_ERROR),
RusqliteErrorExtended(_, _) => self.format_err(StatusCode::INTERNAL_SERVER_ERROR),
RpcQueryError(_) => self.format_err(StatusCode::BAD_REQUEST),
RpcQueryExecutionError(_) => self.format_err(StatusCode::INTERNAL_SERVER_ERROR),
DbValueError(_) => self.format_err(StatusCode::BAD_REQUEST),
Expand Down
23 changes: 13 additions & 10 deletions sqld/src/rpc/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,23 @@ pub mod rpc {

impl From<SqldError> for Error {
fn from(other: SqldError) -> Self {
Error {
message: other.to_string(),
code: ErrorCode::from(other).into(),
}
}
}

impl From<SqldError> for ErrorCode {
fn from(other: SqldError) -> Self {
match other {
let code = match other {
SqldError::LibSqlInvalidQueryParams(_) => ErrorCode::SqlError,
SqldError::LibSqlTxTimeout => ErrorCode::TxTimeout,
SqldError::LibSqlTxBusy => ErrorCode::TxBusy,
_ => ErrorCode::Internal,
};

let extended_code = if let SqldError::RusqliteErrorExtended(_, code) = &other {
*code
} else {
0
};

Error {
message: other.to_string(),
code: code as i32,
extended_code,
}
}
}
Expand Down
30 changes: 28 additions & 2 deletions sqld/tests/embedded_replica/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use libsql::Database;
use serde_json::json;
use sqld::config::{AdminApiConfig, RpcServerConfig, UserApiConfig};
use turmoil::{Builder, Sim};
use uuid::Uuid;

fn make_primary(sim: &mut Sim, path: PathBuf) {
init_tracing();
Expand All @@ -21,6 +22,7 @@ fn make_primary(sim: &mut Sim, path: PathBuf) {
admin_api_config: Some(AdminApiConfig {
acceptor: TurmoilAcceptor::bind(([0, 0, 0, 0], 9090)).await?,
connector: TurmoilConnector,
disable_metrics: false,
}),
rpc_server_config: Some(RpcServerConfig {
acceptor: TurmoilAcceptor::bind(([0, 0, 0, 0], 4567)).await?,
Expand All @@ -42,7 +44,11 @@ fn make_primary(sim: &mut Sim, path: PathBuf) {
fn embedded_replica() {
let mut sim = Builder::new().build();

let tmp = std::env::temp_dir();
let tmp_dir_name = Uuid::new_v4().simple().to_string();

let tmp = std::env::temp_dir().join(tmp_dir_name);

tracing::debug!("tmp dir: {:?}", tmp);

// We need to ensure that libsql's init code runs before we do anything
// with rusqlite in sqld. This is because libsql has saftey checks and
Expand Down Expand Up @@ -71,9 +77,29 @@ fn embedded_replica() {
TurmoilConnector,
)?;

let n = db.sync().await.unwrap();
let n = db.sync().await?;
assert_eq!(n, 0);

let conn = db.connect()?;

conn.execute("CREATE TABLE user (id INTEGER NOT NULL PRIMARY KEY)", ())
.await?;

let n = db.sync().await?;
assert_eq!(n, 2);

let err = conn
.execute("INSERT INTO user(id) VALUES (1), (1)", ())
.await
.unwrap_err();

let libsql::Error::RemoteSqliteFailure(code, extended_code, _) = err else {
panic!()
};

assert_eq!(code, 3);
assert_eq!(extended_code, 1555);

Ok(())
});

Expand Down

0 comments on commit 24addb5

Please sign in to comment.