Merge remote-tracking branch 'jgallagher/master' into vtab

This commit is contained in:
gwenn 2016-02-01 20:35:30 +01:00
commit eab16402be
6 changed files with 61 additions and 19 deletions

View File

@ -4,6 +4,9 @@
* Adds `types::Value` for dynamic column types. * Adds `types::Value` for dynamic column types.
* Adds support for user-defined aggregate functions (behind the existing `functions` Cargo feature). * Adds support for user-defined aggregate functions (behind the existing `functions` Cargo feature).
* Introduces a `RowIndex` trait allowing columns to be fetched via index (as before) or name (new). * Introduces a `RowIndex` trait allowing columns to be fetched via index (as before) or name (new).
* Introduces `ZeroBlob` type under the `blob` module/feature exposing SQLite's zeroblob API.
* Adds CI testing for Windows via AppVeyor.
* Fixes a warning building libsqlite3-sys under Rust 1.6.
# Version 0.6.0 (2015-12-17) # Version 0.6.0 (2015-12-17)

View File

@ -1,6 +1,7 @@
# Rusqlite # Rusqlite
[![Build Status](https://api.travis-ci.org/jgallagher/rusqlite.svg?branch=master)](https://travis-ci.org/jgallagher/rusqlite) [![Travis Build Status](https://api.travis-ci.org/jgallagher/rusqlite.svg?branch=master)](https://travis-ci.org/jgallagher/rusqlite)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/jgallagher/rusqlite?branch=master&svg=true)](https://ci.appveyor.com/project/jgallagher/rusqlite)
Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to expose Rusqlite is an ergonomic wrapper for using SQLite from Rust. It attempts to expose
an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres). View the full an interface similar to [rust-postgres](https://github.com/sfackler/rust-postgres). View the full

22
appveyor.yml Normal file
View File

@ -0,0 +1,22 @@
environment:
TARGET: 1.6.0-x86_64-pc-windows-gnu
MSYS2_BITS: 64
install:
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe"
- rust-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
- if defined MSYS2_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS2_BITS%\bin
- rustc -V
- cargo -V
- ps: Start-FileDownload 'http://sqlite.org/2016/sqlite-dll-win64-x64-3100200.zip'
- cmd: 7z e sqlite-dll-win64-x64-3100200.zip -y > nul
- SET SQLITE3_LIB_DIR=%APPVEYOR_BUILD_FOLDER%
build: false
test_script:
- cargo test --lib --verbose
- cargo test --lib --features "backup blob functions load_extension trace"
cache:
- C:\Users\appveyor\.cargo

View File

@ -1,4 +1,4 @@
#![allow(raw_pointer_derive, non_snake_case, non_camel_case_types)] #![allow(non_snake_case, non_camel_case_types)]
/* automatically generated by rust-bindgen */ /* automatically generated by rust-bindgen */
pub type va_list = __builtin_va_list; pub type va_list = __builtin_va_list;

View File

@ -17,6 +17,7 @@
//! extern crate rusqlite; //! extern crate rusqlite;
//! //!
//! use rusqlite::{Connection, DatabaseName}; //! use rusqlite::{Connection, DatabaseName};
//! use rusqlite::blob::ZeroBlob;
//! use std::io::{Read, Write, Seek, SeekFrom}; //! use std::io::{Read, Write, Seek, SeekFrom};
//! //!
//! fn main() { //! fn main() {
@ -38,7 +39,7 @@
//! let bytes_read = blob.read(&mut buf[..]).unwrap(); //! let bytes_read = blob.read(&mut buf[..]).unwrap();
//! assert_eq!(bytes_read, 10); // note we read 10 bytes because the blob has size 10 //! assert_eq!(bytes_read, 10); // note we read 10 bytes because the blob has size 10
//! //!
//! db.execute("INSERT INTO test (content) VALUES (ZEROBLOB(64))", &[]).unwrap(); //! db.execute("INSERT INTO test (content) VALUES (?)", &[&ZeroBlob(64)]).unwrap();
//! //!
//! // given a new row ID, we can reopen the blob on that row //! // given a new row ID, we can reopen the blob on that row
//! let rowid = db.last_insert_rowid(); //! let rowid = db.last_insert_rowid();
@ -51,8 +52,10 @@ use std::io;
use std::cmp::min; use std::cmp::min;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use libc::c_int;
use super::ffi; use super::ffi;
use super::types::ToSql;
use {Result, Connection, DatabaseName}; use {Result, Connection, DatabaseName};
/// Handle to an open BLOB. /// Handle to an open BLOB.
@ -232,6 +235,19 @@ impl<'conn> Drop for Blob<'conn> {
} }
} }
/// BLOB of length N that is filled with zeroes.
/// Zeroblobs are intended to serve as placeholders for BLOBs whose content is later written using incremental BLOB I/O routines.
/// A negative value for the zeroblob results in a zero-length BLOB.
#[derive(Copy,Clone)]
pub struct ZeroBlob(pub i32);
impl ToSql for ZeroBlob {
unsafe fn bind_parameter(&self, stmt: *mut ffi::sqlite3_stmt, col: c_int) -> c_int {
let ZeroBlob(length) = *self;
ffi::sqlite3_bind_zeroblob(stmt, col, length)
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std::io::{BufReader, BufRead, BufWriter, Read, Write, Seek, SeekFrom}; use std::io::{BufReader, BufRead, BufWriter, Read, Write, Seek, SeekFrom};

View File

@ -509,9 +509,10 @@ impl InnerConnection {
where D: Aggregate<A, T>, where D: Aggregate<A, T>,
T: ToResult T: ToResult
{ {
unsafe fn aggregate_context<A>(ctx: *mut sqlite3_context) -> Option<*mut *mut A> { unsafe fn aggregate_context<A>(ctx: *mut sqlite3_context,
let pac = ffi::sqlite3_aggregate_context(ctx, ::std::mem::size_of::<*mut A>() as c_int) bytes: usize)
as *mut *mut A; -> Option<*mut *mut A> {
let pac = ffi::sqlite3_aggregate_context(ctx, bytes as c_int) as *mut *mut A;
if pac.is_null() { if pac.is_null() {
return None; return None;
} }
@ -545,7 +546,7 @@ impl InnerConnection {
assert!(!boxed_aggr.is_null(), assert!(!boxed_aggr.is_null(),
"Internal error - null aggregate pointer"); "Internal error - null aggregate pointer");
let pac = match aggregate_context(ctx) { let pac = match aggregate_context(ctx, ::std::mem::size_of::<*mut A>()) {
Some(pac) => pac, Some(pac) => pac,
None => { None => {
ffi::sqlite3_result_error_nomem(ctx); ffi::sqlite3_result_error_nomem(ctx);
@ -576,19 +577,18 @@ impl InnerConnection {
assert!(!boxed_aggr.is_null(), assert!(!boxed_aggr.is_null(),
"Internal error - null aggregate pointer"); "Internal error - null aggregate pointer");
let pac = match aggregate_context(ctx) { // Within the xFinal callback, it is customary to set N=0 in calls to
Some(pac) => pac, // sqlite3_aggregate_context(C,N) so that no pointless memory allocations occur.
None => { let a: Option<A> = match aggregate_context(ctx, 0) {
ffi::sqlite3_result_error_nomem(ctx); Some(pac) => {
return; if (*pac).is_null() {
None
} else {
let a = Box::from_raw(*pac);
Some(*a)
}
} }
}; None => None,
let a: Option<A> = if (*pac).is_null() {
None
} else {
let a = Box::from_raw(*pac);
Some(*a)
}; };
match (*boxed_aggr).finalize(a) { match (*boxed_aggr).finalize(a) {