PostgreSQL: возврат функцией таблицы

Задача: вызываемая функция должна вернуть таблицу.

Решение:

DROP FUNCTION get_count_np_by_ls(date,bigint,bigint,boolean); 

CREATE OR REPLACE FUNCTION public.get_count_np_by_ls(pr date, porog1 bigint, porog2 bigint, epd boolean)
 RETURNS TABLE(name character varying, cnt numeric)
 LANGUAGE plpgsql
AS $function$
	BEGIN	
       if epd=true then
		return QUERY
					select
						arname as brname,
						sum(acnt) as gcnt 
					 from (
					select * from ( 
					SELECT 
						areas.name as arname,
						count(*) as acnt
					FROM public.posting_addresses
					inner join ls_addresses on ls_addresses.ls=posting_addresses.ls and ls_addresses.address_type=1 and ls_addresses.area between 1 and 26
					inner join areas on areas.id=ls_addresses.area
					inner join ls on ls.id=posting_addresses.ls
					where 
						posting_addresses.period=pr and 
						ls.dt_cancel_epd_bill<=pr  
						group by areas.name,ls_addresses.city,ls_addresses.settler) as zx 
					where 
						zx.acnt between porog1 and porog2
					) as res
					group by brname;
		else
		return QUERY
					select
						arname as brname,
						sum(acnt) as gcnt 
					 from (
					select * from ( 
					SELECT 
						areas.name as arname,
						count(*) as acnt
					FROM public.posting_addresses
					inner join ls_addresses on ls_addresses.ls=posting_addresses.ls and ls_addresses.address_type=1 and ls_addresses.area between 1 and 26
					inner join areas on areas.id=ls_addresses.area
					inner join ls on ls.id=posting_addresses.ls
					where 
						posting_addresses.period=pr 
						group by areas.name,ls_addresses.city,ls_addresses.settler) as zx 
					where 
						zx.acnt between porog1 and porog2
					) as res
					group by brname;
		end if;
	END;	
$function$
;

Вызывается так:

SELECT * from get_count_np_by_ls('2026-05-01',1,1,true)

Внимание! Частой ошибкой является вызов select get_count_np_by_ls(‘2026-05-01’,1,1,true). В этом случае столбцы «схлопываются» в один

Linux: Запись в файл после его удаления

В Linux есть такая особенность: если например удалишь физически файл ну например лога какого то домена, в то время как демон запущен, запись на диск демоном будет продолжена, а сам файл вы уже не увидите до перезапуска службы. Это не всегда удобно. Способ решения:

cat /dev/null > /var/log/myapp.log

Т.е. очистить файл, не меняя его дискриптора.

НСПК: Подпись сообщения из консоли Linux

Задача: подписать и отправить сообщение в НСПК посредством Linux

Решение:

1. Записываем json в файл и преобразуем его в формат base64:

echo '{"ogrn":"123","phone":"+79212349599","email":"gr@vesk.ru"}' | base64 -w 0 >for_sign.txt

2. Формируем файл подписи:

/opt/cprocsp/bin/amd64/cryptcp -sign -cadesbes -detached -thumbprint "каукаукацукацук" for_sign.txt -nostampcert

3. Формируем команду curl:

#!/usr/bin/bash
curl -X POST http://localhost:3070/v1/legal-profiles \
   -H 'Content-Type: application/json' \
   -H 'HOST:  rtptst-sandbox.nspk.ru' \
   -H 'x-sign:MIAGCSserfserNzI4WjAvBgkqhkiG9w0BCQQxIgQgqloyI8OYFTCgEgyK812e88X9zkKfq1PeWDdcc/Ay7sAwgeMGCyqGSIb3DQEJEAIvMYHTMIHQMIHNMIHKMAoGCCqFAwcBAQICBCA9jxTZxSMi6HWaxAyK3V48uIE0egiIBMqTA/s3ykB+SzCBmTCBhKSBgTB/MR0wGwYDVQQDDBRJbmZerfAAAAAAA==' \
   -d '{"ogrn":"123","phone":"+79212349599","email":"gr@vesk.ru"}'

НСПК: Выпуск туннельного и сертификата для подписи

Для работы с НСПК необходимо два сертификата: один для установки зашифрованного туннеля (например при помощи stunnel), а второй непосредственно для подписи сообщений передаваемых по этому туннелю. Сам процесс выпуска заключается в следующих шагах:

  1. В лк https://mircerts.nspk.ru создается заявка на сертификат
  2. Каким-то образом создается файл заявки на выпуск сертификата и подгружается в лк. В момент создания заявки создаётся закрытый ключ
  3. После выпуска сертификата появляется возможность его скачать в лк и установить

Первоначально п.2 я сделал при помощи утилиты Linux xca, еще и радуясь при этом, что закрытый ключ остался в виде файла, и не нужно его специальными утилитами вытаскивать с токена. Но радость была не долгой — выпущеный в конечном итоге таким образом сертификат отлично работал, подписывать сообщения можно было без проблем. Одно но: только при помощи утилиты openssl. А Крипто-про с таким сертификатом не дружит от слова совсем. Т.е. не реализовать подписание в 1С и не поднять туннель при помощи stunnel. Пришлось таки воспользоваться утилитами windows. Для этого создается регистрационный inf файл вида:

Для туннельного сертификата:

[NewRequest]
Subject = "CN=ROGA, O=ROGA, C=RU, OU = SP12345, ST=Vologda Lenina 1, L=Vologda"
Exportable = TRUE
KeyLength = 512
ProviderType=80
ProviderName = "Crypto-Pro GOST R 34.10-2012 Cryptographic Service Provider"
KeySpec = 1
KeyUsage = 0xf0
MachineKeySet = FALSE

Для сертификата для подписи:

[NewRequest]
Subject = "CN=SignRTP, O=ROGA, C=RU, OU = SP12345, ST=Vologda Lenina 1, L=Vologda"
Exportable = TRUE
KeyLength = 512
ProviderType=80
ProviderName = "Crypto-Pro GOST R 34.10-2012 Cryptographic Service Provider"
KeySpec = 1
KeyUsage = 0xf0
MachineKeySet = FALSE

Далее создаем контейнер и закрытый ключ, отдельно для каждого сертификата:

certreq -new req.inf request_cp.req

Полученный файл загружаем в ЛК и ждём выпуска сертификата. После чего скачиваем его и устанавливаем. Тем самым создавая пару закрытый ключ-сертификат на токене. А дальше уже стандартные пляски с выгрузкой с токена в файл при помощи P12FromGostCSP

НСПК: Подпись файла тестовым сертификатом для подписи

Для начала нужно получить закрытый ключ в формате, который может прочитать openssl. Для этого из утилиты xca, экспортируем ключ в формате p12:

Далее извлекаем закрытый ключ:

openssl pkcs12 -in SignRTP.p12 -nocerts -nodes -out p1.pem

Подписывать можно командой вида:

openssl dgst -engine gost -md_gost12_256 -binary -sign p1.pem 1.txt | base64

1 2 3 61