80 lines
2.6 KiB
Bash
80 lines
2.6 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# Copyright © 2012-2026 ScriptFanix
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License.
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
|
|
# A copy of the GNU General Public License v3 is includded in the LICENSE file
|
|
# at the root of the project.
|
|
|
|
openDatabase() {
|
|
local \
|
|
populate_db
|
|
|
|
# If the DB file doesn't exist yet, mark it for schema population
|
|
[[ -f "$database" ]] || populate_db=1
|
|
|
|
# Create named FIFOs for bidirectional communication with sqlite3
|
|
rm -f "$tempdir"/sqlite.{in,out}
|
|
mkfifo "$tempdir"/sqlite.{in,out}
|
|
|
|
# Start sqlite3 in background:
|
|
# - '-newline ::AtOM:SQL:EOL::' makes each row end with our custom
|
|
# marker. Allows storing newlines.
|
|
# - pipe through sed to convert the custom EOL to NUL bytes
|
|
# (for 'read -d $'\0'')
|
|
# - sed also removes the trailing newline that follows each NUL
|
|
stdbuf -o0 sqlite3 -bail \
|
|
-newline $'::AtOM:SQL:EOL::\n' \
|
|
"$database" \
|
|
< "$tempdir/sqlite.in" \
|
|
| stdbuf -o0 \
|
|
sed 's/::AtOM:SQL:EOL::/\x0/g;s/\(\x0\)\xA/\1/g' \
|
|
> "$tempdir/sqlite.out" &
|
|
# Store the PID of the background sqlite3 process so we can wait for it
|
|
# to exit
|
|
db_pid=$!
|
|
|
|
# Open FD 3 as the write end (send SQL commands to sqlite3)
|
|
exec 3> "$tempdir"/sqlite.in
|
|
# Open FD 4 as the read end (receive query results from sqlite3)
|
|
exec 4< "$tempdir"/sqlite.out
|
|
|
|
# FIFOs can be deleted immediately after opening; the fds keep them
|
|
# alive
|
|
rm "$tempdir"/sqlite.{in,out}
|
|
|
|
# At debug level > 2, tee all SQL to a debug log file (FD 5 = original FD 3)
|
|
if (( debug > 2 ))
|
|
then
|
|
exec 5>&3
|
|
exec 3> >(tee -a "$tempdir/debug.log" >&5)
|
|
fi
|
|
|
|
# If new database, populate schema from the SQL schema file
|
|
(( populate_db )) && cat $schema >&3
|
|
|
|
# Configure sqlite3 output separator to match what we parse with ::AtOM:SQL:Sep::
|
|
echo '.separator ::AtOM:SQL:Sep::' >&3
|
|
# Enforce referential integrity
|
|
echo 'PRAGMA foreign_keys = ON;' >&3
|
|
# Allow trigger chains
|
|
echo 'PRAGMA recursive_triggers = ON;' >&3
|
|
# Keep temp tables in memory
|
|
echo 'PRAGMA temp_store = 2;' >&3
|
|
# We don't handle concurrent writes, lock the database for exclusive
|
|
# access to prevent corruption
|
|
echo 'PRAGMA locking_mode = EXCLUSIVE;' >&3
|
|
|
|
# Drain the initial empty result sqlite3 sends on startup
|
|
read -u4 -r -d $'\0'
|
|
unset REPLY
|
|
checkDatabaseVersion
|
|
}
|