Перенос БД с MySQL на Postgresql

Как то уже описывал в одном из постов, что в одной из инсталяций внедрял WordPress на основе БД PostreeSQL. И в принципе спустя год могу сказать что особых проблем пока не возникло. Кроме одного НО! Если требуется какой-то установить плагин, то чаще всего он просто так, без некоторой адаптации не заработает. Вот сейчас адаптирую плагин «WP Voting Contest Lite«, который можно использовать для «выбора лучшего фото» пользователями.

В данном случае столкнулся для начала с проблемой его установки. При активации он пытается создать, если отсутствуют таблицы:

  • wp_votes_tbl
  • wp_votes_post_contestant_track
  • wp_votes_custom_registeration_contestant
  • wp_votes_custom_field_contestant

В которых встречается имеющийся в MySQL, но отсутствующий в PostgreSQL тип ENUM. Ну чтож.. создадим эти типы «руками», благо такая возможность в PostgreSQL предусмотрена:

CREATE TYPE public.admin_only_enum AS ENUM ('Y','N');
CREATE TYPE public.grid_only_enum AS ENUM ('Y','N');
CREATE TYPE public.list_only_enum AS ENUM ('Y','N');	
CREATE TYPE public.pretty_view_enum AS ENUM ('Y','N');	
CREATE TYPE public.question_type_enum AS ENUM ('TEXT','TEXTAREA','MULTIPLE','SINGLE','DROPDOWN','FILE','DATE');	
CREATE TYPE public.required_enum AS ENUM ('Y','N');	
CREATE TYPE public.set_limit_enum AS ENUM ('Y','N');	
CREATE TYPE public.show_labels_enum AS ENUM ('Y','N');	

И далее создать таблицы по типу:

CREATE TABLE public.wp_votes_custom_registeration_contestant (
	id bigserial NOT NULL,
	"sequence" int4 NULL,
	question_type public.question_type_enum NULL,
	question text NULL,
	system_name varchar(45) NULL,
	response text NULL,
	required public.required_enum NULL,
	required_text text NULL,
	admin_only public.admin_only_enum NULL,
	delete_time varchar(45) NULL,
	react_val text NULL,
	wp_user int4 NULL,
	CONSTRAINT wp_votes_custom_registeration_contestant_pk PRIMARY KEY (id)
);

JavaScript: Еще один вариант загрузки файла по клику на кнопку

Общая идея следующая: по клику на кнопку вызываем AJAX запрос на сервер с определенными параметрами передаваемыми в POST, затем получив в результат запроса файл — формируем в DOM на файл в формате blob, и тут-же её нажимаем. В результате браузер показывает диалоговое окно сохранения файла.

Таким необычным способом мы убиваем несколько зайцев сразу:

  1. Получаем возможность показать ошибку, если вдруг файл на сервере сформировать не удалось. Это полезно если например файл формируется на сервере «на лету» — например файл XLSX с отчётом
  2. Мы можем передать серверу какие-то условия для формирования файла в POST запросе
  3. На странице мы не размещаем заранее данные в тегах <form></form>, как практикуется в подобных решениях
  4. Пользователю достаточно нажать на кнопку один раз для получения результата.

В результате скрипт формирования файла может выглядеть примерно следующим образом:

На клиенте:

/**
 * Формирование отчета
 * @param {type} filename - имя файла на сервере для формирования отчета
 * @param {type} ext - выходное расширение (например xlsx,csv)
 * @returns {Number}
 */
function get_report(filename,ext){
        $("#global").addClass("loading");    
        var xhr = new XMLHttpRequest();
        xhr.open('POST', '?r=reports/'+filename, true);
        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        xhr.responseType = 'blob';     
        xhr.onload = function(e) {
            $("#global").removeClass("loading");    
            if (this.status == 200) {
                var link=document.createElement('a');
                link.href=window.URL.createObjectURL(this.response);                
                console.log("Расширение:"+ext);
                link.download="report."+ext;
                link.click();
            }
            else {
                console.log(e);
                ToastMessage("error","Произошла ошибка при формировании файла. Попробуйте позднее или обратитесь к администратору системы.");
            }
        };     
        var form_data = new Map();
        form_data.period_from = period_from.value;
        form_data.period_to = period_to.value;
        form_data.area = area_select.value;
        form_data.division_check=division_check.checked;
        form_data.period_check=period_check.checked;
        xhr.send(mapToQueryString(form_data));                                          
};

На сервере:

    public function actionGet_report_by_settlers(){               
       $request = Yii::$app->request;      
       $area= $request->post("area");
       $dir=Yii::$app->basePath."/web/templates";
        
      $oSpreadsheet = IOFactory::load($dir . "/report_1_1.xlsx");
      ...
      формируем файл эксель
      ...
      $oWriter = IOFactory::createWriter($oSpreadsheet, 'Xlsx');
      $oWriter->save('php://output');      
    };

Консоль администрирования 1С под Linux

Перейдя с Windows на Linux, теряется возможность управлять сервером 1С Предприятие через консоль администрирования, через оснастку. Но! оказывается довольно давно уже в платформе зашита подобная же утилита, которая доступна через «Функции для технического специалиста»: Стандартные -> Управление серверами.

При запуске будет практически аналогичная функциональность доступная ранее через консоль:

Чтиво за последнее время

  1. Андрей Ланченко. Блуждающие огни 1-4. Краткий сюжет: земля на задворках, и оказывается она забытая колония. Программист Дима через портал попал на транспортный корабль колонистов. И понеслось (с). Читабельность 4/5
  2. Григорий Володин. Газлайтер 1-18. Классическое бояр-аниме. Попаданец в паралельный мир с магией и прочим. Там не было СССР и власть в руках дворян/царя. Читабельность 4/5
  3. Толкиню Хоббит. Властелин колец. Дочке не зашло, хотя прочитали примерно половину.
чтиво за последнее время

1С: Фоновые задания внутри фоновых заданий

Задача: распаралелить медленную вставку записей в БД 1С, при чтении файла Excel

Как ни странно, но такая возможность есть и работает начиная с версии платформы 8.3.8. Т.е. можно запустить фоновое задание внутри фонового задания….ну например по вставке в БД большого количества записей, которая выполняется весьма медленно. Полноценно этот процесс распаралелить можно например как-то так:

Функция СделатьЗаписьвБДПДЗФоново(парам) экспорт
	...
    // делаем медленную запись в БД
	...
конецфункции	

// Просматриваем массив с идентификаторами фоновых заданий и удаляем те которые завершились
Функция ПочиститьМассивОтЗавершенныхЗаданий(МассивФоновыхЗаданий) экспорт
		для каждого ФЗМ из МассивФоновыхЗаданий цикл
			ФЗ = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ФЗМ);
			если ФЗ.Состояние<>СостояниеФоновогоЗадания.Активно тогда
				МассивФоновыхЗаданий.Удалить(МассивФоновыхЗаданий.Найти(ФЗМ));
			конецесли;	
		конеццикла;		
	возврат МассивФоновыхЗаданий;
конецфункции		

// выполняем загрузку построчно файла Excel, запуская запись данных в БД
// отдельным потоком. Количество потоков ограничивам 10 штуками
Функция ВыполнитьЗагрузку(парам) экспорт
	МассивФоновыхЗаданий=Новый Массив();
	МаксимумЗаданий=10;
...
    Для	 нСтрокаТФ = 2 ПО КолВоСтрокФайла Цикл  
        ....
			МассивПараметров = Новый Массив;
			Параметры=Новый Структура("aa,bb,cc",
				1,
				2,
				3,
            );
			МассивПараметров.Добавить(Параметры);
			ФЗ = ФоновыеЗадания.Выполнить("ДлительныеОперации.СделатьЗаписьвБДПДЗФоново",МассивПараметров);	
			МассивФоновыхЗаданий.Добавить(ФЗ.УникальныйИдентификатор);											
			МассивФоновыхЗаданий=ПочиститьМассивОтЗавершенныхЗаданий(МассивФоновыхЗаданий);
			// ждём пока завершаться запущеные потоки, если их больше 10
			пока МассивФоновыхЗаданий.Количество()>МаксимумЗаданий цикл
				МассивФоновыхЗаданий=ПочиститьМассивОтЗавершенныхЗаданий(МассивФоновыхЗаданий);
			конеццикла;	        
        ....
   конеццикла;
конецфункции	   

В ниже приведённом каркасе кода, фоново выполняется функция ВыполнитьЗагрузку(), которая читает большой файл Excel, затем каждый цикл вставки записи в БД запускает в свою очередь фоново, ограничивая в данном случае количество фоновых заданий 10 штуками.