Skip to content

Commit

Permalink
Merge c38df66 into 2e50a3b
Browse files Browse the repository at this point in the history
  • Loading branch information
pacman82 committed Oct 22, 2023
2 parents 2e50a3b + c38df66 commit 736bb28
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 4 deletions.
2 changes: 1 addition & 1 deletion odbc-api/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ impl<'c> Connection<'c> {
/// ```
pub fn preallocate(&self) -> Result<Preallocated<'_>, Error> {
let stmt = self.allocate_statement()?;
Ok(Preallocated::new(stmt))
unsafe { Ok(Preallocated::new(stmt)) }
}

/// Specify the transaction mode. By default, ODBC transactions are in auto-commit mode.
Expand Down
11 changes: 10 additions & 1 deletion odbc-api/src/preallocated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,16 @@ pub struct Preallocated<'open_connection> {
}

impl<'o> Preallocated<'o> {
pub(crate) fn new(statement: StatementImpl<'o>) -> Self {

/// Users which intend to write their application in safe Rust should prefer using
/// [`crate::Connection::preallocate`] as opposed to this constructor.
///
/// # Safety
///
/// `statement` must be an allocated handled with no pointers bound for either results or
/// arguments. The statement must not be prepared, but in the state of a "freshly" allocated
/// handle.
pub unsafe fn new(statement: StatementImpl<'o>) -> Self {
Self { statement }
}

Expand Down
77 changes: 75 additions & 2 deletions odbc-api/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use odbc_api::{
},
parameter::{InputParameter, VarCharSliceMut},
sys, Bit, ColumnDescription, Connection, ConnectionOptions, Cursor, DataType, Error, InOut,
IntoParameter, Narrow, Nullability, Nullable, Out, ResultSetMetadata, U16Str, U16String,
IntoParameter, Narrow, Nullability, Nullable, Out, Preallocated, ResultSetMetadata, U16Str,
U16String,
};
use std::{
ffi::CString,
Expand Down Expand Up @@ -4096,7 +4097,8 @@ fn fetch_decimal_as_numeric_struct_using_bind_col(profile: &Profile) {
// seem to set the wrong pointer if just using bind col. Postgres and MariaDB would work as
// intended with bind_col.
// stmt.bind_col(1, &mut target);
ard.set_data_ptr(1, &mut target as *mut Numeric as Pointer).unwrap();
ard.set_data_ptr(1, &mut target as *mut Numeric as Pointer)
.unwrap();

stmt.fetch();

Expand All @@ -4116,6 +4118,77 @@ fn fetch_decimal_as_numeric_struct_using_bind_col(profile: &Profile) {
assert_eq!(0, target.val[2]);
}

/// Learning test to see how scrolling cursors behave
#[test_case(MSSQL; "Microsoft SQL Server")]
#[test_case(MARIADB; "Maria DB")]
#[test_case(SQLITE_3; "SQLite 3")]
#[test_case(POSTGRES; "PostgreSQL")]
fn scroll_cursor(profile: &Profile) {
// Given a table
let table_name = table_name!();
let (conn, table) = profile.given(&table_name, &["VARCHAR(50)"]).unwrap();
conn.execute(&table.sql_insert(), &"one".into_parameter())
.unwrap();
conn.execute(&table.sql_insert(), &"two".into_parameter())
.unwrap();
conn.execute(&table.sql_insert(), &"three".into_parameter())
.unwrap();
let query = table.sql_all_ordered_by_id();

// When
let stmt = conn.preallocate().unwrap();
let stmt = stmt.into_statement();
let stmt_ptr = stmt.as_sys();
let first;
let second;
let third;
unsafe {
// 3(UL) ~ SQL_CURSOR_STATIC
let _ = odbc_sys::SQLSetStmtAttr(
stmt_ptr,
odbc_sys::StatementAttribute::CursorType,
3 as Pointer,
0,
);
// Bind row set buffer
let mut stmt = Preallocated::new(stmt);
let mut cursor = stmt.execute(&query, ()).unwrap().unwrap();
let mut buffer = TextRowSet::for_cursor(1, &mut cursor, Some(10)).unwrap();
let mut block_cursor = cursor.bind_buffer(&mut buffer).unwrap();
// Move cursor two forward
first = block_cursor
.fetch()
.unwrap()
.unwrap()
.at_as_str(0, 0)
.unwrap()
.unwrap()
.to_owned();
second = block_cursor
.fetch()
.unwrap()
.unwrap()
.at_as_str(0, 0)
.unwrap()
.unwrap()
.to_owned();
let _ = odbc_sys::SQLFetchScroll(stmt_ptr, sys::FetchOrientation::Absolute, 1);
third = block_cursor
.fetch()
.unwrap()
.unwrap()
.at_as_str(0, 0)
.unwrap()
.unwrap()
.to_owned();
}

// Then
assert_eq!("one", first);
assert_eq!("two", second);
assert_eq!("two", third);
}

#[test_case(MSSQL; "Microsoft SQL Server")]
#[test_case(MARIADB; "Maria DB")]
#[test_case(SQLITE_3; "SQLite 3")]
Expand Down

0 comments on commit 736bb28

Please sign in to comment.