-- file name: sql/changes/1.12/migrate_serial_to_identity.sql
--
-- Migrate, where possible, serial column types to GENERATED AS IDENTITY.
-- Remove unused sequences.
-- Rename sequences for consistency and usage clarity
--
-- Serial types are not true data types. Instead, it’s a shorthand that creates
-- a column and a sequence for its default value.
-- PostgreSQL 10 (Oct 2017) added support for SQL-standard IDENTITY columns.
--
-- With IDENTITY, It’s easier to grant permissions. Just grant permission on the table and column.
-- It is also easier to update the next value. You don't need to know the sequence name,
-- just use ALTER TABLE.
--

CREATE OR REPLACE FUNCTION migrate_to_identity(table_name_in text, column_name_in text)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
    seq_name            text = format('%s_%s_seq', table_name_in, column_name_in);
    curr_seq_name       text;
    next_seq_value      int;
    table_col_exist     boolean;

BEGIN
    -- Verify that the existing sequence exists and get the next value.
    SELECT  sequence_name,
            nextval(seq_name::regclass)
    INTO    curr_seq_name,
            next_seq_value
    FROM    information_schema.sequences
    WHERE   sequence_name = seq_name;

    IF NOT FOUND THEN
        RAISE EXCEPTION 'Not able to find seq name: %', seq_name;
    END IF;
    RAISE NOTICE 'Next % value is %', seq_name, next_seq_value;

    -- Verify table and column exist.
    SELECT  TRUE
    INTO    table_col_exist
    FROM    information_schema.columns
    WHERE   table_name = table_name_in
        AND column_name = column_name_in;
    IF NOT FOUND THEN
        RAISE EXCEPTION 'Table % or column % do not exist.', table_name_in, column_name_in;
    END IF;

    -- Drop the column default, so the old sequence has no dependency.
    execute format('alter table %I alter column %I drop default;',
                                table_name_in, column_name_in);

    -- Drop the old sequence so when re-created the name postfix is '_seq', not '_seq1'.
    execute format('drop sequence %s;', seq_name);

    -- Add the new identity defaults.
    execute format('alter table %I alter column %I add generated by default as identity (start with %s);',
                                table_name_in, column_name_in, next_seq_value);

END;
$$;

COMMENT ON FUNCTION migrate_to_identity(table_name_in text, column_name_in text) IS
    'Migrate SERIAL to GENERATED AS IDENTITY.';

SELECT migrate_to_identity(table_name_in := 'acc_trans', column_name_in := 'entry_id');
SELECT migrate_to_identity(table_name_in := 'account_checkpoint', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'account_heading', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'account', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'asset_class', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'asset_dep_method', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'asset_disposal_method', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'asset_item', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'asset_report', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'audittrail', column_name_in := 'entry_id');
SELECT migrate_to_identity(table_name_in := 'batch_class', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'batch', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'budget_info', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'business_unit_class', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'business_unit', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'business', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'company', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'contact_class', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'country_tax_form', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'country', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'cr_report_line', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'cr_report', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'employee_class', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'entity_bank_account', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'entity_class', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'entity_credit_account', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'entity', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'exchangerate_type', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'file_class', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'inventory_report', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'invoice', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'jcitems', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'journal_entry', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'journal_line', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'journal_type', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'location_class_to_entity_class', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'location_class', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'location', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'menu_acl', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'menu_node', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'mfg_lot_item', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'mfg_lot', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'mime_type', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'new_shipto', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'note_class', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'oe', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'orderitems', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'parts', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'partscustomer', column_name_in := 'entry_id');
SELECT migrate_to_identity(table_name_in := 'partsgroup', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'partsvendor', column_name_in := 'entry_id');
SELECT migrate_to_identity(table_name_in := 'payment_type', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'payment', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'payroll_deduction_type', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'payroll_deduction', column_name_in := 'entry_id');
SELECT migrate_to_identity(table_name_in := 'payroll_employee_class', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'payroll_income_category', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'payroll_income_type', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'payroll_pto_class', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'payroll_report_line', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'payroll_report', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'payroll_wage', column_name_in := 'entry_id');
SELECT migrate_to_identity(table_name_in := 'person', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'pricegroup', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'robot', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'salutation', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'session', column_name_in := 'session_id');
SELECT migrate_to_identity(table_name_in := 'taxcategory', column_name_in := 'taxcategory_id');
SELECT migrate_to_identity(table_name_in := 'taxmodule', column_name_in := 'taxmodule_id');
SELECT migrate_to_identity(table_name_in := 'template', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'user_preference', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'users', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'voucher', column_name_in := 'id');
SELECT migrate_to_identity(table_name_in := 'warehouse_inventory', column_name_in := 'entry_id');
SELECT migrate_to_identity(table_name_in := 'warehouse', column_name_in := 'id');

-- Has been unused since 1.5: sql/changes/1.5/open_forms_callers.sql:
--      ALTER TABLE open_forms ALTER COLUMN id SET DEFAULT floor(random()*(1000000))+1;
DROP SEQUENCE IF EXISTS open_forms_id_seq;

-- Workflow library uses the following 2 sequences from perl (select nextval('workflow_seq')),
-- so they cannot be converted to IDENTITY:
COMMENT ON SEQUENCE workflow_history_seq IS 'No database dependencies because it is used by the perl Workflow library.';
COMMENT ON SEQUENCE workflow_seq         IS 'No database dependencies because it is used by the perl Workflow library.';

-- Both not converted to identity because it is used by inherited tables
COMMENT ON SEQUENCE file_base_id_seq IS 'Used by inherited tables.';
COMMENT ON SEQUENCE note_id_seq IS 'Used by inherited tables.';

-- Drop the function now that we are done using it.
DROP FUNCTION migrate_to_identity(table_name_in text, column_name_in text);
