Comment lib/database/* (#LLM-assisted - Claude Code)

This commit is contained in:
Vincent Riquer 2026-03-13 05:15:02 +01:00
parent ee119f07a4
commit 22549072c3
16 changed files with 340 additions and 8 deletions

View File

@ -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

View File

@ -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

View File

@ -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[@]}

View File

@ -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[@]}

View File

@ -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"

View File

@ -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" )
;; ;;
*) *)

View File

@ -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
} }

View File

@ -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<&-
} }

View File

@ -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

View File

@ -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" \

View File

@ -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"

View File

@ -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"

View File

@ -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;

View File

@ -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

View File

@ -1,11 +1,28 @@
#!/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
done done
Update atom version 7 <<<"1 = 1" Update atom version 7 <<<"1 = 1"
} }

View File

@ -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"
}