feat(db): add embedded auto-migrating schema system

Replace 4 independent schema management code paths (Docker shell
script, setup wizard pg_restore, test helpers, manual psql) with a
single migration runner embedded in the server binary.

The new server/migrations/ package uses Go embed to bundle all SQL
schemas. On startup, Migrate() creates a schema_version tracking
table, detects existing databases (auto-marks baseline as applied),
and runs pending migrations in transactions.

Key changes:
- Consolidated init.sql + 9.2-update + 33 patches into 0001_init.sql
- Setup wizard simplified to single "Apply schema" checkbox
- Test helpers use migrations.Migrate() instead of pg_restore
- Docker no longer needs schema volume mounts or init script
- Seed data (shops, events, gacha) embedded and applied via API
- Future migrations just add 0002_*.sql files — no manual steps
This commit is contained in:
Houmgaor
2026-02-23 21:19:21 +01:00
parent 6a7db47723
commit 27fb0faa1e
62 changed files with 4736 additions and 932 deletions

Binary file not shown.

View File

@@ -1,13 +0,0 @@
BEGIN;
ALTER TABLE users ADD COLUMN IF NOT EXISTS psn_id TEXT;
ALTER TABLE public.sign_sessions ADD COLUMN id SERIAL;
ALTER TABLE public.sign_sessions ADD CONSTRAINT sign_sessions_pkey PRIMARY KEY (id);
ALTER TABLE public.sign_sessions ALTER COLUMN user_id DROP NOT NULL;
ALTER TABLE public.sign_sessions ADD COLUMN psn_id TEXT;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
ALTER TABLE public.users ADD COLUMN IF NOT EXISTS wiiu_key TEXT;
END;

View File

@@ -1,29 +0,0 @@
BEGIN;
CREATE TABLE IF NOT EXISTS tower (
char_id INT,
tr INT,
trp INT,
tsp INT,
block1 INT,
block2 INT,
skills TEXT,
gems TEXT
);
ALTER TABLE IF EXISTS guild_characters
ADD COLUMN IF NOT EXISTS tower_mission_1 INT;
ALTER TABLE IF EXISTS guild_characters
ADD COLUMN IF NOT EXISTS tower_mission_2 INT;
ALTER TABLE IF EXISTS guild_characters
ADD COLUMN IF NOT EXISTS tower_mission_3 INT;
ALTER TABLE IF EXISTS guilds
ADD COLUMN IF NOT EXISTS tower_mission_page INT DEFAULT 1;
ALTER TABLE IF EXISTS guilds
ADD COLUMN IF NOT EXISTS tower_rp INT DEFAULT 0;
END;

View File

@@ -1,14 +0,0 @@
BEGIN;
create table if not exists event_quests
(
id serial primary key,
max_players integer,
quest_type integer not null,
quest_id integer not null,
mark integer
);
ALTER TABLE IF EXISTS public.servers DROP COLUMN IF EXISTS season;
END;

View File

@@ -1,7 +0,0 @@
CREATE TABLE public.trend_weapons
(
weapon_id integer NOT NULL,
weapon_type integer NOT NULL,
count integer DEFAULT 0,
PRIMARY KEY (weapon_id)
);

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.gacha_entries
ADD COLUMN name text;
END;

View File

@@ -1,11 +0,0 @@
BEGIN;
ALTER TABLE gook RENAME TO goocoo;
ALTER TABLE goocoo RENAME COLUMN gook0 TO goocoo0;
ALTER TABLE goocoo RENAME COLUMN gook1 TO goocoo1;
ALTER TABLE goocoo RENAME COLUMN gook2 TO goocoo2;
ALTER TABLE goocoo RENAME COLUMN gook3 TO goocoo3;
ALTER TABLE goocoo RENAME COLUMN gook4 TO goocoo4;
END;

View File

@@ -1,9 +0,0 @@
BEGIN;
CREATE TABLE IF NOT EXISTS scenario_counter (
id serial primary key,
scenario_id numeric not null,
category_id numeric not null
);
END;

View File

@@ -1,12 +0,0 @@
CREATE TABLE public.kill_logs
(
id serial,
character_id integer NOT NULL,
monster integer NOT NULL,
quantity integer NOT NULL,
timestamp timestamp with time zone NOT NULL,
PRIMARY KEY (id)
);
ALTER TABLE IF EXISTS public.guild_characters
ADD COLUMN box_claimed timestamp with time zone DEFAULT now();

View File

@@ -1,26 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.guild_hunts DROP COLUMN IF EXISTS hunters;
ALTER TABLE IF EXISTS public.guild_characters
ADD COLUMN treasure_hunt integer;
ALTER TABLE IF EXISTS public.guild_hunts
ADD COLUMN start timestamp with time zone NOT NULL DEFAULT now();
UPDATE guild_hunts SET start=to_timestamp(return);
ALTER TABLE IF EXISTS public.guild_hunts DROP COLUMN IF EXISTS "return";
ALTER TABLE IF EXISTS public.guild_hunts
RENAME claimed TO collected;
CREATE TABLE public.guild_hunts_claimed
(
hunt_id integer NOT NULL,
character_id integer NOT NULL
);
ALTER TABLE IF EXISTS public.guild_hunts DROP COLUMN IF EXISTS treasure;
END;

View File

@@ -1,36 +0,0 @@
BEGIN;
-- This will delete all of your old distribution data!
--ALTER TABLE IF EXISTS public.distribution DROP COLUMN IF EXISTS data;
CREATE TABLE public.distribution_items
(
id serial PRIMARY KEY,
distribution_id integer NOT NULL,
item_type integer NOT NULL,
item_id integer,
quantity integer
);
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_hr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_hr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_sr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_sr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_gr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_gr DROP DEFAULT;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_hr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_hr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_sr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_sr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN min_gr DROP NOT NULL;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN max_gr DROP NOT NULL;
UPDATE distribution SET min_hr=NULL WHERE min_hr=65535;
UPDATE distribution SET max_hr=NULL WHERE max_hr=65535;
UPDATE distribution SET min_sr=NULL WHERE min_sr=65535;
UPDATE distribution SET max_sr=NULL WHERE max_sr=65535;
UPDATE distribution SET min_gr=NULL WHERE min_gr=65535;
UPDATE distribution SET max_gr=NULL WHERE max_gr=65535;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.event_quests ADD COLUMN IF NOT EXISTS flags integer;
END;

View File

@@ -1,10 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.event_quests ADD COLUMN IF NOT EXISTS start_time timestamp with time zone NOT NULL DEFAULT now();
ALTER TABLE IF EXISTS public.event_quests ADD COLUMN IF NOT EXISTS active_duration int;
ALTER TABLE IF EXISTS public.event_quests ADD COLUMN IF NOT EXISTS inactive_duration int;
UPDATE public.event_quests SET active_duration=NULL, inactive_duration=NULL;
ALTER TABLE IF EXISTS public.event_quests RENAME active_duration TO active_days;
ALTER TABLE IF EXISTS public.event_quests RENAME inactive_duration TO inactive_days;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.guild_characters ADD COLUMN trial_vote integer;
END;

View File

@@ -1,20 +0,0 @@
DO $$ BEGIN
-- Only apply if the new-schema columns exist (item_type vs legacy itemtype)
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name='fpoint_items' AND column_name='item_type'
) THEN
DELETE FROM public.fpoint_items;
ALTER TABLE public.fpoint_items ALTER COLUMN item_type SET NOT NULL;
ALTER TABLE public.fpoint_items ALTER COLUMN item_id SET NOT NULL;
ALTER TABLE public.fpoint_items ALTER COLUMN quantity SET NOT NULL;
ALTER TABLE public.fpoint_items ALTER COLUMN fpoints SET NOT NULL;
ALTER TABLE public.fpoint_items DROP COLUMN IF EXISTS trade_type;
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name='fpoint_items' AND column_name='buyable'
) THEN
ALTER TABLE public.fpoint_items ADD COLUMN buyable boolean NOT NULL DEFAULT false;
END IF;
END IF;
END $$;

View File

@@ -1,5 +0,0 @@
BEGIN;
UPDATE goocoo SET goocoo0=NULL, goocoo1=NULL, goocoo2=NULL, goocoo3=NULL, goocoo4=NULL;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.users ADD COLUMN discord_token text;
ALTER TABLE IF EXISTS public.users ADD COLUMN discord_id text;
END;

View File

@@ -1,12 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.users ADD COLUMN op boolean;
CREATE TABLE public.bans
(
user_id integer NOT NULL,
expires timestamp with time zone,
PRIMARY KEY (user_id)
);
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
ALTER TABLE users ADD COLUMN IF NOT EXISTS timer bool;
END;

View File

@@ -1,16 +0,0 @@
CREATE TABLE IF NOT EXISTS festa_submissions (
character_id int NOT NULL,
guild_id int NOT NULL,
trial_type int NOT NULL,
souls int NOT NULL,
timestamp timestamp with time zone NOT NULL
);
ALTER TABLE guild_characters DROP COLUMN IF EXISTS souls;
DO $$ BEGIN
ALTER TYPE festival_colour RENAME TO festival_color;
EXCEPTION
WHEN undefined_object THEN NULL;
WHEN duplicate_object THEN NULL;
END $$;

View File

@@ -1,6 +0,0 @@
BEGIN;
UPDATE guilds SET item_box=NULL;
UPDATE users SET item_box=NULL;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.characters RENAME hrp TO hr;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE guilds ADD COLUMN IF NOT EXISTS room_rp INT DEFAULT 0;
ALTER TABLE guilds ADD COLUMN IF NOT EXISTS room_expiry TIMESTAMP WITHOUT TIME ZONE;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE distribution ADD COLUMN rights INTEGER;
ALTER TABLE distribution ADD COLUMN selection BOOLEAN;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.stamps RENAME hl_next TO hl_checked;
ALTER TABLE IF EXISTS public.stamps RENAME ex_next TO ex_checked;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
CREATE SEQUENCE IF NOT EXISTS public.rasta_id_seq;
END;

View File

@@ -1,5 +0,0 @@
BEGIN;
ALTER TABLE mail ADD COLUMN IF NOT EXISTS is_sys_message BOOLEAN NOT NULL DEFAULT false;
END;

View File

@@ -1,15 +0,0 @@
BEGIN;
-- Initialize otomoairou (mercenary data) with default empty data for characters that have NULL or empty values
-- This prevents error logs when loading mercenary data during zone transitions
UPDATE characters
SET otomoairou = decode(repeat('00', 10), 'hex')
WHERE otomoairou IS NULL OR length(otomoairou) = 0;
-- Initialize platemyset (plate configuration) with default empty data for characters that have NULL or empty values
-- This prevents error logs when loading plate data during zone transitions
UPDATE characters
SET platemyset = decode(repeat('00', 1920), 'hex')
WHERE platemyset IS NULL OR length(platemyset) = 0;
COMMIT;

View File

@@ -1,7 +0,0 @@
-- Drop transient binary columns that are now memory-only.
-- UserBinary type2/type3 and characters.minidata are session state
-- resent by the client on every login; they do not need persistence.
ALTER TABLE user_binary DROP COLUMN IF EXISTS type2;
ALTER TABLE user_binary DROP COLUMN IF EXISTS type3;
ALTER TABLE characters DROP COLUMN IF EXISTS minidata;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.guilds
ADD COLUMN IF NOT EXISTS weekly_bonus_users INT NOT NULL DEFAULT 0;
END;

View File

@@ -1,6 +0,0 @@
BEGIN;
ALTER TABLE IF EXISTS public.gacha_stepup
ADD COLUMN IF NOT EXISTS created_at TIMESTAMP WITH TIME ZONE DEFAULT now();
ALTER TABLE IF EXISTS public.guilds
ADD COLUMN IF NOT EXISTS rp_reset_at TIMESTAMP WITH TIME ZONE;
END;

View File

@@ -1,3 +0,0 @@
ALTER TABLE IF EXISTS public.stamps ADD COLUMN IF NOT EXISTS monthly_claimed TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.stamps ADD COLUMN IF NOT EXISTS monthly_hl_claimed TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.stamps ADD COLUMN IF NOT EXISTS monthly_ex_claimed TIMESTAMP WITH TIME ZONE;

View File

@@ -1,6 +0,0 @@
BEGIN;
-- Add soft-delete column to guild_posts, matching the pattern used by characters and mail tables.
ALTER TABLE guild_posts ADD COLUMN IF NOT EXISTS deleted boolean DEFAULT false NOT NULL;
COMMIT;

View File

@@ -1,241 +0,0 @@
BEGIN;
DROP TABLE IF EXISTS public.fpoint_items;
CREATE TABLE IF NOT EXISTS public.fpoint_items (
id serial PRIMARY KEY,
item_type integer,
item_id integer,
quantity integer,
fpoints integer,
trade_type integer
);
ALTER TABLE IF EXISTS public.characters ADD bonus_quests INT NOT NULL DEFAULT 0;
ALTER TABLE IF EXISTS public.characters ADD daily_quests INT NOT NULL DEFAULT 0;
ALTER TABLE IF EXISTS public.characters ADD promo_points INT NOT NULL DEFAULT 0;
ALTER TABLE IF EXISTS public.guild_characters ADD rp_today INT DEFAULT 0;
ALTER TABLE IF EXISTS public.guild_characters ADD rp_yesterday INT DEFAULT 0;
UPDATE public.characters SET savemercenary = NULL;
ALTER TABLE IF EXISTS public.characters ADD rasta_id INT;
ALTER TABLE IF EXISTS public.characters ADD pact_id INT;
ALTER TABLE IF EXISTS public.characters ADD stampcard INT NOT NULL DEFAULT 0;
ALTER TABLE IF EXISTS public.characters DROP COLUMN IF EXISTS gacha_prem;
ALTER TABLE IF EXISTS public.characters DROP COLUMN IF EXISTS gacha_trial;
ALTER TABLE IF EXISTS public.characters DROP COLUMN IF EXISTS frontier_points;
ALTER TABLE IF EXISTS public.users ADD IF NOT EXISTS gacha_premium INT;
ALTER TABLE IF EXISTS public.users ADD IF NOT EXISTS gacha_trial INT;
ALTER TABLE IF EXISTS public.users ADD IF NOT EXISTS frontier_points INT;
DROP TABLE IF EXISTS public.gacha_shop;
CREATE TABLE IF NOT EXISTS public.gacha_shop (
id SERIAL PRIMARY KEY,
min_gr INTEGER,
min_hr INTEGER,
name TEXT,
url_banner TEXT,
url_feature TEXT,
url_thumbnail TEXT,
wide BOOLEAN,
recommended BOOLEAN,
gacha_type INTEGER,
hidden BOOLEAN
);
DROP TABLE IF EXISTS public.gacha_shop_items;
CREATE TABLE IF NOT EXISTS public.gacha_entries (
id SERIAL PRIMARY KEY,
gacha_id INTEGER,
entry_type INTEGER,
item_type INTEGER,
item_number INTEGER,
item_quantity INTEGER,
weight INTEGER,
rarity INTEGER,
rolls INTEGER,
frontier_points INTEGER,
daily_limit INTEGER
);
CREATE TABLE IF NOT EXISTS public.gacha_items (
id SERIAL PRIMARY KEY,
entry_id INTEGER,
item_type INTEGER,
item_id INTEGER,
quantity INTEGER
);
DROP TABLE IF EXISTS public.stepup_state;
CREATE TABLE IF NOT EXISTS public.gacha_stepup (
gacha_id INTEGER,
step INTEGER,
character_id INTEGER
);
DROP TABLE IF EXISTS public.lucky_box_state;
CREATE TABLE IF NOT EXISTS public.gacha_box (
gacha_id INTEGER,
entry_id INTEGER,
character_id INTEGER
);
DROP TABLE IF EXISTS public.login_boost_state;
CREATE TABLE IF NOT EXISTS public.login_boost (
char_id INTEGER,
week_req INTEGER,
expiration TIMESTAMP WITH TIME ZONE,
reset TIMESTAMP WITH TIME ZONE
);
ALTER TABLE IF EXISTS public.characters ADD COLUMN mezfes BYTEA;
ALTER TABLE IF EXISTS public.characters ALTER COLUMN daily_time TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.characters ALTER COLUMN guild_post_checked TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.characters ALTER COLUMN boost_time TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.characters ADD COLUMN IF NOT EXISTS cafe_reset TIMESTAMP WITHOUT TIME ZONE;
ALTER TABLE IF EXISTS public.characters ALTER COLUMN cafe_reset TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.distribution ALTER COLUMN deadline TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.events ALTER COLUMN start_time TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.feature_weapon ALTER COLUMN start_time TYPE TIMESTAMP WITH TIME ZONE;
CREATE TABLE IF NOT EXISTS public.feature_weapon
(
start_time TIMESTAMP WITH TIME ZONE NOT NULL,
featured INTEGER NOT NULL
);
ALTER TABLE IF EXISTS public.guild_alliances ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.guild_applications ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.guild_characters ALTER COLUMN joined_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.guild_posts ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.characters ALTER COLUMN daily_time TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.guilds ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.mail ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.stamps ALTER COLUMN hl_next TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.stamps ALTER COLUMN ex_next TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.titles ALTER COLUMN unlocked_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.titles ALTER COLUMN updated_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.users ALTER COLUMN last_login TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.users ALTER COLUMN return_expires TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE IF EXISTS public.guild_meals DROP COLUMN IF EXISTS expires;
ALTER TABLE IF EXISTS public.guild_meals ADD COLUMN IF NOT EXISTS created_at TIMESTAMP WITH TIME ZONE;
DROP TABLE IF EXISTS public.account_ban;
DROP TABLE IF EXISTS public.account_history;
DROP TABLE IF EXISTS public.account_moderation;
DROP TABLE IF EXISTS public.account_sub;
DROP TABLE IF EXISTS public.history;
DROP TABLE IF EXISTS public.questlists;
DROP TABLE IF EXISTS public.schema_migrations;
DROP TABLE IF EXISTS public.user_binaries;
DROP PROCEDURE IF EXISTS raviinit;
DROP PROCEDURE IF EXISTS ravireset;
ALTER TABLE IF EXISTS public.normal_shop_items RENAME TO shop_items;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN shoptype TO shop_type;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN shopid TO shop_id;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN itemhash TO id;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN itemid TO item_id;
ALTER TABLE IF EXISTS public.shop_items ALTER COLUMN points TYPE integer;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN points TO cost;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN tradequantity TO quantity;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN rankreqlow TO min_hr;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN rankreqhigh TO min_sr;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN rankreqg TO min_gr;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN storelevelreq TO store_level;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN maximumquantity TO max_quantity;
ALTER TABLE IF EXISTS public.shop_items DROP COLUMN IF EXISTS boughtquantity;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN roadfloorsrequired TO road_floors;
ALTER TABLE IF EXISTS public.shop_items RENAME COLUMN weeklyfataliskills TO road_fatalis;
ALTER TABLE public.shop_items RENAME CONSTRAINT normal_shop_items_pkey TO shop_items_pkey;
ALTER TABLE IF EXISTS public.shop_items DROP CONSTRAINT IF EXISTS normal_shop_items_itemhash_key;
CREATE SEQUENCE IF NOT EXISTS public.shop_items_id_seq;
ALTER SEQUENCE IF EXISTS public.shop_items_id_seq OWNER TO postgres;
ALTER TABLE IF EXISTS public.shop_items ALTER COLUMN id SET DEFAULT nextval('shop_items_id_seq'::regclass);
ALTER SEQUENCE IF EXISTS public.shop_items_id_seq OWNED BY shop_items.id;
SELECT setval('shop_items_id_seq', (SELECT MAX(id) FROM public.shop_items));
DROP TABLE IF EXISTS public.shop_item_state;
CREATE TABLE IF NOT EXISTS public.shop_items_bought (
character_id INTEGER,
shop_item_id INTEGER,
bought INTEGER
);
UPDATE users SET rights = rights-2;
ALTER TABLE IF EXISTS public.users ALTER COLUMN rights SET DEFAULT 12;
END;