Comment lib/database/* (#LLM-assisted - Claude Code)
This commit is contained in:
parent
ee119f07a4
commit
22549072c3
@ -1,4 +1,18 @@
|
|||||||
#!/bin/bash
|
#!/bin/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.
|
||||||
|
|
||||||
Delete() {
|
Delete() {
|
||||||
#Delete table < where_key where_operator where_value
|
#Delete table < where_key where_operator where_value
|
||||||
# [where_key where_operator where_value
|
# [where_key where_operator where_value
|
||||||
@ -10,13 +24,16 @@ Delete() {
|
|||||||
value \
|
value \
|
||||||
where_statement \
|
where_statement \
|
||||||
results
|
results
|
||||||
|
# Build WHERE clause from stdin: one "key op value" triple per line
|
||||||
while read key operator value
|
while read key operator value
|
||||||
do
|
do
|
||||||
(( ${#where_statement} )) && where_statement+=( "AND" )
|
(( ${#where_statement} )) && where_statement+=( "AND" )
|
||||||
if [[ $value == NULL ]]
|
if [[ $value == NULL ]]
|
||||||
then
|
then
|
||||||
|
# NULL comparisons require IS NULL, not = "NULL"
|
||||||
where_statement+=( "$key is NULL" )
|
where_statement+=( "$key is NULL" )
|
||||||
else
|
else
|
||||||
|
# Double embedded quotes to safely escape string values
|
||||||
where_statement+=( "$key $operator "'"'"${value//\"/\"\"}"'"' )
|
where_statement+=( "$key $operator "'"'"${value//\"/\"\"}"'"' )
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
@ -1,14 +1,32 @@
|
|||||||
#!/bin/bash
|
#!/bin/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.
|
||||||
|
|
||||||
Insert() {
|
Insert() {
|
||||||
#Insert table [no_id] < key value
|
#Insert table [no_id] < key value
|
||||||
# [key value
|
# [key value
|
||||||
# […]]
|
# […]]
|
||||||
|
#
|
||||||
|
# If no_id is set to a non-zero value, the function will not return the
|
||||||
|
# auto-assigned row ID of the inserted row.
|
||||||
local \
|
local \
|
||||||
table="$1" \
|
table="$1" \
|
||||||
no_id="${2:-0}" \
|
no_id="${2:-0}" \
|
||||||
insert_keys \
|
insert_keys \
|
||||||
insert_values \
|
insert_values \
|
||||||
results
|
results
|
||||||
|
# Build column list and value list from stdin key-value pairs
|
||||||
while read key value
|
while read key value
|
||||||
do
|
do
|
||||||
(( ${#insert_keys} )) && insert_keys+=","
|
(( ${#insert_keys} )) && insert_keys+=","
|
||||||
@ -16,16 +34,24 @@ Insert() {
|
|||||||
(( ${#insert_values} )) && insert_values+=","
|
(( ${#insert_values} )) && insert_values+=","
|
||||||
case $value in
|
case $value in
|
||||||
'::AtOM:FT::'*)
|
'::AtOM:FT::'*)
|
||||||
|
# Force-text prefix: strip the marker and quote
|
||||||
|
# as string (prevents numeric-looking values
|
||||||
|
# from being stored as int / float)
|
||||||
value="${value//::AtOM:FT::/}"
|
value="${value//::AtOM:FT::/}"
|
||||||
insert_values+='"'"${value//\"/\"\"}"'"'
|
insert_values+='"'"${value//\"/\"\"}"'"'
|
||||||
;;
|
;;
|
||||||
'NULL')
|
'NULL')
|
||||||
|
# Insert SQL NULL (not the string "NULL")
|
||||||
insert_values+="NULL"
|
insert_values+="NULL"
|
||||||
;;
|
;;
|
||||||
+([0-9])?(.+([0-9])))
|
+([0-9])?(.+([0-9])))
|
||||||
|
# Pure integer or decimal: insert unquoted for
|
||||||
|
# numeric storage
|
||||||
insert_values+=$value
|
insert_values+=$value
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
# General string: restore encoded newlines,
|
||||||
|
# then quote
|
||||||
value=${value//::AtOM:NewLine:SQL:Inline::/$'\n'}
|
value=${value//::AtOM:NewLine:SQL:Inline::/$'\n'}
|
||||||
insert_values+='"'"${value//\"/\"\"}"'"'
|
insert_values+='"'"${value//\"/\"\"}"'"'
|
||||||
;;
|
;;
|
||||||
@ -35,6 +61,7 @@ Insert() {
|
|||||||
"( $insert_keys )" \
|
"( $insert_keys )" \
|
||||||
"VALUES" \
|
"VALUES" \
|
||||||
"( $insert_values );" >&3
|
"( $insert_values );" >&3
|
||||||
|
# Unless no_id is set, return the auto-assigned row ID
|
||||||
(( no_id )) || {
|
(( no_id )) || {
|
||||||
echo 'SELECT LAST_INSERT_ROWID();' >&3
|
echo 'SELECT LAST_INSERT_ROWID();' >&3
|
||||||
read -u4 -r -d $'\0' results
|
read -u4 -r -d $'\0' results
|
||||||
|
|||||||
@ -1,6 +1,23 @@
|
|||||||
#!/bin/bash
|
#!/bin/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.
|
||||||
|
|
||||||
InsertIfUnset() {
|
InsertIfUnset() {
|
||||||
#InsertIfUnset table [no_id] < key value \n key value
|
#InsertIfUnset table [no_id] < key value \n key value
|
||||||
|
#
|
||||||
|
# If no_id is set to a non-zero value, the function will not return the
|
||||||
|
# auto-assigned row ID of the inserted row.
|
||||||
local \
|
local \
|
||||||
table="$1" \
|
table="$1" \
|
||||||
no_id="${2:-0}" \
|
no_id="${2:-0}" \
|
||||||
@ -10,27 +27,32 @@ InsertIfUnset() {
|
|||||||
results \
|
results \
|
||||||
value \
|
value \
|
||||||
values
|
values
|
||||||
|
# Read all key-value pairs from stdin into parallel arrays
|
||||||
while read key value
|
while read key value
|
||||||
do
|
do
|
||||||
keys+=( "$key" )
|
keys+=( "$key" )
|
||||||
values+=( "$value" )
|
values+=( "$value" )
|
||||||
done
|
done
|
||||||
|
# Choose which column to return: first key column if no_id, else 'id'
|
||||||
if (( no_id ))
|
if (( no_id ))
|
||||||
then
|
then
|
||||||
column="${keys[0]}"
|
column="${keys[0]}"
|
||||||
else
|
else
|
||||||
column='id'
|
column='id'
|
||||||
fi
|
fi
|
||||||
|
# Check if a matching row already exists
|
||||||
if ! results=$(
|
if ! results=$(
|
||||||
Select "$table" "$column" < <(
|
Select "$table" "$column" < <(
|
||||||
for key in ${!keys[@]}
|
for key in ${!keys[@]}
|
||||||
do
|
do
|
||||||
|
# Strip ::AtOM:FT:: for WHERE comparison
|
||||||
echo "${keys[$key]}" = \
|
echo "${keys[$key]}" = \
|
||||||
"${values[$key]//::AtOM:FT::}"
|
"${values[$key]//::AtOM:FT::}"
|
||||||
done
|
done
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
then
|
then
|
||||||
|
# Row not found: insert it and return the new id
|
||||||
results=$(
|
results=$(
|
||||||
Insert "$table" < <(
|
Insert "$table" < <(
|
||||||
for key in ${!keys[@]}
|
for key in ${!keys[@]}
|
||||||
|
|||||||
@ -1,4 +1,18 @@
|
|||||||
#!/bin/bash
|
#!/bin/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.
|
||||||
|
|
||||||
InsertOrUpdate() {
|
InsertOrUpdate() {
|
||||||
#InsertOrUpdate table set_key set_value [set_key set_value […]] < where_key where_value
|
#InsertOrUpdate table set_key set_value [set_key set_value […]] < where_key where_value
|
||||||
# [where_key where_value
|
# [where_key where_value
|
||||||
@ -15,6 +29,8 @@ InsertOrUpdate() {
|
|||||||
what \
|
what \
|
||||||
results
|
results
|
||||||
shift
|
shift
|
||||||
|
# Parse positional args as alternating key/value pairs for the SET
|
||||||
|
# clause
|
||||||
what=key
|
what=key
|
||||||
for argument
|
for argument
|
||||||
do
|
do
|
||||||
@ -29,11 +45,13 @@ InsertOrUpdate() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
# Read WHERE conditions from stdin
|
||||||
while read key value
|
while read key value
|
||||||
do
|
do
|
||||||
keys+=( "$key" )
|
keys+=( "$key" )
|
||||||
values+=( "$value" )
|
values+=( "$value" )
|
||||||
done
|
done
|
||||||
|
# Check if a matching row exists using the WHERE keys
|
||||||
if results=$(
|
if results=$(
|
||||||
Select "$table" ${keys[0]} < <(
|
Select "$table" ${keys[0]} < <(
|
||||||
for key in ${!keys[@]}
|
for key in ${!keys[@]}
|
||||||
@ -43,6 +61,7 @@ InsertOrUpdate() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
then
|
then
|
||||||
|
# Row exists: update it with the SET values
|
||||||
Update "$table" "$@" < <(
|
Update "$table" "$@" < <(
|
||||||
for key in ${!keys[@]}
|
for key in ${!keys[@]}
|
||||||
do
|
do
|
||||||
@ -50,6 +69,8 @@ InsertOrUpdate() {
|
|||||||
done
|
done
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
|
# Row not found: insert combining SET columns and WHERE-match
|
||||||
|
# columns
|
||||||
results=$(
|
results=$(
|
||||||
Insert "$table" < <(
|
Insert "$table" < <(
|
||||||
for key in ${!set_keys[@]}
|
for key in ${!set_keys[@]}
|
||||||
|
|||||||
@ -1,4 +1,18 @@
|
|||||||
#!/bin/bash
|
#!/bin/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.
|
||||||
|
|
||||||
Select() {
|
Select() {
|
||||||
#Select table [col1 [col2 [..]]] < WHERE_key WHERE_operator WHERE_value
|
#Select table [col1 [col2 [..]]] < WHERE_key WHERE_operator WHERE_value
|
||||||
# [WHERE_key WHERE_operator WHERE_value
|
# [WHERE_key WHERE_operator WHERE_value
|
||||||
@ -11,23 +25,28 @@ Select() {
|
|||||||
results \
|
results \
|
||||||
where_statement
|
where_statement
|
||||||
shift
|
shift
|
||||||
|
# Build column list
|
||||||
for col
|
for col
|
||||||
do
|
do
|
||||||
(( ${#columns} )) && columns+=','
|
(( ${#columns} )) && columns+=','
|
||||||
columns+="$col"
|
columns+="$col"
|
||||||
done
|
done
|
||||||
|
# Build WHERE clause from stdin triplets
|
||||||
while read key operator value
|
while read key operator value
|
||||||
do
|
do
|
||||||
(( ${#where_statement} )) && where_statement+=( "AND" )
|
(( ${#where_statement} )) && where_statement+=( "AND" )
|
||||||
|
# Restore encoded newlines before embedding in SQL
|
||||||
value=${value//::AtOM:NewLine:SQL:Inline::/$'\n'}
|
value=${value//::AtOM:NewLine:SQL:Inline::/$'\n'}
|
||||||
where_statement+=( "$key $operator "'"'"${value//\"/\"\"}"'"' )
|
where_statement+=( "$key $operator "'"'"${value//\"/\"\"}"'"' )
|
||||||
done
|
done
|
||||||
|
# Use IFNULL so SQLite always produces output.
|
||||||
echo "SELECT IFNULL(" \
|
echo "SELECT IFNULL(" \
|
||||||
"(SELECT $columns FROM $table" \
|
"(SELECT $columns FROM $table" \
|
||||||
"WHERE ${where_statement[@]})" \
|
"WHERE ${where_statement[@]})" \
|
||||||
",'SQL::Select:not found'" \
|
",'SQL::Select:not found'" \
|
||||||
");" >&3
|
");" >&3
|
||||||
read -u 4 -r -d $'\0' results
|
read -u 4 -r -d $'\0' results
|
||||||
|
# Return exit code 1 if the sentinel value indicates no row was found
|
||||||
if ! [[ $results == "SQL::Select:not found" ]]
|
if ! [[ $results == "SQL::Select:not found" ]]
|
||||||
then
|
then
|
||||||
echo "$results"
|
echo "$results"
|
||||||
|
|||||||
@ -1,4 +1,18 @@
|
|||||||
#!/bin/bash
|
#!/bin/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.
|
||||||
|
|
||||||
Update() {
|
Update() {
|
||||||
#Update table set_key set_value [set_key set_value […]] < where_key where_operator where_value
|
#Update table set_key set_value [set_key set_value […]] < where_key where_operator where_value
|
||||||
# [where_key where_operator where_value
|
# [where_key where_operator where_value
|
||||||
@ -16,17 +30,22 @@ Update() {
|
|||||||
where_statement \
|
where_statement \
|
||||||
results
|
results
|
||||||
shift
|
shift
|
||||||
|
# Parse positional args as alternating key/value for the SET clause
|
||||||
what=key
|
what=key
|
||||||
for argument
|
for argument
|
||||||
do
|
do
|
||||||
case $what in
|
case $what in
|
||||||
key)
|
key)
|
||||||
|
# Backtick-quote column name to handle reserved
|
||||||
|
# words
|
||||||
set_statement="${set_statement:+${set_statement},}\`$argument\`"
|
set_statement="${set_statement:+${set_statement},}\`$argument\`"
|
||||||
what=value
|
what=value
|
||||||
;;
|
;;
|
||||||
value)
|
value)
|
||||||
case $argument in
|
case $argument in
|
||||||
'::AtOM:FT::'*)
|
'::AtOM:FT::'*)
|
||||||
|
# Force-text: strip prefix and
|
||||||
|
# quote as string
|
||||||
argument="${argument//::AtOM:FT::/}"
|
argument="${argument//::AtOM:FT::/}"
|
||||||
set_statement+=" = "'"'"${argument//\"/\"\"}"'"'
|
set_statement+=" = "'"'"${argument//\"/\"\"}"'"'
|
||||||
;;
|
;;
|
||||||
@ -34,6 +53,7 @@ Update() {
|
|||||||
set_statement+=" = NULL"
|
set_statement+=" = NULL"
|
||||||
;;
|
;;
|
||||||
+([0-9])?(.+([0-9])))
|
+([0-9])?(.+([0-9])))
|
||||||
|
# Numeric value: store unquoted
|
||||||
set_statement+=" = $argument"
|
set_statement+=" = $argument"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@ -44,6 +64,7 @@ Update() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
# Build WHERE clause from stdin
|
||||||
while read key operator value
|
while read key operator value
|
||||||
do
|
do
|
||||||
(( ${#where_statement} )) && where_statement+=( "AND" )
|
(( ${#where_statement} )) && where_statement+=( "AND" )
|
||||||
@ -52,6 +73,7 @@ Update() {
|
|||||||
where_statement+=( "$key is NULL" )
|
where_statement+=( "$key is NULL" )
|
||||||
;;
|
;;
|
||||||
+([0-9.]))
|
+([0-9.]))
|
||||||
|
# Numeric: compare without quotes
|
||||||
where_statement+=( "$key $operator $value" )
|
where_statement+=( "$key $operator $value" )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
|||||||
@ -1,26 +1,53 @@
|
|||||||
#!/usr/bin/env 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.
|
||||||
|
|
||||||
|
# Current schema version this AtOM binary understands
|
||||||
currentdbversion=8
|
currentdbversion=8
|
||||||
checkDatabaseVersion() {
|
checkDatabaseVersion() {
|
||||||
local dbversion
|
local dbversion
|
||||||
|
# Try to read the stored version from the 'atom' metadata table
|
||||||
if dbversion=$(Select atom version <<<"\"1\" = 1")
|
if dbversion=$(Select atom version <<<"\"1\" = 1")
|
||||||
then
|
then
|
||||||
if (( dbversion == currentdbversion ))
|
if (( dbversion == currentdbversion ))
|
||||||
then
|
then
|
||||||
return 0
|
return 0 # Already up to date
|
||||||
elif (( dbversion < currentdbversion ))
|
elif (( dbversion < currentdbversion ))
|
||||||
then
|
then
|
||||||
|
# Run sequential upgrade functions until we reach
|
||||||
|
# `$currentdbversion`
|
||||||
until (( dbversion == currentdbversion ))
|
until (( dbversion == currentdbversion ))
|
||||||
do
|
do
|
||||||
|
# Dynamically calls e.g. upgradedatabase_3_4
|
||||||
upgradedatabase_${dbversion}_$((dbversion+1))
|
upgradedatabase_${dbversion}_$((dbversion+1))
|
||||||
|
# After each upgrade, re-read the version from
|
||||||
|
# the database to ensure it was updated
|
||||||
|
# correctly
|
||||||
dbversion=$(Select atom version <<<"\"1\" = 1")
|
dbversion=$(Select atom version <<<"\"1\" = 1")
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
|
# DB was created by a newer AtOM; we can't run and
|
||||||
|
# ensure consistency
|
||||||
echo "Database schema version $dbversion is" \
|
echo "Database schema version $dbversion is" \
|
||||||
"higher thanthat of this version of" \
|
"higher thanthat of this version of" \
|
||||||
"AtOM ($currentdbversion). Bailing out." >&2
|
"AtOM ($currentdbversion). Bailing out." >&2
|
||||||
exit $EDBVERSION
|
exit $EDBVERSION
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
# No version row found: this is a database from very early
|
||||||
|
# drafts
|
||||||
|
# This is stupid but nobody is running with DB schema v0 anyway
|
||||||
Insert atom 1 <<<"version $currentdbversion"
|
Insert atom 1 <<<"version $currentdbversion"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,31 @@
|
|||||||
#!/bin/bash
|
#!/bin/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.
|
||||||
|
|
||||||
closeDatabase() {
|
closeDatabase() {
|
||||||
|
# Run VACUUM to reclaim space and defragment the database before closing
|
||||||
echo 'vacuum;' >&3
|
echo 'vacuum;' >&3
|
||||||
|
# Tell sqlite3 to exit cleanly
|
||||||
echo .quit >&3
|
echo .quit >&3
|
||||||
(( debug )) && echo -n "Waiting for SQLite to terminate... "
|
(( debug )) && echo -n "Waiting for SQLite to terminate... "
|
||||||
|
# Close the debug tee fd if it was opened (debug level > 2)
|
||||||
(( debug > 2 )) && exec 5>&-
|
(( debug > 2 )) && exec 5>&-
|
||||||
|
# Wait for the sqlite3 background process to fully exit
|
||||||
wait $db_pid
|
wait $db_pid
|
||||||
(( debug )) && echo OK
|
(( debug )) && echo OK
|
||||||
|
# Close the write end of the SQLite input FIFO (FD 3)
|
||||||
exec 3>&-
|
exec 3>&-
|
||||||
|
# Close the read end of the SQLite output FIFO (FD 4)
|
||||||
exec 4<&-
|
exec 4<&-
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,35 @@
|
|||||||
#!/usr/bin/env 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() {
|
openDatabase() {
|
||||||
local \
|
local \
|
||||||
populate_db
|
populate_db
|
||||||
|
|
||||||
|
# If the DB file doesn't exist yet, mark it for schema population
|
||||||
[[ -f "$database" ]] || populate_db=1
|
[[ -f "$database" ]] || populate_db=1
|
||||||
|
|
||||||
|
# Create named FIFOs for bidirectional communication with sqlite3
|
||||||
rm -f "$tempdir"/sqlite.{in,out}
|
rm -f "$tempdir"/sqlite.{in,out}
|
||||||
mkfifo "$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 \
|
stdbuf -o0 sqlite3 -bail \
|
||||||
-newline $'::AtOM:SQL:EOL::\n' \
|
-newline $'::AtOM:SQL:EOL::\n' \
|
||||||
"$database" \
|
"$database" \
|
||||||
@ -13,21 +37,42 @@ openDatabase() {
|
|||||||
| stdbuf -o0 \
|
| stdbuf -o0 \
|
||||||
sed 's/::AtOM:SQL:EOL::/\x0/g;s/\(\x0\)\xA/\1/g' \
|
sed 's/::AtOM:SQL:EOL::/\x0/g;s/\(\x0\)\xA/\1/g' \
|
||||||
> "$tempdir/sqlite.out" &
|
> "$tempdir/sqlite.out" &
|
||||||
|
# Store the PID of the background sqlite3 process so we can wait for it
|
||||||
|
# to exit
|
||||||
db_pid=$!
|
db_pid=$!
|
||||||
|
|
||||||
|
# Open FD 3 as the write end (send SQL commands to sqlite3)
|
||||||
exec 3> "$tempdir"/sqlite.in
|
exec 3> "$tempdir"/sqlite.in
|
||||||
|
# Open FD 4 as the read end (receive query results from sqlite3)
|
||||||
exec 4< "$tempdir"/sqlite.out
|
exec 4< "$tempdir"/sqlite.out
|
||||||
|
|
||||||
|
# FIFOs can be deleted immediately after opening; the fds keep them
|
||||||
|
# alive
|
||||||
rm "$tempdir"/sqlite.{in,out}
|
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 ))
|
if (( debug > 2 ))
|
||||||
then
|
then
|
||||||
exec 5>&3
|
exec 5>&3
|
||||||
exec 3> >(tee -a "$tempdir/debug.log" >&5)
|
exec 3> >(tee -a "$tempdir/debug.log" >&5)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# If new database, populate schema from the SQL schema file
|
||||||
(( populate_db )) && cat $schema >&3
|
(( populate_db )) && cat $schema >&3
|
||||||
|
|
||||||
|
# Configure sqlite3 output separator to match what we parse with ::AtOM:SQL:Sep::
|
||||||
echo '.separator ::AtOM:SQL:Sep::' >&3
|
echo '.separator ::AtOM:SQL:Sep::' >&3
|
||||||
|
# Enforce referential integrity
|
||||||
echo 'PRAGMA foreign_keys = ON;' >&3
|
echo 'PRAGMA foreign_keys = ON;' >&3
|
||||||
|
# Allow trigger chains
|
||||||
echo 'PRAGMA recursive_triggers = ON;' >&3
|
echo 'PRAGMA recursive_triggers = ON;' >&3
|
||||||
|
# Keep temp tables in memory
|
||||||
echo 'PRAGMA temp_store = 2;' >&3
|
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
|
echo 'PRAGMA locking_mode = EXCLUSIVE;' >&3
|
||||||
|
|
||||||
|
# Drain the initial empty result sqlite3 sends on startup
|
||||||
read -u4 -r -d $'\0'
|
read -u4 -r -d $'\0'
|
||||||
unset REPLY
|
unset REPLY
|
||||||
checkDatabaseVersion
|
checkDatabaseVersion
|
||||||
|
|||||||
@ -1,5 +1,18 @@
|
|||||||
#!/usr/bin/env 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.
|
||||||
|
|
||||||
upgradedatabase_1_2() {
|
upgradedatabase_1_2() {
|
||||||
local data \
|
local data \
|
||||||
datas \
|
datas \
|
||||||
@ -9,8 +22,11 @@ upgradedatabase_1_2() {
|
|||||||
fat32
|
fat32
|
||||||
echo "Upgrading database to version 2... (backup is $database.bak_v1)"
|
echo "Upgrading database to version 2... (backup is $database.bak_v1)"
|
||||||
cp "$database" "$database.bak_v1"
|
cp "$database" "$database.bak_v1"
|
||||||
|
# Add new columns to hold the fat32compat and ascii settings separately
|
||||||
echo 'ALTER TABLE destination_files ADD COLUMN fat32compat INTEGER;' >&3
|
echo 'ALTER TABLE destination_files ADD COLUMN fat32compat INTEGER;' >&3
|
||||||
echo 'ALTER TABLE destination_files ADD COLUMN ascii INTEGER;' >&3
|
echo 'ALTER TABLE destination_files ADD COLUMN ascii INTEGER;' >&3
|
||||||
|
# Read all existing destination_files rows to migrate rename_pattern format
|
||||||
|
# Old format embedded fat32compat after a colon: "pattern:fat32value"
|
||||||
echo '
|
echo '
|
||||||
SELECT id,
|
SELECT id,
|
||||||
rename_pattern
|
rename_pattern
|
||||||
@ -24,14 +40,17 @@ SELECT "AtOM::NoMoreData";' >&3
|
|||||||
datas+=( "$data" )
|
datas+=( "$data" )
|
||||||
read -u4 -r -d $'\0' data
|
read -u4 -r -d $'\0' data
|
||||||
done
|
done
|
||||||
|
# Ensure consistency by performing all updates in a single transaction
|
||||||
echo 'BEGIN TRANSACTION;' >&3
|
echo 'BEGIN TRANSACTION;' >&3
|
||||||
for data in "${datas[@]}"
|
for data in "${datas[@]}"
|
||||||
do
|
do
|
||||||
id="${data%%::AtOM:SQL:Sep::*}"
|
id="${data%%::AtOM:SQL:Sep::*}"
|
||||||
rename_pattern="${data#*::AtOM:SQL:Sep::}"
|
rename_pattern="${data#*::AtOM:SQL:Sep::}"
|
||||||
|
# Split "pattern:fat32" on the colon separator
|
||||||
IFS=':'
|
IFS=':'
|
||||||
read pattern fat32 <<<"$rename_pattern"
|
read pattern fat32 <<<"$rename_pattern"
|
||||||
IFS="$oldIFS"
|
IFS="$oldIFS"
|
||||||
|
# ASCII-only didn't exist in v1; default to off
|
||||||
Update destination_files \
|
Update destination_files \
|
||||||
rename_pattern "$pattern" \
|
rename_pattern "$pattern" \
|
||||||
fat32compat "$fat32" \
|
fat32compat "$fat32" \
|
||||||
|
|||||||
@ -1,5 +1,18 @@
|
|||||||
#!/usr/bin/env 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.
|
||||||
|
|
||||||
upgradedatabase_2_3() {
|
upgradedatabase_2_3() {
|
||||||
local data \
|
local data \
|
||||||
datas \
|
datas \
|
||||||
@ -7,7 +20,9 @@ upgradedatabase_2_3() {
|
|||||||
destination
|
destination
|
||||||
echo "Upgrading database to version 3... (backup is $database.bak_v2)"
|
echo "Upgrading database to version 3... (backup is $database.bak_v2)"
|
||||||
cp "$database" "$database.bak_v2"
|
cp "$database" "$database.bak_v2"
|
||||||
|
# Add 'enabled' flag to destinations so individual destinations can be disabled
|
||||||
echo 'ALTER TABLE destinations ADD COLUMN enabled INTEGER DEFAULT 1;' >&3
|
echo 'ALTER TABLE destinations ADD COLUMN enabled INTEGER DEFAULT 1;' >&3
|
||||||
|
# Enable all existing destinations (preserve old behaviour where all were active)
|
||||||
Update destinations enabled 1 <<< "1 = 1"
|
Update destinations enabled 1 <<< "1 = 1"
|
||||||
|
|
||||||
Update atom version 3 <<<"1 = 1"
|
Update atom version 3 <<<"1 = 1"
|
||||||
|
|||||||
@ -1,8 +1,22 @@
|
|||||||
#!/usr/bin/env 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.
|
||||||
|
|
||||||
upgradedatabase_3_4() {
|
upgradedatabase_3_4() {
|
||||||
echo "Upgrading database to version 4... (backup is $database.bak_v3)"
|
echo "Upgrading database to version 4... (backup is $database.bak_v3)"
|
||||||
cp "$database" "$database.bak_v3"
|
cp "$database" "$database.bak_v3"
|
||||||
|
# Add releasecountry tag storage (MusicBrainz Album Release Country)
|
||||||
echo 'ALTER TABLE tags ADD COLUMN releasecountry TEXT;' >&3
|
echo 'ALTER TABLE tags ADD COLUMN releasecountry TEXT;' >&3
|
||||||
|
|
||||||
Update atom version 4 <<<"1 = 1"
|
Update atom version 4 <<<"1 = 1"
|
||||||
|
|||||||
@ -1,8 +1,23 @@
|
|||||||
#!/usr/bin/env 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.
|
||||||
|
|
||||||
upgradedatabase_4_5() {
|
upgradedatabase_4_5() {
|
||||||
echo "Upgrading database to version 5... (backup is $database.bak_v4)"
|
echo "Upgrading database to version 5... (backup is $database.bak_v4)"
|
||||||
cp "$database" "$database.bak_v4"
|
cp "$database" "$database.bak_v4"
|
||||||
|
# Drop and recreate the trigger so it now also watches releasecountry
|
||||||
|
# (added in v4 but not yet included in the trigger's watched columns)
|
||||||
echo 'DROP TRIGGER force_destination_update_on_tag_update;' >&3
|
echo 'DROP TRIGGER force_destination_update_on_tag_update;' >&3
|
||||||
echo '
|
echo '
|
||||||
CREATE TRIGGER IF NOT EXISTS force_destination_update_on_tag_update
|
CREATE TRIGGER IF NOT EXISTS force_destination_update_on_tag_update
|
||||||
@ -24,6 +39,8 @@ upgradedatabase_4_5() {
|
|||||||
depth
|
depth
|
||||||
ON tags
|
ON tags
|
||||||
BEGIN
|
BEGIN
|
||||||
|
-- Reset destination timestamp so the file gets
|
||||||
|
-- re-encoded on next run
|
||||||
UPDATE destination_files SET last_change=0
|
UPDATE destination_files SET last_change=0
|
||||||
WHERE source_file_id=old.source_file;
|
WHERE source_file_id=old.source_file;
|
||||||
END;
|
END;
|
||||||
|
|||||||
@ -1,11 +1,25 @@
|
|||||||
#!/usr/bin/env 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.
|
||||||
|
|
||||||
upgradedatabase_5_6() {
|
upgradedatabase_5_6() {
|
||||||
echo "Upgrading database to version 6... (backup is $database.bak_v5)"
|
echo "Upgrading database to version 6... (backup is $database.bak_v5)"
|
||||||
cp "$database" "$database.bak_v5"
|
cp "$database" "$database.bak_v5"
|
||||||
echo '
|
echo '
|
||||||
ALTER TABLE tags ADD COLUMN replaygain_alb TEXT;
|
ALTER TABLE tags ADD COLUMN replaygain_alb TEXT;
|
||||||
ALTER TABLE tags ADD COLUMN replaygain_trk TEXT;
|
ALTER TABLE tags ADD COLUMN replaygain_trk TEXT;
|
||||||
|
-- Recreate trigger to also watch the new ReplayGain columns
|
||||||
DROP TRIGGER force_destination_update_on_tag_update;
|
DROP TRIGGER force_destination_update_on_tag_update;
|
||||||
CREATE TRIGGER IF NOT EXISTS force_destination_update_on_tag_update
|
CREATE TRIGGER IF NOT EXISTS force_destination_update_on_tag_update
|
||||||
AFTER UPDATE OF
|
AFTER UPDATE OF
|
||||||
|
|||||||
@ -1,8 +1,25 @@
|
|||||||
#!/usr/bin/env 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.
|
||||||
|
|
||||||
upgradedatabase_6_7() {
|
upgradedatabase_6_7() {
|
||||||
echo "Upgrading database to version 7... (backup is $database.bak_v6)"
|
echo "Upgrading database to version 7... (backup is $database.bak_v6)"
|
||||||
cp "$database" "$database.bak_v6"
|
cp "$database" "$database.bak_v6"
|
||||||
|
# In v6 and earlier, destination_files.filename stored absolute paths.
|
||||||
|
# From v7 onwards, filenames are stored relative to the destination
|
||||||
|
# root.
|
||||||
|
# Strip the destination path prefix from all stored filenames.
|
||||||
for destination in "${destinations[@]}"
|
for destination in "${destinations[@]}"
|
||||||
do
|
do
|
||||||
echo "UPDATE destination_files SET filename = REPLACE(filename,'${destinationpath[$destination]}/','') WHERE filename LIKE '${destinationpath[$destination]}/%';" >&3
|
echo "UPDATE destination_files SET filename = REPLACE(filename,'${destinationpath[$destination]}/','') WHERE filename LIKE '${destinationpath[$destination]}/%';" >&3
|
||||||
|
|||||||
@ -1,9 +1,25 @@
|
|||||||
#!/usr/bin/env 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.
|
||||||
|
|
||||||
upgradedatabase_7_8() {
|
upgradedatabase_7_8() {
|
||||||
echo "Upgrading database to version 8... (backup is $database.bak_v7)"
|
echo "Upgrading database to version 8... (backup is $database.bak_v7)"
|
||||||
cp "$database" "$database.bak_v7"
|
cp "$database" "$database.bak_v7"
|
||||||
echo 'Deletion of old files was failing. Users of previous versions (YOU!) are strongly advised to run cleandestinations with the "-r" flag.'
|
# This migration only contains a user notice; no schema changes needed.
|
||||||
read -p "Press Enter to continue..."
|
# The bug fixed in v8 was that old destination files were not being
|
||||||
Update atom version 8 <<<"1 = 1"
|
# deleted on disk correctly; users must run 'cleandestinations -r' to clean up.
|
||||||
|
echo 'Deletion of old files was failing. Users of previous versions (YOU!) are strongly advised to run cleandestinations with the "-r" flag.'
|
||||||
|
read -p "Press Enter to continue..."
|
||||||
|
Update atom version 8 <<<"1 = 1"
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user