Сохранение данных в LAS формат


    CREATE OR REPLACE FUNCTION public.func_core_save_to_las(
        a_user_id integer,
        a_parameters jsonb DEFAULT NULL::jsonb)
        RETURNS jsonb
        LANGUAGE 'plpgsql'
        COST 100
        VOLATILE PARALLEL UNSAFE
    AS $BODY$
    DECLARE
        v_las_content text := '';
        v_well_info jsonb;
        v_curve_info jsonb;
        v_log_data jsonb;
        v_wrap_mode text := 'NO';
        v_null_value text := '-999.25';
        v_start_depth numeric;
        v_stop_depth numeric;
        v_step numeric;
    BEGIN
        -- Начало выполнения функции
        RAISE NOTICE 'func_core_save_to_las: Начало выполнения (user_id: %, parameters: %)', a_user_id, a_parameters;
      
        -- Извлекаем информацию из параметров
        v_well_info := a_parameters->'well_info';
        v_curve_info := a_parameters->'curve_info';
        v_log_data := a_parameters->'log_data';
        
        -- Получаем параметры глубины
        v_start_depth := (v_well_info->>'start_depth')::numeric;
        v_stop_depth := (v_well_info->>'stop_depth')::numeric;
        v_step := (v_well_info->>'step')::numeric;
        
        -- Определяем режим переноса (если много кривых, используем WRAP YES)
        IF jsonb_array_length(v_curve_info) > 10 THEN
            v_wrap_mode := 'YES';
        END IF;
        
        -- Формируем заголовок LAS файла
        
        -- 1. Секция Version Information
        v_las_content := v_las_content || '~VERSION INFORMATION' || E'\n';
        v_las_content := v_las_content || 'VERS. 2.1 : CWLS LOG ASCII STANDARD - VERSION 2.1' || E'\n';
        v_las_content := v_las_content || 'WRAP. ' || v_wrap_mode || ' : ' || 
                         CASE WHEN v_wrap_mode = 'YES' THEN 'Multiple lines per depth step' 
                              ELSE 'One line per depth step' END || E'\n';
        v_las_content := v_las_content || E'\n';
        
        -- 2. Секция Well Information
        v_las_content := v_las_content || '~WELL INFORMATION' || E'\n';
        v_las_content := v_las_content || '#MNEM.UNIT      VALUE           DESCRIPTION' || E'\n';
        v_las_content := v_las_content || '#--------       ----------      ---------------------' || E'\n';
        v_las_content := v_las_content || 'STRT .' || (v_well_info->>'depth_unit') || ' ' || 
                         to_char(v_start_depth, 'FM999999990.0000') || ' : START DEPTH' || E'\n';
        v_las_content := v_las_content || 'STOP .' || (v_well_info->>'depth_unit') || ' ' || 
                         to_char(v_stop_depth, 'FM999999990.0000') || ' : STOP DEPTH' || E'\n';
        v_las_content := v_las_content || 'STEP .' || (v_well_info->>'depth_unit') || ' ' || 
                         to_char(v_step, 'FM999999990.0000') || ' : STEP' || E'\n';
        v_las_content := v_las_content || 'NULL . ' || v_null_value || ' : NULL VALUE' || E'\n';
        v_las_content := v_las_content || 'COMP . ' || (v_well_info->>'company') || ' : COMPANY' || E'\n';
        v_las_content := v_las_content || 'WELL . ' || (v_well_info->>'well_name') || ' : WELL' || E'\n';
        v_las_content := v_las_content || 'FLD  . ' || (v_well_info->>'field') || ' : FIELD' || E'\n';
        v_las_content := v_las_content || 'LOC  . ' || (v_well_info->>'location') || ' : LOCATION' || E'\n';
        v_las_content := v_las_content || 'PROV . ' || (v_well_info->>'province') || ' : PROVINCE' || E'\n';
        v_las_content := v_las_content || 'SRVC . ' || (v_well_info->>'service_company') || ' : SERVICE COMPANY' || E'\n';
        v_las_content := v_las_content || 'DATE . ' || (v_well_info->>'log_date') || ' : LOG DATE' || E'\n';
        v_las_content := v_las_content || 'UWI  . ' || (v_well_info->>'unique_well_id') || ' : UNIQUE WELL ID' || E'\n';
        v_las_content := v_las_content || E'\n';
        
        -- 3. Секция Curve Information
        v_las_content := v_las_content || '~CURVE INFORMATION' || E'\n';
        v_las_content := v_las_content || '#MNEM.UNIT      API CODE      CURVE DESCRIPTION' || E'\n';
        v_las_content := v_las_content || '#-----------     -----------  ------------------------------' || E'\n';
        
        -- Добавляем кривые из параметров
        FOR i IN 0..jsonb_array_length(v_curve_info)-1 LOOP
            DECLARE
                v_curve jsonb := v_curve_info->i;
            BEGIN
                v_las_content := v_las_content || 
                    rpad((v_curve->>'mnemonic')::text, 8) || '.' || 
                    rpad((v_curve->>'unit')::text, 8) || ' ' ||
                    rpad(COALESCE((v_curve->>'api_code')::text, ''), 12) || ' : ' || 
                    (v_curve->>'description')::text || E'\n';
            END;
        END LOOP;
        v_las_content := v_las_content || E'\n';
        
        -- 4. Секция Parameter Information (необязательная)
        IF a_parameters ? 'parameter_info' THEN
            v_las_content := v_las_content || '~PARAMETER INFORMATION' || E'\n';
            v_las_content := v_las_content || '#MNEM.UNIT      VALUE           DESCRIPTION' || E'\n';
            
            FOR i IN 0..jsonb_array_length(a_parameters->'parameter_info')-1 LOOP
                DECLARE
                    v_param jsonb := (a_parameters->'parameter_info')->i;
                BEGIN
                    v_las_content := v_las_content || 
                        rpad((v_param->>'mnemonic')::text, 8) || '.' || 
                        rpad(COALESCE((v_param->>'unit')::text, ''), 8) || ' ' ||
                        rpad((v_param->>'value')::text, 16) || ' : ' || 
                        (v_param->>'description')::text || E'\n';
                END;
            END LOOP;
            v_las_content := v_las_content || E'\n';
        END IF;
        
        -- 5. Секция данных (~A)
        v_las_content := v_las_content || '~A' || E'\n';
        
        -- Добавляем данные каротажа
        IF v_wrap_mode = 'NO' THEN
            -- Режим без переноса - одна строка на точку
            FOR i IN 0..jsonb_array_length(v_log_data)-1 LOOP
                DECLARE
                    v_data_point jsonb := v_log_data->i;
                    v_line text := '';
                BEGIN
                    -- Добавляем значения всех кривых для текущей глубины
                    FOR j IN 0..jsonb_array_length(v_curve_info)-1 LOOP
                        DECLARE
                            v_curve jsonb := v_curve_info->j;
                            v_mnemonic text := v_curve->>'mnemonic';
                            v_value text;
                        BEGIN
                            IF j > 0 THEN
                                v_line := v_line || ' ';
                            END IF;
                            
                            IF v_data_point ? v_mnemonic THEN
                                v_value := (v_data_point->>v_mnemonic)::text;
                            ELSE
                                v_value := v_null_value;
                            END IF;
                            
                            v_line := v_line || v_value;
                        END;
                    END LOOP;
                    
                    v_las_content := v_las_content || v_line || E'\n';
                END;
            END LOOP;
        ELSE
            -- Режим с переносом - сначала глубина, затем значения
            FOR i IN 0..jsonb_array_length(v_log_data)-1 LOOP
                DECLARE
                    v_data_point jsonb := v_log_data->i;
                    v_depth text := (v_data_point->>(v_curve_info->0->>'mnemonic'))::text;
                    v_line text := '';
                    v_values_per_line integer := 5; -- Количество значений в строке
                BEGIN
                    -- Строка с глубиной
                    v_las_content := v_las_content || v_depth || E'\n';
                    
                    -- Строки со значениями (по v_values_per_line значений в строке)
                    FOR j IN 1..jsonb_array_length(v_curve_info)-1 LOOP
                        DECLARE
                            v_curve jsonb := v_curve_info->j;
                            v_mnemonic text := v_curve->>'mnemonic';
                            v_value text;
                        BEGIN
                            IF (j-1) % v_values_per_line = 0 THEN
                                IF j > 1 THEN
                                    v_las_content := v_las_content || v_line || E'\n';
                                END IF;
                                v_line := '';
                            ELSE
                                v_line := v_line || ' ';
                            END IF;
                            
                            IF v_data_point ? v_mnemonic THEN
                                v_value := (v_data_point->>v_mnemonic)::text;
                            ELSE
                                v_value := v_null_value;
                            END IF;
                            
                            v_line := v_line || v_value;
                        END;
                    END LOOP;
                    
                    -- Добавляем последнюю строку значений
                    IF length(v_line) > 0 THEN
                        v_las_content := v_las_content || v_line || E'\n';
                    END IF;
                END;
            END LOOP;
        END IF;
        
        -- Возвращаем результат в формате LAS
        RETURN jsonb_build_object(
            'msg', 'ok', 
            'las_content', v_las_content,
            'las_format', 'LAS 2.1'
        );
        
    EXCEPTION
        WHEN OTHERS THEN
            -- Ошибка выполнения функции
            RAISE WARNING 'func_core_save_to_las: Ошибка (user_id: %): %', a_user_id, SQLERRM;
            RETURN jsonb_build_object(
                'msg', 'error',
                'error', 'Ошибка func_core_save_to_las: ' || SQLERRM
            );
    END;
    $BODY$;
    
    ALTER FUNCTION public.func_core_save_to_las(integer, jsonb)
        OWNER TO core;