#!/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
}
