Newer
Older
pivot-app / src / main / resources / db / migration / V4__create_partitions_and_functions.sql
-- V4__create_partitions_and_functions.sql
-- Partitions for test organizations and utility functions

-- ============================================
-- Create partitions for test organizations (1, 2, 3)
-- "All data, metadata, and pivot table structures are physically
-- partitioned by OrgID using native database partitioning"
-- ============================================

-- Partitions for mt_data
CREATE TABLE mt_data_org1 PARTITION OF mt_data FOR VALUES IN (1);
CREATE TABLE mt_data_org2 PARTITION OF mt_data FOR VALUES IN (2);
CREATE TABLE mt_data_org3 PARTITION OF mt_data FOR VALUES IN (3);

-- Partitions for mt_clobs
CREATE TABLE mt_clobs_org1 PARTITION OF mt_clobs FOR VALUES IN (1);
CREATE TABLE mt_clobs_org2 PARTITION OF mt_clobs FOR VALUES IN (2);
CREATE TABLE mt_clobs_org3 PARTITION OF mt_clobs FOR VALUES IN (3);

-- Partitions for mt_indexes
CREATE TABLE mt_indexes_org1 PARTITION OF mt_indexes FOR VALUES IN (1);
CREATE TABLE mt_indexes_org2 PARTITION OF mt_indexes FOR VALUES IN (2);
CREATE TABLE mt_indexes_org3 PARTITION OF mt_indexes FOR VALUES IN (3);

-- Partitions for mt_unique_fields
CREATE TABLE mt_unique_fields_org1 PARTITION OF mt_unique_fields FOR VALUES IN (1);
CREATE TABLE mt_unique_fields_org2 PARTITION OF mt_unique_fields FOR VALUES IN (2);
CREATE TABLE mt_unique_fields_org3 PARTITION OF mt_unique_fields FOR VALUES IN (3);

-- Partitions for mt_relationships
CREATE TABLE mt_relationships_org1 PARTITION OF mt_relationships FOR VALUES IN (1);
CREATE TABLE mt_relationships_org2 PARTITION OF mt_relationships FOR VALUES IN (2);
CREATE TABLE mt_relationships_org3 PARTITION OF mt_relationships FOR VALUES IN (3);

-- Partitions for mt_fallback_index
CREATE TABLE mt_fallback_index_org1 PARTITION OF mt_fallback_index FOR VALUES IN (1);
CREATE TABLE mt_fallback_index_org2 PARTITION OF mt_fallback_index FOR VALUES IN (2);
CREATE TABLE mt_fallback_index_org3 PARTITION OF mt_fallback_index FOR VALUES IN (3);

-- Partitions for mt_name_denorm
CREATE TABLE mt_name_denorm_org1 PARTITION OF mt_name_denorm FOR VALUES IN (1);
CREATE TABLE mt_name_denorm_org2 PARTITION OF mt_name_denorm FOR VALUES IN (2);
CREATE TABLE mt_name_denorm_org3 PARTITION OF mt_name_denorm FOR VALUES IN (3);

-- Partitions for mt_field_history
CREATE TABLE mt_field_history_org1 PARTITION OF mt_field_history FOR VALUES IN (1);
CREATE TABLE mt_field_history_org2 PARTITION OF mt_field_history FOR VALUES IN (2);
CREATE TABLE mt_field_history_org3 PARTITION OF mt_field_history FOR VALUES IN (3);

-- ============================================
-- Function: Create all partitions for a new organization
-- ============================================
CREATE OR REPLACE FUNCTION create_org_partitions(p_org_id INTEGER)
RETURNS VOID AS $$
BEGIN
    -- mt_data
    EXECUTE format('CREATE TABLE IF NOT EXISTS mt_data_org%s PARTITION OF mt_data FOR VALUES IN (%s)',
                   p_org_id, p_org_id);
    -- mt_clobs
    EXECUTE format('CREATE TABLE IF NOT EXISTS mt_clobs_org%s PARTITION OF mt_clobs FOR VALUES IN (%s)',
                   p_org_id, p_org_id);
    -- mt_indexes
    EXECUTE format('CREATE TABLE IF NOT EXISTS mt_indexes_org%s PARTITION OF mt_indexes FOR VALUES IN (%s)',
                   p_org_id, p_org_id);
    -- mt_unique_fields
    EXECUTE format('CREATE TABLE IF NOT EXISTS mt_unique_fields_org%s PARTITION OF mt_unique_fields FOR VALUES IN (%s)',
                   p_org_id, p_org_id);
    -- mt_relationships
    EXECUTE format('CREATE TABLE IF NOT EXISTS mt_relationships_org%s PARTITION OF mt_relationships FOR VALUES IN (%s)',
                   p_org_id, p_org_id);
    -- mt_fallback_index
    EXECUTE format('CREATE TABLE IF NOT EXISTS mt_fallback_index_org%s PARTITION OF mt_fallback_index FOR VALUES IN (%s)',
                   p_org_id, p_org_id);
    -- mt_name_denorm
    EXECUTE format('CREATE TABLE IF NOT EXISTS mt_name_denorm_org%s PARTITION OF mt_name_denorm FOR VALUES IN (%s)',
                   p_org_id, p_org_id);
    -- mt_field_history
    EXECUTE format('CREATE TABLE IF NOT EXISTS mt_field_history_org%s PARTITION OF mt_field_history FOR VALUES IN (%s)',
                   p_org_id, p_org_id);
END;
$$ LANGUAGE plpgsql;

-- ============================================
-- Function: Case-folding for StringValue (case-insensitive search)
-- "Application servers use a case-folding algorithm that converts
-- string values to a universal, case-insensitive format"
-- ============================================
CREATE OR REPLACE FUNCTION case_fold(p_value VARCHAR)
RETURNS VARCHAR AS $$
BEGIN
    RETURN LOWER(TRIM(p_value));
END;
$$ LANGUAGE plpgsql IMMUTABLE;

-- ============================================
-- Function: Convert flex column value to appropriate type
-- "Uses underlying database datatype-conversion functions
-- (TO_NUMBER, TO_DATE, TO_CHAR) as necessary"
-- ============================================
CREATE OR REPLACE FUNCTION to_num(p_value VARCHAR)
RETURNS NUMERIC AS $$
BEGIN
    RETURN p_value::NUMERIC;
EXCEPTION WHEN OTHERS THEN
    RETURN NULL;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

CREATE OR REPLACE FUNCTION to_dt(p_value VARCHAR)
RETURNS TIMESTAMPTZ AS $$
BEGIN
    RETURN p_value::TIMESTAMPTZ;
EXCEPTION WHEN OTHERS THEN
    RETURN NULL;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

CREATE OR REPLACE FUNCTION to_bool(p_value VARCHAR)
RETURNS BOOLEAN AS $$
BEGIN
    RETURN CASE
        WHEN LOWER(p_value) IN ('true', '1', 'yes', 'y', 't') THEN TRUE
        WHEN LOWER(p_value) IN ('false', '0', 'no', 'n', 'f') THEN FALSE
        ELSE NULL
    END;
END;
$$ LANGUAGE plpgsql IMMUTABLE;