///|
/// Deprecated APIs kept for the 0.6.x -> 0.7.0 migration.
///|
/// Extract the diagnostic text of an error, as matching on the removed
/// `DuckDBError::Message(String)` variant used to.
///
/// Prefer matching on the structured `DuckDBError` variants for categories
/// and calling `DuckDBError::message` for the text.
#deprecated("DuckDBError::Message was replaced by structured variants in 0.7.0; use err.message() for the diagnostic text or match on the Query/Prepare/Bind/Append/Unsupported/Closed/InvalidArgument/Backend/DuckDB variants")
pub fn DuckDBError::to_message(self : DuckDBError) -> String {
self.message()
}
///|
/// Construct an error from a plain diagnostic message, as constructing
/// `DuckDBError::Message(message)` used to.
///
/// Prefer constructing the structured variant that fits the failure (for
/// example `DuckDBError::Query`, `DuckDBError::Unsupported`, or
/// `DuckDBError::Backend`).
#deprecated("DuckDBError::Message was replaced by structured variants in 0.7.0; construct the matching variant (Query/Prepare/Bind/Append/Unsupported/Closed/InvalidArgument/Backend/DuckDB) instead")
pub fn duckdb_message_error(message : String) -> DuckDBError {
DuckDBError::Backend(backend="generic", message~)
}
// ============================================================================
// Quack convenience methods (moved to the f4ah6o/duckdb/quack package)
//
// These `Connection` methods are deprecated forwarding facades kept for the
// transition period. New code should import `f4ah6o/duckdb/quack`
// (`quack::install(conn, ...)`, `quack::query(conn, ...)`, ...) or compose
// the generic `Connection::install_extension` / `load_extension` / `attach`
// primitives.
// ============================================================================
///|
fn quack_sql_string(value : String) -> String {
sql_string_literal(value)
}
///|
fn quack_is_identifier_char(c : Char) -> Bool {
is_sql_identifier_char(c)
}
///|
fn quack_identifier(value : String) -> Result[String, DuckDBError] {
if value.length() == 0 {
Err(
DuckDBError::InvalidArgument(
argument="alias",
reason="Quack alias must not be empty",
),
)
} else {
for c in value {
if !quack_is_identifier_char(c) {
return Err(
DuckDBError::InvalidArgument(
argument="alias",
reason="Quack alias may only contain letters, digits, and underscores",
),
)
}
}
Ok("\"" + value + "\"")
}
}
///|
/// The parenthesized ATTACH option clause for a Quack catalog:
/// `TYPE quack[, TOKEN 'x'][, DISABLE_SSL true]`.
fn quack_attach_options(token : String, disable_ssl : Bool) -> String {
let sb = StringBuilder()
ignore(sb.write_view("TYPE quack"))
if token != "" {
ignore(sb..write_view(", TOKEN ").write_view(quack_sql_string(token)))
}
if disable_ssl {
ignore(sb.write_view(", DISABLE_SSL true"))
}
sb.to_string()
}
///|
fn quack_query_sql(
uri : String,
sql : String,
token : String,
disable_ssl : Bool,
) -> String {
let sb = StringBuilder()
ignore(
sb
..write_view("FROM quack_query(")
..write_view(quack_sql_string(uri))
..write_view(", ")
.write_view(quack_sql_string(sql)),
)
if token != "" {
ignore(sb..write_view(", token => ").write_view(quack_sql_string(token)))
}
if disable_ssl {
ignore(sb.write_view(", disable_ssl => true"))
}
ignore(sb.write_char(')'))
sb.to_string()
}
///|
fn quack_secret_sql(token : String, scope : String) -> String {
let sb = StringBuilder()
ignore(
sb
..write_view("CREATE SECRET (TYPE quack, TOKEN ")
.write_view(quack_sql_string(token)),
)
if scope != "" {
ignore(sb..write_view(", SCOPE ").write_view(quack_sql_string(scope)))
}
ignore(sb.write_char(')'))
sb.to_string()
}
///|
fn quack_serve_sql(
uri : String,
token : String,
allow_other_hostname : Bool,
) -> String {
let sb = StringBuilder()
ignore(sb..write_view("CALL quack_serve(").write_view(quack_sql_string(uri)))
if token != "" {
ignore(sb..write_view(", token => ").write_view(quack_sql_string(token)))
}
if allow_other_hostname {
ignore(sb.write_view(", allow_other_hostname => true"))
}
ignore(sb.write_char(')'))
sb.to_string()
}
///|
fn quack_stop_sql(uri : String) -> String {
let sb = StringBuilder()
ignore(sb..write_view("CALL quack_stop(").write_view(quack_sql_string(uri)))
ignore(sb.write_char(')'))
sb.to_string()
}
///|
fn quack_unit_done(
result : Result[QueryResult, DuckDBError],
on_done : (Result[Unit, DuckDBError]) -> Unit,
) -> Unit {
unit_done(result, on_done)
}
///|
/// Install the experimental Quack extension from DuckDB's `core_nightly` repository.
///
/// Migration: use `quack::install(conn, on_done=...)` from the
/// `f4ah6o/duckdb/quack` package, or the generic
/// `conn.install_extension("quack", repository="core_nightly", force=true)`.
#deprecated("moved to the f4ah6o/duckdb/quack package (quack::install); or use Connection::install_extension(\"quack\", repository=\"core_nightly\", force=true)")
pub fn Connection::install_quack(
self : Connection,
on_done~ : (Result[Unit, DuckDBError]) -> Unit,
) -> Unit {
self.install_extension(
"quack",
repository="core_nightly",
force=true,
on_done~,
)
}
///|
/// Load the Quack extension in the current DuckDB connection.
///
/// Migration: use `quack::load(conn, on_done=...)` from the
/// `f4ah6o/duckdb/quack` package, or `conn.load_extension("quack")`.
#deprecated("moved to the f4ah6o/duckdb/quack package (quack::load); or use Connection::load_extension(\"quack\")")
pub fn Connection::load_quack(
self : Connection,
on_done~ : (Result[Unit, DuckDBError]) -> Unit,
) -> Unit {
self.load_extension("quack", on_done~)
}
///|
/// Start a Quack server for this connection.
///
/// Migration: use `quack::serve(conn, uri, ...)` from the
/// `f4ah6o/duckdb/quack` package.
#deprecated("moved to the f4ah6o/duckdb/quack package (quack::serve)")
pub fn Connection::start_quack_server(
self : Connection,
uri : String,
token? : String = "",
allow_other_hostname? : Bool = false,
on_done~ : (Result[QueryResult, DuckDBError]) -> Unit,
) -> Unit {
self.query(quack_serve_sql(uri, token, allow_other_hostname), on_done~)
}
///|
/// Stop a Quack server started for this connection.
///
/// Migration: use `quack::stop(conn, uri, ...)` from the
/// `f4ah6o/duckdb/quack` package.
#deprecated("moved to the f4ah6o/duckdb/quack package (quack::stop)")
pub fn Connection::stop_quack_server(
self : Connection,
uri : String,
on_done~ : (Result[Unit, DuckDBError]) -> Unit,
) -> Unit {
self.query(quack_stop_sql(uri), on_done=fn(result) {
quack_unit_done(result, on_done)
})
}
///|
/// Run a stateless query against a Quack endpoint.
///
/// Migration: use `quack::query(conn, uri, sql, ...)` from the
/// `f4ah6o/duckdb/quack` package.
#deprecated("moved to the f4ah6o/duckdb/quack package (quack::query)")
pub fn Connection::quack_query(
self : Connection,
uri : String,
sql : String,
token? : String = "",
disable_ssl? : Bool = false,
on_done~ : (Result[QueryResult, DuckDBError]) -> Unit,
) -> Unit {
self.query(quack_query_sql(uri, sql, token, disable_ssl), on_done~)
}
///|
/// Create a scoped or unscoped Quack secret for client authentication.
///
/// Migration: use `quack::create_secret(conn, token, ...)` from the
/// `f4ah6o/duckdb/quack` package.
#deprecated("moved to the f4ah6o/duckdb/quack package (quack::create_secret)")
pub fn Connection::create_quack_secret(
self : Connection,
token : String,
scope? : String = "",
on_done~ : (Result[Unit, DuckDBError]) -> Unit,
) -> Unit {
self.query(quack_secret_sql(token, scope), on_done=fn(result) {
quack_unit_done(result, on_done)
})
}
///|
/// Attach a Quack endpoint as a remote DuckDB catalog.
///
/// Migration: use `quack::attach(conn, uri, alias, ...)` from the
/// `f4ah6o/duckdb/quack` package, or the generic `conn.attach` primitive.
#deprecated("moved to the f4ah6o/duckdb/quack package (quack::attach); or use Connection::attach with a 'TYPE quack' options clause")
pub fn Connection::attach_quack(
self : Connection,
uri : String,
db_alias : String,
token? : String = "",
disable_ssl? : Bool = false,
on_done~ : (Result[Unit, DuckDBError]) -> Unit,
) -> Unit {
match quack_identifier(db_alias) {
Ok(_) =>
self.attach(
uri,
db_alias~,
options=quack_attach_options(token, disable_ssl),
on_done~,
)
Err(err) => on_done(Err(err))
}
}
// ============================================================================
// Arrow per-column accessors (reworked in #62)
//
// `query_arrow` now materializes results into canonical `VectorChunk`s.
// These legacy getters keep working as forwarders that flatten the typed
// vectors into row-aligned arrays (NULL rows yield the type's zero value;
// the `*_nullable` variants also return the validity mask). Prefer
// `ArrowResult::to_chunks` plus the `Vector` accessors for new code.
// ============================================================================
///|
/// Materialized chunks of an open arrow result; `[]` once closed.
fn arrow_open_chunks(result : ArrowResult) -> Array[VectorChunk] {
match result.to_chunks() {
Ok(chunks) => chunks
Err(_) => []
}
}
///|
/// Row `row` of `vector` coerced to `Int` (0 for NULL/unconvertible rows).
fn arrow_row_int(vector : Vector, row : Int) -> Int {
match vector.value_at(row) {
Value::Int(n) => n
Value::Int64(n) => n.to_int()
Value::UInt64(n) => n.to_int()
Value::Double(d) => d.to_int()
Value::Bool(b) => if b { 1 } else { 0 }
_ => 0
}
}
///|
/// Row `row` of `vector` coerced to `Int64` (0 for NULL/unconvertible rows).
fn arrow_row_int64(vector : Vector, row : Int) -> Int64 {
match vector.value_at(row) {
Value::Int(n) => n.to_int64()
Value::Int64(n) => n
Value::UInt64(n) => n.to_int64()
Value::Double(d) => d.to_int64()
Value::Bool(b) => if b { 1L } else { 0L }
_ => 0L
}
}
///|
/// Row `row` of `vector` coerced to `Double` (0.0 for NULL/unconvertible).
fn arrow_row_double(vector : Vector, row : Int) -> Double {
match vector.value_at(row) {
Value::Double(d) => d
Value::Int(n) => n.to_double()
Value::Int64(n) => n.to_double()
Value::UInt64(n) => n.to_double()
Value::Bool(b) => if b { 1.0 } else { 0.0 }
_ => 0.0
}
}
///|
/// Row `row` of `vector` coerced to `Bool` (false for NULL/unconvertible).
fn arrow_row_bool(vector : Vector, row : Int) -> Bool {
match vector.value_at(row) {
Value::Bool(b) => b
Value::Int(n) => n != 0
Value::Int64(n) => n != 0L
_ => false
}
}
///|
/// Row `row` of `vector` rendered to `String` ("" for NULL rows), matching
/// the legacy `duckdb_value_varchar` coercion semantics.
fn arrow_row_string(vector : Vector, row : Int) -> String {
if !vector.validity[row] {
""
} else {
vector.string_at(row)
}
}
///|
/// Column `col` flattened to `Int` values across all chunks (NULL rows
/// yield 0).
#deprecated("arrow getters now read canonical typed vectors; use ArrowResult::to_chunks with Vector::ints/value_at for new code")
pub fn ArrowResult::get_column_int32(
self : ArrowResult,
col : Int,
) -> Array[Int] {
let values : Array[Int] = []
for chunk in arrow_open_chunks(self) {
match chunk.column(col) {
Some(vector) =>
for row = 0; row < vector.len(); row = row + 1 {
values.push(arrow_row_int(vector, row))
} nobreak {
()
}
None => ()
}
} nobreak {
()
}
values
}
///|
/// Column `col` flattened to `Int64` values across all chunks (NULL rows
/// yield 0). Note: this getter previously returned `Array[Int]`, which
/// truncated BIGINT to 32 bits; it now keeps full Int64 precision.
#deprecated("arrow getters now read canonical typed vectors; use ArrowResult::to_chunks with Vector::int64s/value_at for new code")
pub fn ArrowResult::get_column_int64(
self : ArrowResult,
col : Int,
) -> Array[Int64] {
let values : Array[Int64] = []
for chunk in arrow_open_chunks(self) {
match chunk.column(col) {
Some(vector) =>
for row = 0; row < vector.len(); row = row + 1 {
values.push(arrow_row_int64(vector, row))
} nobreak {
()
}
None => ()
}
} nobreak {
()
}
values
}
///|
/// Column `col` flattened to `Double` values across all chunks (NULL rows
/// yield 0.0).
#deprecated("arrow getters now read canonical typed vectors; use ArrowResult::to_chunks with Vector::doubles/value_at for new code")
pub fn ArrowResult::get_column_double(
self : ArrowResult,
col : Int,
) -> Array[Double] {
let values : Array[Double] = []
for chunk in arrow_open_chunks(self) {
match chunk.column(col) {
Some(vector) =>
for row = 0; row < vector.len(); row = row + 1 {
values.push(arrow_row_double(vector, row))
} nobreak {
()
}
None => ()
}
} nobreak {
()
}
values
}
///|
/// Column `col` flattened to `Bool` values across all chunks (NULL rows
/// yield false).
#deprecated("arrow getters now read canonical typed vectors; use ArrowResult::to_chunks with Vector::bools/value_at for new code")
pub fn ArrowResult::get_column_bool(
self : ArrowResult,
col : Int,
) -> Array[Bool] {
let values : Array[Bool] = []
for chunk in arrow_open_chunks(self) {
match chunk.column(col) {
Some(vector) =>
for row = 0; row < vector.len(); row = row + 1 {
values.push(arrow_row_bool(vector, row))
} nobreak {
()
}
None => ()
}
} nobreak {
()
}
values
}
///|
/// Column `col` flattened to rendered strings across all chunks (NULL rows
/// yield "").
#deprecated("arrow getters now read canonical typed vectors; use ArrowResult::to_chunks with Vector::strings/string_at for new code")
pub fn ArrowResult::get_column_string(
self : ArrowResult,
col : Int,
) -> Array[String] {
let values : Array[String] = []
for chunk in arrow_open_chunks(self) {
match chunk.column(col) {
Some(vector) =>
for row = 0; row < vector.len(); row = row + 1 {
values.push(arrow_row_string(vector, row))
} nobreak {
()
}
None => ()
}
} nobreak {
()
}
values
}
///|
/// Column `col` flattened to `(values, validity)` across all chunks.
#deprecated("arrow getters now read canonical typed vectors; use ArrowResult::to_chunks with Vector::ints and Vector::is_null for new code")
pub fn ArrowResult::get_column_int32_nullable(
self : ArrowResult,
col : Int,
) -> (Array[Int], Array[Bool]) {
let values : Array[Int] = []
let validity : Array[Bool] = []
for chunk in arrow_open_chunks(self) {
match chunk.column(col) {
Some(vector) =>
for row = 0; row < vector.len(); row = row + 1 {
values.push(arrow_row_int(vector, row))
validity.push(vector.validity[row])
} nobreak {
()
}
None => ()
}
} nobreak {
()
}
(values, validity)
}
///|
/// Column `col` flattened to `(values, validity)` across all chunks.
/// See `get_column_int64` for the Int -> Int64 precision fix.
#deprecated("arrow getters now read canonical typed vectors; use ArrowResult::to_chunks with Vector::int64s and Vector::is_null for new code")
pub fn ArrowResult::get_column_int64_nullable(
self : ArrowResult,
col : Int,
) -> (Array[Int64], Array[Bool]) {
let values : Array[Int64] = []
let validity : Array[Bool] = []
for chunk in arrow_open_chunks(self) {
match chunk.column(col) {
Some(vector) =>
for row = 0; row < vector.len(); row = row + 1 {
values.push(arrow_row_int64(vector, row))
validity.push(vector.validity[row])
} nobreak {
()
}
None => ()
}
} nobreak {
()
}
(values, validity)
}
///|
/// Column `col` flattened to `(values, validity)` across all chunks.
#deprecated("arrow getters now read canonical typed vectors; use ArrowResult::to_chunks with Vector::doubles and Vector::is_null for new code")
pub fn ArrowResult::get_column_double_nullable(
self : ArrowResult,
col : Int,
) -> (Array[Double], Array[Bool]) {
let values : Array[Double] = []
let validity : Array[Bool] = []
for chunk in arrow_open_chunks(self) {
match chunk.column(col) {
Some(vector) =>
for row = 0; row < vector.len(); row = row + 1 {
values.push(arrow_row_double(vector, row))
validity.push(vector.validity[row])
} nobreak {
()
}
None => ()
}
} nobreak {
()
}
(values, validity)
}
///|
/// Column `col` flattened to `(values, validity)` across all chunks.
#deprecated("arrow getters now read canonical typed vectors; use ArrowResult::to_chunks with Vector::strings and Vector::is_null for new code")
pub fn ArrowResult::get_column_string_nullable(
self : ArrowResult,
col : Int,
) -> (Array[String], Array[Bool]) {
let values : Array[String] = []
let validity : Array[Bool] = []
for chunk in arrow_open_chunks(self) {
match chunk.column(col) {
Some(vector) =>
for row = 0; row < vector.len(); row = row + 1 {
values.push(arrow_row_string(vector, row))
validity.push(vector.validity[row])
} nobreak {
()
}
None => ()
}
} nobreak {
()
}
(values, validity)
}
///|
/// Column `col` flattened to `(values, validity)` across all chunks.
#deprecated("arrow getters now read canonical typed vectors; use ArrowResult::to_chunks with Vector::bools and Vector::is_null for new code")
pub fn ArrowResult::get_column_bool_nullable(
self : ArrowResult,
col : Int,
) -> (Array[Bool], Array[Bool]) {
let values : Array[Bool] = []
let validity : Array[Bool] = []
for chunk in arrow_open_chunks(self) {
match chunk.column(col) {
Some(vector) =>
for row = 0; row < vector.len(); row = row + 1 {
values.push(arrow_row_bool(vector, row))
validity.push(vector.validity[row])
} nobreak {
()
}
None => ()
}
} nobreak {
()
}
(values, validity)
}