sqlfuncs

Check-in Differences
Login

Check-in Differences

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Difference From sqlfuncs-0.1.0 To trunk

2025-03-27
16:26
Up version. Leaf check-in: a81a8cb224 user: jan tags: trunk
16:20
Add transcode module with dehex() function. Document function flags. check-in: d74ac00308 user: jan tags: trunk
2025-03-26
23:10
Move from old repo. check-in: 4b108c1578 user: jan tags: trunk, sqlfuncs-0.1.0
22:26
initial empty check-in check-in: 13b22e059a user: jan tags: trunk

Changes to .efiles.

1
2
3
4
5
6
7

Cargo.toml
README.md
www/index.md
www/changelog.md
src/lib.rs
src/hashing.rs
src/text.rs








>
1
2
3
4
5
6
7
8
Cargo.toml
README.md
www/index.md
www/changelog.md
src/lib.rs
src/hashing.rs
src/text.rs
src/transcode.rs

Changes to Cargo.toml.

1
2
3
4
5
6
7
8
9
10
[package]
name = "sqlfuncs"
version = "0.1.0"
edition = "2021"
license = "0BSD"
# https://crates.io/category_slugs
categories = [ "database" ]
keywords = [ "sqlite", "rusqlite", "functions" ]
repository = "https://repos.qrnch.tech/pub/sqlfuncs"
description = "Scalar functions for use in SQLite through rusqlite."


|







1
2
3
4
5
6
7
8
9
10
[package]
name = "sqlfuncs"
version = "0.1.1"
edition = "2021"
license = "0BSD"
# https://crates.io/category_slugs
categories = [ "database" ]
keywords = [ "sqlite", "rusqlite", "functions" ]
repository = "https://repos.qrnch.tech/pub/sqlfuncs"
description = "Scalar functions for use in SQLite through rusqlite."
20
21
22
23
24
25
26

27
28
29
30
31

# https://doc.rust-lang.org/cargo/reference/manifest.html#the-badges-section
[badges]
maintenance = { status = "actively-developed" }

[dependencies]
digest = { version = "0.10.7" }

orphanage = { version = "0.1.4" }
rusqlite = { version = "0.34.0", features = ["functions"] }
sha2 = { version = "0.10.8" }
sha3 = { version = "0.10.8" }








>





20
21
22
23
24
25
26
27
28
29
30
31
32

# https://doc.rust-lang.org/cargo/reference/manifest.html#the-badges-section
[badges]
maintenance = { status = "actively-developed" }

[dependencies]
digest = { version = "0.10.7" }
hex = { version = "0.4.3" }
orphanage = { version = "0.1.4" }
rusqlite = { version = "0.34.0", features = ["functions"] }
sha2 = { version = "0.10.8" }
sha3 = { version = "0.10.8" }

Changes to src/hashing.rs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//! A collection of hashing functions.
//!
//! Hashing functions that take in an algorigm name accept the following names:
//! `sha2/224`, `sha2/256`, `sha2/384`, `sha2/512`, `sha3/224`, `sha3/256`,
//! `sha3/384`, `sha3/512`

use digest::Digest;

use rusqlite::{functions::FunctionFlags, Connection, Error};


fn mkhasher(algo: &str) -> Result<Box<dyn digest::DynDigest>, Error> {
  match algo {
    "sha2/224" => Ok(Box::new(sha2::Sha224::new())),
    "sha2/256" => Ok(Box::new(sha2::Sha256::new())),
    "sha2/384" => Ok(Box::new(sha2::Sha384::new())),








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//! A collection of hashing functions.
//!
//! Hashing functions that take in an algorigm name accept the following names:
//! `sha2/224`, `sha2/256`, `sha2/384`, `sha2/512`, `sha3/224`, `sha3/256`,
//! `sha3/384`, `sha3/512`

use digest::Digest;

use rusqlite::{Connection, Error, functions::FunctionFlags};


fn mkhasher(algo: &str) -> Result<Box<dyn digest::DynDigest>, Error> {
  match algo {
    "sha2/224" => Ok(Box::new(sha2::Sha224::new())),
    "sha2/256" => Ok(Box::new(sha2::Sha256::new())),
    "sha2/384" => Ok(Box::new(sha2::Sha384::new())),
45
46
47
48
49
50
51





52
53
54
55
56
57
58
///   [instr],
///   |row| {
///     row.get(0)
///   }
///   ).unwrap();
/// assert_eq!(&hstr[..8], "09ca7e4e");
/// ```





#[allow(clippy::missing_errors_doc)]
pub fn hashstr(conn: &Connection) -> Result<(), Error> {
  conn.create_scalar_function(
    "hashstr",
    2,
    FunctionFlags::SQLITE_UTF8
      | FunctionFlags::SQLITE_INNOCUOUS







>
>
>
>
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
///   [instr],
///   |row| {
///     row.get(0)
///   }
///   ).unwrap();
/// assert_eq!(&hstr[..8], "09ca7e4e");
/// ```
///
/// ## SQLite function properties
/// - Deterministic
/// - Innocuous
/// - UTF8
#[allow(clippy::missing_errors_doc)]
pub fn hashstr(conn: &Connection) -> Result<(), Error> {
  conn.create_scalar_function(
    "hashstr",
    2,
    FunctionFlags::SQLITE_UTF8
      | FunctionFlags::SQLITE_INNOCUOUS
92
93
94
95
96
97
98





99
100
101
102
103
104
105
///   [&buf],
///   |row| {
///     row.get(0)
///   }
///   ).unwrap();
/// assert_eq!(&hstr[..8], "09ca7e4e");
/// ```





#[allow(clippy::missing_errors_doc)]
pub fn hashblob(conn: &Connection) -> Result<(), Error> {
  conn.create_scalar_function(
    "hashblob",
    2,
    FunctionFlags::SQLITE_UTF8
      | FunctionFlags::SQLITE_INNOCUOUS







>
>
>
>
>







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
///   [&buf],
///   |row| {
///     row.get(0)
///   }
///   ).unwrap();
/// assert_eq!(&hstr[..8], "09ca7e4e");
/// ```
///
/// ## SQLite function properties
/// - Deterministic
/// - Innocuous
/// - UTF8
#[allow(clippy::missing_errors_doc)]
pub fn hashblob(conn: &Connection) -> Result<(), Error> {
  conn.create_scalar_function(
    "hashblob",
    2,
    FunctionFlags::SQLITE_UTF8
      | FunctionFlags::SQLITE_INNOCUOUS

Changes to src/lib.rs.

1
2
3
4

5
6
//! Collection of scalar functions for use with SQLite through rusqlite.

pub mod hashing;
pub mod text;


// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :




>


1
2
3
4
5
6
7
//! Collection of scalar functions for use with SQLite through rusqlite.

pub mod hashing;
pub mod text;
pub mod transcode;

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :

Changes to src/text.rs.

1
2
3
4
5
6
7
8
9
10
11
12
//! A collection of functions intended to work with text strings.

use rusqlite::{functions::FunctionFlags, Connection, Error};

use orphanage::strx::{validate_objname, RndStr};


/// Add a `randomstr()` SQL function to the connection object.
///
/// The SQL function `randomstr()` takes a single argument:
/// 1. The length of the random string, in characters.
///


|

|







1
2
3
4
5
6
7
8
9
10
11
12
//! A collection of functions intended to work with text strings.

use rusqlite::{Connection, Error, functions::FunctionFlags};

use orphanage::strx::{RndStr, validate_objname};


/// Add a `randomstr()` SQL function to the connection object.
///
/// The SQL function `randomstr()` takes a single argument:
/// 1. The length of the random string, in characters.
///
23
24
25
26
27
28
29




30
31
32
33
34
35
36
/// conn.execute(r#"
/// CREATE TABLE IF NOT EXISTS stuff (
///   id   INTEGER PRIMARY KEY,
///   salt TEXT NOT NULL DEFAULT (randomstr(8))
/// );
/// "#, []);
/// ```




#[allow(clippy::missing_errors_doc)]
pub fn rndstr_alphanum(db: &Connection) -> Result<(), Error> {
  db.create_scalar_function(
    "randomstr",
    1,
    FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_INNOCUOUS,
    move |ctx| {







>
>
>
>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/// conn.execute(r#"
/// CREATE TABLE IF NOT EXISTS stuff (
///   id   INTEGER PRIMARY KEY,
///   salt TEXT NOT NULL DEFAULT (randomstr(8))
/// );
/// "#, []);
/// ```
///
/// ## SQLite function properties
/// - Innocuous
/// - UTF8
#[allow(clippy::missing_errors_doc)]
pub fn rndstr_alphanum(db: &Connection) -> Result<(), Error> {
  db.create_scalar_function(
    "randomstr",
    1,
    FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_INNOCUOUS,
    move |ctx| {
62
63
64
65
66
67
68




69
70
71
72
73
74
75
/// conn.execute(r#"
/// CREATE TABLE IF NOT EXISTS stuff (
///   id   INTEGER PRIMARY KEY,
///   salt TEXT NOT NULL DEFAULT (randomstr(8, "abcdefABCD123456"))
/// );
/// "#, []);
/// ```




#[allow(clippy::missing_errors_doc)]
pub fn rndstr(db: &Connection) -> Result<(), Error> {
  db.create_scalar_function(
    "randomstr",
    2,
    FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_INNOCUOUS,
    move |ctx| {







>
>
>
>







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/// conn.execute(r#"
/// CREATE TABLE IF NOT EXISTS stuff (
///   id   INTEGER PRIMARY KEY,
///   salt TEXT NOT NULL DEFAULT (randomstr(8, "abcdefABCD123456"))
/// );
/// "#, []);
/// ```
///
/// ## SQLite function properties
/// - Innocuous
/// - UTF8
#[allow(clippy::missing_errors_doc)]
pub fn rndstr(db: &Connection) -> Result<(), Error> {
  db.create_scalar_function(
    "randomstr",
    2,
    FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_INNOCUOUS,
    move |ctx| {
100
101
102
103
104
105
106





107
108
109
110
111
112
113
/// CREATE TABLE IF NOT EXISTS stuff (
///   id   INTEGER PRIMARY KEY,
///   name TEXT UNIQUE NOT NULL,
///   CHECK (isobjname(name) == 1)
/// );
/// "#, []);
/// ```





///
/// # Panics
/// The number of input parameters must be exactly 1.
#[allow(clippy::missing_errors_doc)]
pub fn isobjname(conn: &Connection) -> Result<(), Error> {
  conn.create_scalar_function(
    "isobjname",







>
>
>
>
>







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/// CREATE TABLE IF NOT EXISTS stuff (
///   id   INTEGER PRIMARY KEY,
///   name TEXT UNIQUE NOT NULL,
///   CHECK (isobjname(name) == 1)
/// );
/// "#, []);
/// ```
///
/// ## SQLite function properties
/// - Deterministic
/// - Innocuous
/// - UTF8
///
/// # Panics
/// The number of input parameters must be exactly 1.
#[allow(clippy::missing_errors_doc)]
pub fn isobjname(conn: &Connection) -> Result<(), Error> {
  conn.create_scalar_function(
    "isobjname",

Added src/transcode.rs.































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//! Functions for transcoding data.

use rusqlite::{Connection, Error, functions::FunctionFlags};

/// Decode a hex encoded string
///
/// The SQL function `dehex()` takes a single argument:
/// 1. The input hex string.
///
/// Its output will be a blob of the decoded data.
///
/// ```
/// use rusqlite::Connection;
/// use sqlfuncs::transcode::dehex;
///
/// let conn = Connection::open_in_memory().unwrap();
/// dehex(&conn).unwrap();
/// let instr = "48656c6c6f20776f726c6421";
/// let buf: Vec<u8> = conn.query_row_and_then(
///   "SELECT dehex(?);", [instr], |row| {
///     row.get(0)
///   }).unwrap();
/// assert_eq!(buf, "Hello world!".to_owned().into_bytes());
/// ```
///
/// ## SQLite function properties
/// - Deterministic
/// - Innocuous
/// - UTF8
#[allow(clippy::missing_errors_doc)]
pub fn dehex(db: &Connection) -> Result<(), Error> {
  db.create_scalar_function(
    "dehex",
    1,
    FunctionFlags::SQLITE_UTF8
      | FunctionFlags::SQLITE_INNOCUOUS
      | FunctionFlags::SQLITE_DETERMINISTIC,
    move |ctx| {
      let hex_input = ctx.get::<String>(0)?;
      let buf = hex::decode(hex_input)
        .map_err(|_| Error::UserFunctionError("Invalid hex".into()))?;
      Ok(buf)
    }
  )
}

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :

Changes to www/changelog.md.

1
2
3
4
5
6
7


8
9
10
11
12
13
14
# Change Log

## [Unreleased]

[Details](/vdiff?from=sqlfuncs-0.1.0&to=trunk)

### Added



### Changed

### Removed

---








>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Change Log

## [Unreleased]

[Details](/vdiff?from=sqlfuncs-0.1.0&to=trunk)

### Added

- Add `transcode` module with `dehex()` sql function.

### Changed

### Removed

---