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

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
1
2

3
4
5
6
7
8
9
10


-
+







[package]
name = "sqlfuncs"
version = "0.1.0"
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
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
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};
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
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
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
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
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 rusqlite::{Connection, Error, functions::FunctionFlags};

use orphanage::strx::{validate_objname, RndStr};
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
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
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
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
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

---