Форум » Для флейма » MiniGui + PostgreSQL » Ответить

MiniGui + PostgreSQL

Andrey: Кому будет интересно. https://habrahabr.ru/post/282764/

Ответов - 126, стр: 1 2 3 4 5 6 7 All

Andrey: Всем привет ! Кто то работает на МиниГуи с PostgreSQL ? Поделитесь опытом...

Dima: Andrey пишет: Кто то работает на МиниГуи с PostgreSQL ? Погугли... http://www.pctoledo.com.br/forum/viewtopic.php?f=45&t=14457

SergKis: Andrey пишет:Поделитесь опытом.. Примеры из contrib\hbpgsql\tests\*.* ты уже попробовал и классы (tpostgre.prg) для работы изучил ?

Andrey: SergKis пишет: Примеры из contrib\hbpgsql\tests\*.* ты уже попробовал и классы (tpostgre.prg) для работы изучил ? Примеры попробовал, работают. Классы пока изучаю...

Andrey: Сделал пример, работает.... Если база в инете и провайдер мудрит с портами, то пример на МиниГуи после сообщения об ошибке - вешается... И причем к базе очень долгоооо коннектится.... Можно ли как то проверить доступнось IP-адреса по определённому порту ? LetoDb отвечает корректно и быстрей ! Нет коннекта и всё тут !

Dima: Andrey Попробуй hb_inetConnect( cAddress, nPort )

Andrey: Dima пишет: Попробуй hb_inetConnect( cAddress, nPort ) xVal := hb_inetConnect( "хх.хх.хх.хх", 5432 ) MsgDebug( xVal ) Выдаёт такое сообщение:

Dima: [pre2] lResult := hb_inetInit() Инициализирует INET подсистему, возвращает .T. в случае успеха. Должна вызываться перед вызовами других INET функций ( в начале программы, например ). hb_inetCleanup() Освобождает ресурсы, занятые INET подсистемой. Ее надо вызывать в конце программы, использующей INET функции. [/pre2]

Andrey: Не помогло... lResult := hb_inetInit() -> .T. далее возвращает результат <pointer> ....

Dima: Примерно так [pre2] if hb_inetInit() hSocket := hb_inetCreate(2500) hb_inetConnectIP( "192.168.0.200",13,hSocket ) if hb_inetErrorCode( hSocket )==0 ret:=.t. else ret:=.f. endif hb_inetCleanup() endif [/pre2]

Andrey: Dima пишет: Примерно так Заработало ! Но опять возврат дурацкий... MsgDebug( hSocket , hb_inetErrorCode( hSocket ), ret ) <pointer>, -1, .f. Срабатывает через 2,5 сек. А если брать стандартный коннект: oServer := TPQServer():New(cHost, cDatabase, cUser, cPass,,schema) то ответ приходит через 25 сек. Спасибо БОЛЬШОЕ ДИМА !

PSP: Andrey пишет: Заработало ! Но опять возврат дурацкий... MsgDebug( hSocket , hb_inetErrorCode( hSocket ), ret ) <pointer>, -1, .f. Что дурацкого в нем?

Dima: Andrey пишет: Срабатывает через 2,5 сек. Dima пишет: hSocket := hb_inetCreate(2500) Ни о чем не говорит ? Поиграй с цифрой и добейся нормального коннекта. Цифра экспериментальная и я ее подбирал руками для LAN что работает через инет. Andrey пишет: А если брать стандартный коннект: oServer := TPQServer():New(cHost, cDatabase, cUser, cPass,,schema) Возможно в нем где то настраивается таймаут , надо смотреть. Andrey пишет: А если брать стандартный коннект: Его и надо юзать а не куй знает что Это тоже самое что пытаться проверить коннект к LETODB (или ADS) такой же методой с таймаутом в 1 секунду и потом удивляться полученному результату.

Andrey: PSP пишет: Что дурацкого в нем? MsgDebug( hSocket , hb_inetErrorCode( hSocket ), lResult ) hSocket возвращает <pointer> Что это такое ? Dima пишет: Его и надо юзать Понял.

Dima: Andrey пишет: Что это такое ? Смотри доку Александра Кресина , там все доступно описано. Andrey пишет: hSocket возвращает <pointer> Так и должно быть А ты ждал чего ?

PSP: Andrey, pointer - это указатель.

Andrey: PSP пишет: Andrey, pointer - это указатель.

Петр: Пользуясь свободной минутой и прости из любопытства скачал Postgre. Впечатления такие (о hbpgsql) SergKis пишет: классы (tpostgre.prg) для работы изучил ? Для роботы метод New класса TPQserver нуждается в допиливании. Хотя бы до такого вида New( cHost, cHostAddr, cDatabase, cUser, cPass, nPort, nTimeout, .. ) Andrey пишет: А если брать стандартный коннект: oServer := TPQServer():New(cHost, cDatabase, cUser, cPass,,schema) А почему порт не указываете явно ::New( cHost, cDatabase, cUser, cPass, nPort, Schema ) тогда б, возможно, не пришлось писать: Если база в инете и провайдер мудрит с портами, то пример на МиниГуи после сообщения об ошибке - вешается... И, на мой взгляд, стандартный коннект это PQconnectdb(conninfo). Как формировать строку conninfo можно почитать click here Хотелось бы обратить внимание Андрея на описании hostaddr Using hostaddr instead of host allows the application to avoid a host name look-up, which may be important in applications with time constraints. и connect_timeout Maximum wait for connection, in seconds (write as a decimal integer string). Zero or not specified means wait indefinitely. It is not recommended to use a timeout of less than 2 seconds. Почему-то в примерах везде используется только host (localhost), а connect_timeout вообще не используется. Из чего можно делать кое-какие предположения, но мы не будем :)

Andrey: Петр пишет: Для роботы метод New класса TPQserver нуждается в допиливании. Хотя бы до такого вида New( cHost, cHostAddr, cDatabase, cUser, cPass, nPort, nTimeout, .. ) Я обратил на это внимание. У себя сделал. А как это отразить изменение в классе для других ? Чтобы потом не тащить этот исправленный исходник к себе в проект. Петр пишет: А почему порт не указываете явно ::New( cHost, cDatabase, cUser, cPass, nPort, Schema ) Как было в примерах, так стал использовать у себя. И как добавить новую функцию для всех, чтобы сообщение об ошибках сервера приходило в кодировке RU1251 ? По умолчанию ошибки идут в кодировке UTF... Петр пишет: Как формировать строку conninfo можно почитать click here Спасибо БОЛЬШОЕ за наводку документации !

kia: Andrey пишет: Спасибо БОЛЬШОЕ за наводку документации ! Учитывая любовь Андрея к великому и могучему то тут все тоже самое на родном click here плюс есть еще сборки для виндовоза click here но под Linux сервером мороки значительно меньше

Петр: И как добавить новую функцию для всех, чтобы сообщение об ошибках сервера приходило в кодировке RU1251 ? По умолчанию ошибки идут в кодировке UTF... Зависит от настроек сервера. У меня на WIN7 в postgresql.sql можно найти # These settings are initialized by initdb, but they can be changed. lc_messages = 'Ukrainian_Ukraine.1251' # locale for system error message strings Создать универсальную функцию, наверное, не удастся. Можете переопределить метод ErrorMsg() и вообще любой другой метод класса TPQserver используя наследование, или напишите свой класс, что называется "с нуля". У себя сделал. А как это отразить изменение в классе для других ? Опять же, наследование при использовании классов - это, в общем случае, классика (масло масляное - :)). Кому нужно создаст свой класс. Но поскольку базовый класс сделан довольно таки топорно и если уж так хочется поделиться, то git push или через harbour devel-list

Andrey: У себя в проекте подсоединяю либы: -lminigui -lhbpgsql -llibpq Ехе-ник стартует только при наличии libeay32.dll и libpq.dll Как узнать версию libpq.dll (postgres version) который запускается вместе с моим ехе-ником ? Есть ли какая функция для этого ?

Haz: Andrey пишет: Как узнать версию libpq.dll (postgres version) который запускается вместе с моим ехе-ником ? Есть ли какая функция для этого ? Тупо использовать функцию поиска строки , версия DLL хранится внутри текстовой строкой расширенной меж буквами символом CHR(0) или дергать блок VersionInfo из ресурса DLL

Петр: Andrey пишет: Как узнать версию libpq.dll (postgres version) который запускается вместе с моим ехе-ником ? Есть ли какая функция для этого ? libpq version и postgres version - разные вещи postgres version можете определить вызвав PQServerVersion( pConn ) для определения версии libpq добавьте в postgres.c следующий код HB_FUNC( PQLIBVERSION ) { #if PG_VERSION_NUM >= 90100 hb_retni( PQlibVersion() ); #else hb_retni( 0 ); #endif } и пересоберите библиотеку hbpgsql

Andrey: Петр пишет: libpq version и postgres version - разные вещи Да я знаю про это. Петр пишет: для определения версии libpq добавьте в postgres.c следующий код Спасибо БОЛЬШОЕ ! Придётся пользоваться тогда только своей (исправленной) библиотекой.

Andrey: Что то не идёт сборка либы, выдает ошибку: Z:\Harbour SVN\contrib\hbpgsql>z:\HB32\BIN\hbmk2.exe hbpgsql.hbp hbmk2: Warning: Missing dependency: pgsql Подскажите пожалуйста, кто знает как собирать ?

Andrey: Очень удобная вещь - этот PostgreSQL !!! Принцип работы, как я понял также как в LetoDb. Делаешь коннект к базе и работаешь... Правда понятия отличны от Клипера/Харбора. Условно говоря в PostgreSQL такая связка: БД -> таблицы -> схемы (более детально смотрите сами). БД не такая как в Харборе: 1) между БД в PostgreSQL нет взаимодействия (или нужно ставить дополнение на сервере) 2) таблица в PostgreSQL соотвествует dbf-файлу Харбора Переход с DBF на PostgreSQL в принципе не сложный. TsBrowse работает с PostgreSQL, только надо его допиливать немного... Пока гоняю тестовый пример, как сделаю - поделюсь.

Dima: Andrey LetoDB чем не устроил ?

Andrey: Dima пишет: LetoDB чем не устроил ? Из-за отсутствие обратной связи в LetoDb c Сайтом. Не смог написать (найти кто сделает) LetoDb->Руби->LetoDb. C Андроидом тоже проблема. Как работать с LetoDb на нем - непонятно ? https://developer.android.com/studio/index.html Т.е. вообще бы хорошо иметь: 1) Исходник клиента для других компиляторов: C++ и C# 2) Или независимую DLL для работы с LetoDb на других языках 3) для Андроида тоже нужны переходники.

Dima: Andrey пишет: 3) для Андроида тоже нужны переходники. Для него если уже есть готовая прога есть протокол обмена , чем в данный момент и занимаюсь. Все решаемо.

Softlog86: Как запустить LETO на WWW-сервере (LInux) ? Хоцца достучаться до него через Интернет без всяких медиаторов ... (ТОже самое что написал Андрей чуть выше )

Andrey: Softlog86 пишет: Как запустить LETO на WWW-сервере (LInux) ? Хоцца достучаться до него через Интернет без всяких медиаторов ... Спокойно запускается. У меня работает. Смотри тему http://clipper.borda.ru/?1-7-0-00000022-000-10001-0 К нему подключаются с других городов, я сам тестировал из-за границы. Всё быстро, удобно. Мне очень нравиться. Dima пишет: Для него если уже есть готовая прога есть протокол обмена , чем в данный момент и занимаюсь. Все решаемо. У себя в проге обращаюсь поочередно к 2-м серверам: на CentOS и на Windows Server 2008. У меня тоже есть прога на Андроиде. Работает через сайт. Сайт считывает записи из LetoDb. Обратной связи нет. Сделал костыль через CVS-файлы, эти файлы Андроид кладёт в папку и через файловые функции LetoDb перегоняю в DBF (раз в 3-5 минуты). А уже потом просматриваю dbf на МиниГуи. Думаю, что через PostgreSQL буду получать данные напрямую в MiniGui + обратная связь будет, без таймера.

Andrey: Ну на до же, женщина кодит , да не просто так. A patch for libpgsql https://groups.google.com/forum/#!topic/harbour-devel/gfi5grka6jg Уважаю !!!

Dima: Andrey А что тут делает эта тема вообще ? Ей место в разделе выше ([x]Harbour) !

Петр: Dima пишет: А что тут делает эта тема вообще ? Тема эта вроде в флейме была с другим названием (чем PostgreSQL лучше..), потом переползла в GUI из-за упоминания MiniGUI, наверное. Лучше бы в флейме и осталась.

Andrey: Петр пишет: Тема эта вроде в флейме была с другим названием (чем PostgreSQL лучше..), потом переползла в GUI из-за упоминания MiniGUI, наверное. Лучше бы в флейме и осталась. Да нет эта тема задумывалась как переход на новые средства - МиниГуи + PostgreSQL

Andrey: Dima пишет: Ей место в разделе выше ([x]Harbour) ! Сделал тест для МиниГуи + PostgreSQL, копирование dbf-файла 13000 записей за 3 мин. Тормоза однако. Но это копирование записей в лоб: одна за другой. Искал варианты ускорения процесса.

Andrey: Петр пишет: и пересоберите библиотеку hbpgsql Что то не идёт сборка либы, выдает ошибку: Z:\Harbour SVN\contrib\hbpgsql>z:\HB32\BIN\hbmk2.exe hbpgsql.hbp hbmk2: Warning: Missing dependency: pgsql Подскажите пожалуйста, кто знает как собирать ?

Петр: Переменная HB_WITH_PGSQL определена? Почитайте README.md из поставки harbour

Dima: Andrey пишет: Да нет эта тема задумывалась как переход на новые средства - МиниГуи + PostgreSQL Тут гуем и не пахнет да и при чем он тут , гуй это "средство для наведения красоты" и ты снова путаешь теплое с мягким

PSP: Andrey пишет: Сделал тест для МиниГуи + PostgreSQL, копирование dbf-файла 13000 записей за 3 мин. Тормоза однако. Но это копирование записей в лоб: одна за другой. Искал варианты ускорения процесса. Андрюха, SQL никак не ускорит копирование файла. Это же ж Structured Query Language таки...)))

Andrey: PSP пишет: Андрюха, SQL никак не ускорит копирование файла. Это же ж Structured Query Language таки...))) Смотри Пост N: 5017 и читай по ссылке.

Andrey: Петр пишет: Почитайте README.md из поставки harbour Не ту у меня такого файла... Давно не обновлялся с CVS.

Петр: Andrey пишет: Давно не обновлялся с CVS Ну тогда открою великую тайну: harbour уже на git перешел..

PSP: Andrey пишет: Смотри Пост N: 5017 и читай по ссылке. И чё? "...in order to make the insertion of large portions of data into PostgreSQL faster..." Одна простая вещь: физическая среда передачи данных. Всё остальное вторично. Если эта самая large portions of data пролазит через физику с трудом, то никакой SQL тут не поможет. Пойми это. ps. nPreBuffer: автор подразумевает размер 1400 байт, чтобы был ниже стандартного MTU=1500 байт. Но, 1500 байт бывает только в случае соединения IPoE или в локальной сети. Все другие типы соединений имеют свой MTU. Это значит, что фрагментация пакетов будет в любом случае. Она там и пишет: "needs testing how libPQ is doing buffering by itself, and if this is needed?"

Andrey: Петр пишет: Ну тогда открою великую тайну: harbour уже на git перешел.. Спасибо ! Отстал я от жизни... Но там тоже нет доки https://github.com/harbour/core/tree/master/contrib/hbpgsql Понял, про какую доку... https://github.com/harbour/core/blob/master/README.md

Dima: вернул тему на место

Andrey: Разобрался со скоростью загрузки в базу для PostgeSql. Конвертор Dbf -> PostgeSql на MiniGui заработал ! База 18 Мб, 14 тыс.записей за 40 секунд всего - отправка ОДНИМ запросом. То что надо. LetoDb так же примерно качает, может чуть быстрей, только за 15-20 транзакций. Раньше было примерно 4 минуты. Читал что в PostgeSql можно одним запросом отправлять 1Gb. Пока ещё не проверял...

Dima: Andrey И в чем дело было ?

PSP: Andrey пишет: Читал что в PostgeSql можно одним запросом отправлять 1Gb. Пока ещё не проверял... К примеру, есть два канала: один - 10Миб/с, а второй 100Мбит/с. Как думаешь, одинаковое время будет затрачено на передачу пакета данных размером в 1Gb в обоих случаях? Может не стоит озвучивать цифры, зависящие от массы других факторов? Если на передачу тех же твоих 14тыс. записей через хреновый канал сотового оператора понадобится час, ты скажешь, что PostgeSQL - это отстой? Прости уж за сарказм)) LetoDb так же примерно качает, может чуть быстрей, только за 15-20 транзакций. Это только подтверждает, что всё упирается в физику.

Andrey: PSP пишет: Это только подтверждает, что всё упирается в физику. Да я не спорю с этим. Просто долго ковырялся с простым решением у себя в тестовом примере, пока не догадался как сделать. Dima пишет: Andrey И в чем дело было ? Делал как раньше на LetoDb - отправка по одной записи. Потом сделал (SergKis помог, без него бы не получилось!) отправку через транзакции. В PostgreSql сделал отправку всей базы ОДНОЙ транзакцией. Просто привыкнуть надо к Sql, работа с DBF это просто. Хотя дай поработать кто не работал с DBF, то для него будет много непоняток.

PSP: Andrey пишет: Да я не спорю с этим. Просто долго ковырялся с простым решением у себя в тестовом примере, пока не догадался как сделать. Ок, я тоже перегибаю)

Andrey: Хотелось бы иметь отдельный модуль postgres_aadd.c Чтобы не зависить от разработчиков contrib_hbpgsql, когда они ещё это сделают. В свой проект я добавил модуль: postgres_aadd.c ---------------- файл postgres_aadd.c ------------------ /* * Добавочный файл к postgres.c * Для определения версии libpq */ #include "hbapierr.h" #include "hbapiitm.h" HB_FUNC( PQLIBVERSION ) { //#if PG_VERSION_NUM >= 90100 hb_retni( PQlibVersion() ); //#else // hb_retni( 0 ); //#endif } ---------------- конец файла postgres_aadd.c --------------- Закоментировал строчки, т.к. всегда возвращается 0 Но потом не идёт компиляция моего проекта, ошибка: postgres_aadd.c: Turbo Incremental Link 5.66 Copyright (c) 1997-2002 Borland Error: Unresolved external '_PQlibVersion' referenced from .... hbmk2[dbf_to_PostgreSQL]: Error: Running linker. 2 Нашел в исходниках функцию: int PQlibVersion(void) { return PG_VERSION_NUM; } Помогите пожалуйста кто может - как подсоединить эту функцию ?

PSP: PG_VERSION_NUM поищи для начала.

Andrey: PSP пишет: PG_VERSION_NUM поищи для начала. Не нашёл... Где хоть искаь то ?

Pasha: Andrey пишет: Помогите пожалуйста кто может - как подсоединить эту функцию ? Наверное надо подключить файлы в начале модуля: #include "libpq-fe.h" #include "pg_config.h" А еще лучше #include "hbpgsql.h" в которм находятся соответствующий определения А саму функцию лучше написать так: #include "hbapi.h" #include "hbpgsql.h" HB_FUNC( PQLIBVERSION ) { hb_retni( PG_VERSION_NUM ); }

Петр: Pasha пишет: А саму функцию лучше написать так: Если Андрею дать грабли - он рано или поздно на них наступит.

Andrey: Петр пишет: Если Андрею дать грабли - он рано или поздно на них наступит. Не надо мне давать. Я и сам их найду ! Pasha пишет: А саму функцию лучше написать так: Спасибо ! Получилось. Только фигня получается. Эта функция возвращает 80408, т.е. номер библиотеки libpq.lib А мне надо было версию libpq.dll лежащий рядом с ехе-ником, через которую обращаюсь с сервером PostgreSql.

Петр: Andrey пишет: Только фигня получается. Не думал. что все получится так быстро (в смысле - грабли) А ну попробуйте это «[pre2]/* * IT IS IMPORTANT: in my case Postgres ver. 9.5.3 for Windows systems * was installed on local machine, port 5432 (default) */ #include "hbdyn.ch" PROCEDURE Main() LOCAL hLib LOCAL nVersion := 0 LOCAL cConnInfo LOCAL host := "localhost" LOCAL hostaddr := "127.0.0.1" LOCAL port := 5432 LOCAL connect_timeout := 10 ? PQlibVersion() ? hb_DynCall( { "PQlibVersion", "libpq.dll", HB_DYN_CTYPE_INT } ) //? hb_DynCall( { "PQlibVersion", "libpq_8.dll", HB_DYN_CTYPE_INT } ) hLib := hb_libLoad ( "libpq.dll" ) IF ! Empty( hLib ) nVersion := hb_DynCall( { "PQlibVersion", hLib, HB_DYN_CTYPE_INT } ) IF nVersion < 90100 ? "The function PQping() not supported." QUIT ENDIF // 1) !!databases!! is not valid word for ConnInfo cConnInfo := "host = localhost database = test" PingTest( cConnInfo, hLib ) // 2) the default port for Postgres is 5432, but we can try connect to port 3333 and see what is happen cConnInfo := "host = " + host + " port = " + "3333" PingTest( cConnInfo, hLib ) // 3) next attempt cConnInfo := hb_strFormat( "host = %1$s hostaddr = %2$s port = %3$d connect_timeout = %4$d", host, hostaddr, port, connect_timeout ) PingTest( cConnInfo, hLib ) hb_libFree( hLib ) ENDIF RETURN /*--- * */ STATIC PROCEDURE PingTest( c, hLib ) ? 'cConnInfo is "' + c + '"' ? "PQPing( cConnInfo ) returns ", GetPingResult( hb_DynCall( { "PQping", hLib, HB_DYN_CTYPE_INT }, c ) ) RETURN /*--- * */ STATIC FUNCTION GetPingResult( n ) LOCAL aMsg := ; { ; { "PQPING_OK", "(server is accepting connections)"}, ; { "PQPING_REJECT", "(server is alive but rejecting connections)"}, ; { "PQPING_NO_RESPONSE", "(could not establish connection)"}, ; { "PQPING_NO_ATTEMPT", "(connection not attempted (bad params))"} ; } IF n >= 0 .AND. n < Len( aMsg ) RETURN ( aMsg[ n + 1 ][ 1 ] + " " + aMsg[ n + 1 ][ 2 ] ) ENDIF RETURN "" #pragma BEGINDUMP #include "hbpgsql.h" HB_FUNC( PQLIBVERSION ) { hb_retni( PG_VERSION_NUM ); } #pragma ENDDUMP[/pre2]»

Andrey: Петр пишет: А ну попробуйте это Немного модифицировал под МиниГуи. Вот результат: 80408 90407 90407 cConnInfo is "host = localhost database = test" PQPing( cConnInfo ) returns PQPING_NO_ATTEMPT (connection not attempted (bad params)) cConnInfo is "host = localhost port = 3333" PQPing( cConnInfo ) returns PQPING_NO_RESPONSE (could not establish connection) cConnInfo is "host = localhost hostaddr = 127.0.0.1 port = 5432 connect_timeout = 10" PQPing( cConnInfo ) returns PQPING_NO_RESPONSE (could not establish connection) Я так понял, что для определения версии libpq.dll достаточно всего этой строчки (и и новой функции): ? hb_DynCall( { "PQlibVersion", "libpq.dll", HB_DYN_CTYPE_INT } ) ? А выгружать/убить после этой функции hb_DynCall() - не надо ? А то не пользовался такой функцией.

Петр: Все понятно: - hbpgsql из поставки MiniGUI; - вызов hb_DynCall( { "PQlibVersion", "libpq.dll", HB_DYN_CTYPE_INT } ) работает, пользуйтесь и помните о dll hell; - сервер где установлен непонятно, не пингуется на локальной машине и стандартном порте.

Петр: Andrey пишет: А выгружать/убить после этой функции hb_DynCall() - не надо ? Для вызова типа hb_DynCall( { "PQlibVersion", "libpq.dll", HB_DYN_CTYPE_INT } ) никого убивать не надо. hb_DynCall сама кого хошь убьет

Andrey: Петр пишет: - сервер где установлен непонятно, не пингуется на локальной машине и стандартном порте. Вот так: 80408 - 8.4.8 90407 - 9.4.7 90407 - 9.4.7 cConnInfo is "host = localhost database = test" PQPing( cConnInfo ) returns PQPING_NO_ATTEMPT (connection not attempted (bad params)) cConnInfo is "host = Serv-Test port = 3333" PQPing( cConnInfo ) returns PQPING_NO_ATTEMPT (connection not attempted (bad params)) cConnInfo is "host = Serv-Test hostaddr = 85.137.101.33 port = 5432 connect_timeout = 10" PQPing( cConnInfo ) returns PQPING_OK (server is accepting connections) Спасибо БОЛЬШОЕ Петр !

Andrey: Некоторые тесты сравнения LetoDb и PostgreSql. LetoDb - отправка по 1000 записей за 1 транзакцию, размер буфера транзакции равен 1 660 000 байт. PostgreSql - отправка всех записей за 1 транзакцию, размер буфера транзакции равен размеру файла. Система CentOS, 1Gb ОЗУ, 2Gb HDD ---------------------------------- Файл: 16 Мб, 20 полей, 10 000 записей LetoDb ver 2.15 - 15 транзакции, время копирования на сервер 00:04 (сек.) PostgreSql ver 9.4.7 - 1 транзакция, время копирования на сервер 00:08 (сек.) Файл: 158 Мб, 20 полей, 100 000 записей LetoDb ver 2.15 - 143 транзакции, время копирования на сервер 00:25 (сек.) PostgreSql ver 9.4.7 - 1 транзакция, время копирования на сервер НЕТ. Вылет по ошибке. Система Windows 2008 R2, 8Gb ОЗУ, 500Gb HDD ---------------------------------- Файл: 16 Мб, 20 полей, 10 000 записей LetoDb ver 2.15 - 15 транзакции, время копирования на сервер 00:04 (сек.) PostgreSql ver 9.4.7 - 1 транзакция, время копирования на сервер 00:08 (сек.) Файл: 158 Мб, 20 полей, 100 000 записей LetoDb ver 2.15 - 143 транзакции, время копирования на сервер 00:34 (сек.) PostgreSql ver 9.4.7 - 1 транзакция, время копирования на сервер 01:22 (сек.)

PSP: Andrey пишет: Некоторые тесты сравнения LetoDb и PostgreSql. Андрей, а скорость канала какая?

Andrey: 50-60 Мб.

PSP: Мне видится это так: когда передача идет порциями, сервер начинает записывать данные на диск по мере закрытия транзакций, не дожидаясь окончания передачи всех. В случае же, когда транзакция одна, сервер (postgre) сначала открывает новую транзакцию в журнале транзакций, накапливает ее (идет запись на диск), а потом, после закрытия клиентом, переписывает данные в основную базу (опять запись на диск). Т.е., идет интенсивное обращение к дисковой системе, растет время очереди диска. Получается, в этом примере postgre "уперся" в производительность диска. Андрей, интересно, какие будут результаты, если на postgre тоже передать кусками.

Петр: Andrey пишет: Система CentOS, 1Gb ОЗУ, 2Gb HDD Это характеристики сервера или клиента? Если сервера - то сервер транзитный, тестовый или рабочий? Кроме скорости копирования, ведь важна и сохранность данных. К сожалению, мы не видим кода и говорить что-то по теме тяжело. Andrey пишет: PostgreSql ver 9.4.7 - 1 транзакция, время копирования на сервер НЕТ. Вылет по ошибке. Что значит вылет - программа упала или что? Ошибка обрабатывалась? Несколько ссылок по теме, ИМХО Производительность приложений на основе PostgreSQL Транзакции и точки сохранения в PostgreSQL

Andrey: Петр пишет: Система CentOS, 1Gb ОЗУ, 2Gb HDD Это характеристики сервера или клиента? Если сервера - то сервер транзитный, тестовый или рабочий? Это сервер, рабочий - взят в аренду. Прекрасно работает уже лет 5. ЛетоДБ уже года три работает на нем. Поставил туда PostgreSQL для тестирования. Петр пишет: Что значит вылет - программа упала или что? Ошибка обрабатывалась? Ошибка не обрабатывалась. Программа упала при записи ОДНОЙ большой транзакции состоящей из 158 Мб (размер строки). Смотрел по логам, нехватка памяти для PostgreSQL. Т.е. нужно больше оперативки для PostgreSQL, а там всего 1Gb, свободно примерно 500Мб под работу. Это не особо важно, что упала программа. Самое главное что такие данные можно писать в PostgreSQL. Хотя реально такие большие данные сложно представить, да и оперативки сейчас много на серверах. Тесты делал для сравнения с ЛетоДБ и текущими задачами, которые делаю. Получается что ЛетоДБ шустрей будет в таких тестах. А дальше посмотрим. Код выложу, просто ещё тест не доделал до конца. Петр СПАСИБО за статьи !

Andrey: PSP пишет: Андрей, интересно, какие будут результаты, если на postgre тоже передать кусками. Да наверно это лучше будет и по скорости и сервер с маленькой памятью - падать не будет. -------------------- При старте программы открываю базу: conn := PQconnectdb( "dbname="+cDatabase+"host ="+cHost+"user="+cUser+"password = "+cPass+"port=5432" ) Как проверить доступность базы через час/два/и т.д. из программы ? Будет ли правильным следующий код: IF PQstatus( conn ) != CONNECTION_OK MsgStop( "Error connecting to server !") ELSE // запись в базу ! MsgLog(conn, VALTYPE(conn)) // возвращает ->'P' P что за тип такой ? ENDIF Читал про PQstatus здесь https://postgrespro.ru/docs/postgresql/9.5/libpq-status И как сделать PQreset при ошибке ?

Петр: Andrey пишет: MsgLog(conn, VALTYPE(conn)) // возвращает ->'P' P что за тип такой ? Andrey пишет: PSP пишет: цитата: Andrey, pointer - это указатель.

Петр: Andrey пишет: Будет ли правильным следующий код: В чем сомнения? Можно так написать [pre2] IF PQstatus( conn ) == CONNECTION_BAD PQreset( conn ) ENDIF IF PQstatus( conn ) == CONNECTION_OK // запись в базу ! ELSE MsgStop( "Error connecting to server !") ENDIF[/pre2]

Петр: Andrey пишет: Как проверить доступность базы через час/два/и т.д. из программы ? Умеете изъясняться высоким стилем.. из программы ? Программно используя libpq — библиотеку для языка C, hbpqsql — библиотеку для Harbour через час/два/и т.д. ? Используйте таймер. доступность базы? Нет в терминах postgree понятия доступность базы - есть доступность сервера (PQping) и статус соединения (PQstatus), есть PQsocket. После подтвержения статуса соединения можно получить имя базы, с которой установлено соединение (PQdb) В любом случае держать часами открытое соединение я бы не стал. Для периодических задач лучше проверить статус сервера и, в случае доступности, переустановить соединение.

Andrey: Петр пишет: В любом случае держать часами открытое соединение я бы не стал. Для периодических задач лучше проверить статус сервера и, в случае доступности, переустановить соединение. Спасибо ! Понял. Можно ли при получении данных с сервера: oQuery := oServer:Query( "SELECT * FROM " + cTable ) как то и куда то поставить - do events ? А то форма (в другом потоке) замирает и всё... Потом в исходнике tpostgre.prg надо бы исправить METHOD TableStruct( cTable ) CLASS TPQserver строка 344 и ниже, а так же добавить новые типы полей для Харбора : ELSEIF "timestamp" $ cType cType := "C" Как это сделать ? Писать в Github ?

Петр: Andrey пишет: Можно ли при получении данных с сервера: oQuery := oServer:Query( "SELECT * FROM " + cTable ) как то и куда то поставить - do events ? В существующем виде ответ - НЕТ Или перепишите/дополните hbpgsql ( в части см. подключение к серверу баз данных неблокирующим способом), или оптимизируйте ваш запрос, потому, что а) использование * вместо select_list в некоторых кругах считается плохим тоном ; б) обратите внимание на то, что указания LIMIT и OFFSET позволяют получить только часть строк из тех, что выдал остальной запрос Если и у вас в форме отображается 100 строк, зачем вам тащить 1000 (или того больше).

SergKis: Andrey пишет: Потом в исходнике tpostgre.prg надо бы исправить METHOD TableStruct( cTable ) CLASS TPQserver строка 344 и ниже, а так же добавить новые типы полей для Харбора : ELSEIF "timestamp" $ cType cType := "C" Как это сделать ? Писать в Github ? Можно сделать свой клас, наследованный от TPQserver, скопировать (в свой класс) и подправить как нужно METHOD TableStruct( cTable ) В программе вместо TPQserver использовать свой класс.

Петр: Andrey пишет: Как это сделать ? Писать в Github ? Кстати, с почином 2016-09-02 01:58 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com) * contrib/hbpgsql/hbpgsql.hbx * contrib/hbpgsql/postgres.c + add PQlibVersion() -> <nVersion> (returns 0 for pre-9.1 postresql versions) Ref: https://github.com/harbour/core/pull/127/ by @VerchenkoAG

Andrey: Петр пишет: Кстати, с почином Спасибо ! Буду дальше тогда предложения выкладывать... Пока использую библиотеку \MiniGUI\SOURCE\HbPgSql, там сам tpostgre.prg исправил, и очень хорошо и просто собирается libpq.lib - СПАСИБО БОЛЬШОЕ Григорию, об нас всех позаботился !!! В Харборе contrib_hbpgsql - так и не смог собрать. Столкнулся с такой непоняткой. Тестирую работу с базой при отрыве соединения. Т.е. база открыта в Tsbrowse, а потом я отключаю службу на сервере - Postgres. Ну типа внезапный обрыв соединения. После обрыва соединения проверяю доступность коннекта: ? "Ответ сервера при закрытии: ", PQstatus( oServer:pDb() ) IF PQstatus( oServer:pDb() ) == CONNECTION_OK oServer:Commit() ELSE ? "Ошибка сервера :", oServer:ErrorMsg() ENDIF oServer:Destroy() // убить объект Почему PQstatus( oServer:pDb() ) выдаёт 0 (т.е. CONNECTION_OK ) ? Что не так делаю ? А потом сваливается с ошибкой в tpostgre.prg Error BASE/2020 Неверный аргумент: PQRESULTSTATUS</p><BR> Called from PQRESULTSTATUS(0) Called from TPQSERVER:COMMIT(168) res := PQexec( ::pDB, "COMMIT" ) // Строка 167 lError := PQresultStatus( res ) != PGRES_COMMAND_OK // Строка 168 Как в исходнике убрать ошибку или не надо убирать ?

Петр: Andrey пишет: Что не так делаю ? Вам виднее Andrey пишет: А потом сваливается с ошибкой в tpostgre.prg Ошибка в postgres.c Andrey пишет: или не надо убирать ? Надо

Andrey: А как бы использовать функцию PQping у себя ? Или нужно как то затаскивать через те функции которые давали: hLib := hb_libLoad( "libpq.dll" ) ? GetPingResult( hb_DynCall( { "PQping", hLib, HB_DYN_CTYPE_CHAR }, c ) Неудобно уж очень. Подскажите (помогите) сделать пожалуйста эту функцию для tpostgre.prg из MiniGUI\SOURCE\HbPgSql Заранее огромное спасибо !

Петр: Andrey пишет: Подскажите (помогите) сделать пожалуйста эту функцию для tpostgre.prg из MiniGUI\SOURCE\HbPgSql скачайте архив #1 В архиве 2 пакетных файла: MakeLib.bat и to_95.bat Поместите их в MiniGUI\SOURCE\HbPgSql, заменив при этом оригинальный MakeLib.bat Запустите на выполнение to_95.bat В каталоге MiniGUI\SOURCE\HbPgSql будут созданы 2 каталога 8.4 и 9.5. Часть файлов будут перемещены в 8.4. Посмотрите как выглядит каталог 8.4. скачайте архив #2 Разместите файлы из архива в MiniGUI\SOURCE\HbPgSql\9.5. Структура каталога 9.5 должна напоминать структуру каталога 8.4 Откомпилируйте библиотеку hbpgsql (через MakeLib.bat) Убедитесь, что все компилируется нормально и библиотеки создаются.

Петр: Если все "хорошо", можете добавить нужную вам функциональность в postgres.c [pre2]HB_FUNC( PQPING ) { #if PG_VERSION_NUM >= 90100 if( HB_ISCHAR( 1 ) ) hb_retni( PQping( hb_parc( 1 ) ) ); else hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); #else hb_retni( 2 ); #endif }[/pre2] ну и пересобрать библиотеку, конечно.

Andrey: Петр пишет: ну и пересобрать библиотеку, конечно. Всё заработало ! Спасибо ОГРОМНОЕ !

Петр: Andrey пишет: Всё заработало ! ну и чудненько. Теперь можете попробовать убедить Григория внести изменения в MakeLib.bat и в структуру каталога HbPgSQL. Для совместимости можно оставить set PQ_VER=8.4 Andrey пишет: hLib := hb_libLoad( "libpq.dll" ) ? GetPingResult( hb_DynCall( { "PQping", hLib, HB_DYN_CTYPE_CHAR }, c ) Неудобно уж очень. Позвольте не согласиться. Вот так как вы изобразили - может быть, НО ЕСЛИ прописать где-то в tpostgre.prg FUNCTION _PQping( cConnInfo ) RETURN hb_DynCall( { "PQping", "libpq.dll", HB_DYN_CTYPE_INT }, cConnInfo ) или просто добавить в начале приложения (или в каком-то включаемом файле *.ch) строку #translate _PQPing( <cConnInfo> ) => hb_DynCall( { "PQping", "libpq.dll", HB_DYN_CTYPE_INT }, <cConnInfo> ) врядли вы сможете ощутить значительные неудобства при вызове _PQping( cConnInfo ) в сравнении с PQping( cConnInfo ). Уже знакомый вам пример (можно включить в поставку MiniGUI, хуже не будет ) P.S. в вашем случае переход на старшую версию вполне оправдан.

Andrey: Петр пишет: врядли вы сможете ощутить значительные неудобства при вызове _PQping( cConnInfo ) в сравнении с PQping( cConnInfo ). Я понял подход. Про это не подумал сразу. Спасибо ! Петр пишет: P.S. в вашем случае переход на старшую версию вполне оправдан. Спасибо ! Функция PQping() прекрасно ловит потерю связи с сервером, да и GetPingResult() тоже классная функция ! cStaticConnInfo := hb_strFormat( "hostaddr = %1$s port = %2$s connect_timeout = %3$s", cHost, cPort, cTimeout ) res := PQping( cStaticConnInfo ) // проверка доступности сервера IF res == PQPING_OK // можно работать с сервером ELSE cMsg := "Ошибка сервера: " + GetPingResult( res ) MsgStop(cMsg) ? cMsg ENDIF Пришлось внести изменения в postgres.ch: /* From libpq-fe.h * PGPing - The ordering of this enum should not be altered because the * values are exposed externally via pg_isready. For version 9 */ #define PQPING_OK 0 #define PQPING_REJECT 1 #define PQPING_NO_RESPONSE 2 #define PQPING_NO_ATTEMPT 3

Петр: Andrey пишет: Функция PQping() прекрасно ловит потерю связи с сервером это хорошо, НО Andrey пишет: res := PQexec( ::pDB, "COMMIT" ) // Строка 167 lError := PQresultStatus( res ) != PGRES_COMMAND_OK // Строка 168 Как в исходнике убрать ошибку или не надо убирать ? ошибку все равно убрать нужно

Andrey: Петр пишет: ошибку все равно убрать нужно Да не знаю как...

Andrey: Столкнулся с большой проблемой... Использую Tsbrowse по базе PostgreSQL - работает... Но происходит вылет(закрывается по ошибке) если нет открытого dbf-файла. По исходнику h_tbrowse.prg вылет происходит так: Error DBCMD/2001 Файл не открыт: ORDSETFOCUS Called from ORDSETFOCUS(0) Called from (b)TSBROWSE_SETDBF(11389) Called from TSBROWSE:NLOGICPOS(7320) Called from TSBROWSE:LBUTTONDOWN(6926) Called from TCONTROL:HANDLEEVENT(902) Called from TSBROWSE:HANDLEEVENT(7399) Called from EVENTS(79) Called from DOMESSAGELOOP(0) Called from _ACTIVATEWINDOW(1395) Called from DOMETHOD(4651) Called from FORM_PGSQL(167) Called from MYPGSQL(97) Вылет понятен, так как в исходнике ничего не прописано про PostgreSQL If "ADS" $ ::cDriver ... Else ::bTagOrder := {|uTag| ( cAlias )->( OrdSetFocus( uTag ) ) }, ; ::bGoToPos := {|n| Eval( ::bKeyNo, n ) } EndIf Как туда можно прикрутить PostgreSQL ?

SergKis: Andrey пишет: Но происходит вылет(закрывается по ошибке) если нет открытого dbf-файла. По исходнику h_tbrowse.prg вылет происходит так: Error DBCMD/2001 Файл не открыт: ORDSETFOCUS Так dbf или индекс не открыт ? Определись.

Andrey: На экране открываю 2 бровса. Второй с PostgreSQL. FUNCTION Form_PgSql() .... DEFINE TBROWSE oBrw2 ; .... MyCreateTable2(...) END TBROWSE .... STATIC FUNCTION MyCreateTable2(...) ... // создать первую колонку с номером в таблице ADD COLUMN TO oBrw2 HEADER "№№" ; DATA { || oQuery:RECNO() } ; ... // создать другие колонки PGLoadFields( "oBrw2", cForm, .T. ) ... Первое окно с Dbf закрываю. На экране остаётся второй Tsbrowse. Вот он и ломается ! Хотя переменные разные: oBrw1 и oBrw2

SergKis: Andreyпишет DEFINE TBROWSE oBrw2 ; хотелось уточнить что там дальше в ALIAS

Andrey: Ставлю проверку: cAlias := ::cAlias ::cDriver := ( ::cAlias )->( RddName() ) MsgDebug( cAlias, ::cDriver ) Выводит - DBF2TEST, DBFCDX Потом программа вылетает вот так: Error BASE/1003 Переменная не существует: OQUERY Called from (b)MYCREATETABLE2(225) Called from TSBROWSE:DRAWLINE(2942) Called from TSBROWSE:LBUTTONDOWN(6920) Called from TCONTROL:HANDLEEVENT(902) Called from TSBROWSE:HANDLEEVENT(7399) Called from EVENTS(79) Called from DOMESSAGELOOP(0) Called from _ACTIVATEWINDOW(1395) Called from DOMETHOD(4651) Called from MYTABLEDBF(107) Т.е. вот эта строка - ADD COLUMN TO oBrw2 HEADER "№№" ; DATA { || oQuery:RECNO() } ; ...

Dima: Andrey пишет: Error BASE/1003 Переменная не существует: OQUERY а она есть ?

Andrey: Dima пишет: а она есть ? Есть. Объект не удалял.

Haz: Andrey пишет: Есть. Объект не удалял. Весь код давай , а то тут все в угадайку играют

Dima: А если ее сделать не Private а Public и убрать Static у этой функции...

Andrey: Dima пишет: А если ее сделать не Private а Public и убрать Static у этой функции... Какая разница. Это же в тексте этого модуля происходить. Там кажись теряется весь объект oServer := TPQServer():NEW()

SergKis: Dima пишет А если ее сделать не Private а Public и убрать Static у этой функции... Не поможет, т.к. 1. алиас oBrw2 прицепился к алиасу oBrw1 2. блоки кодов управления заполнены на дбф (а здесь переменная объект запроса к постгрес) 3. Возможно надо исп. ole If Upper( uAlias:ClassName() ) == "TOLEAUTO" cAlias := "ADO_" ::oRSet := uAlias EndIf 4. Возможно проще обойтись массивом и как писап Петр ограниченным запросом LIMIT 100

Andrey: Нашёл в \hmg.3.4.3\SAMPLES\HFCL\SQL\POSTGRESQL_1\demo.prg такую строчку: nConnectionHandle := dbPGConnection( cServer + ";" + cDataBase + ";" + cUser + ";" + cPassWord ) CreateTable( cServer , cDataBase , cUser , cPassWord ) USE "SELECT * FROM test ;" ALIAS Test NEW VIA "pgrdd" CONNECTION nConnectionHandle Что за фокус такой, открывать "SELECT * FROM test ;" ?

Петр: Andrey пишет: Что за фокус такой, открывать "SELECT * FROM test ;" ? Андрей, скачайте, наконец, с помощью git сырцы harbour, посмотрите contrib rddsql/sddpg и не морочьте голову людям своими (чужими) строчками. По существу - это какое-то PGRDD (VIA "pgrdd"), скорее всего на базе RDDSQL, украшенное препроцессором

ММК: Andrey пишет: Что за фокус такой, открывать "SELECT * FROM test ;" ? Например с помощью ADO

Andrey: Блин, что за SQL такая непростая штука... Чтобы записать в базу несколько полей целые простыни писать приходиться.... Кому интересно (примерно так): [pre2] cMaska := 'UPDATE test SET "cnza"=?, "dtza"=?, "kmaster"=?, "qadres"=?, "qdop"=?, "qoborud"=?, "qneispr"=?, "qsrokza"=?, "qoperat"=?, "qvipza"=?, "kdate"=?, "kvipza"=?, "datesrok"=?, "datepere"=?, "rem"=?' aDim := HB_ATokens( cMaska, '?', .F., .F. ) cIdz := "'"+HB_NtoS(FIELD->IDZ)+"'" cDTDoc := "'" + TRANSFORM( DTOS(FIELD->DateDoc),"@R 9999-99-99" ) cDTDoc += " " + TRANSFORM(FIELD->TimeDoc,"@R 99:99") + ":00'" ..... IF FIELD->DATESROK == CTOD("") cDateSrok := "NULL" ELSE cDateSrok := "'" + TRANSFORM( DTOS( FIELD->DATESROK ),"@R 9999-99-99" ) + "'" ENDIF IF FIELD->DATEPERE == CTOD("") cDatePere := "NULL" ELSE cDatePere := "'" + TRANSFORM( DTOS( FIELD->DATEPERE ),"@R 9999-99-99" ) + "'" ENDIF cQuery := 'INSERT INTO "test" ("xid") VALUES (' + cIdz + ') ON CONFLICT("xid") DO NOTHING;' + CRLF cQuery += aDim[1] + "'"+ALLTRIM(TRANSFORM(FIELD->NNDOC,"99999/99"))+"'" cQuery += aDim[2] + cDTDoc // Дата + Время ввода документа ................... cQuery += aDim[13] + cDateSrok // cQuery += aDim[14] + cDatePere cQuery += aDim[15] + "'" + ALLTRIM(FIELD->MREM) + "'" // Примечание cQuery += ' WHERE "xid" = ' + cIdz + ';' cQuery := HB_STRTOUTF8( cQuery, "RU1251" ) // на сервер PgSql всегда делаем // вывести в журнал отладку cMsg := " Запись №: " + cIdz + CRLF res := PQping( M->cPubPgConnInfo ) // проверка доступности сервера IF res == PQPING_OK PQexec( oServer:pDB, "BEGIN" ) // oServer:StartTransaction() res := PQexec( oServer:pDB, cQuery ) nResultStatus := PQresultStatus( res ) M->oServer:cError := PQresultErrorMessage( res ) IF nResultStatus == PGRES_COMMAND_OK cMsg += "Результат: " + GetResultStatus( nResultStatus, 2 ) + CRLF + CRLF //WaitWindowOk(cMsg + CRLF) cErr := "Добавление строки: " + HB_UTF8TOSTR( oServer:ErrorMsg() ) + CRLF + CRLF cErr += "Запрос: " + HB_UTF8TOSTR( cQuery ) //HB_MemoWrit( ChangeFileExt( cFile, ".ok" ), cErr ) ELSE cMsg += "Результат: " + GetResultStatus( nResultStatus, 2 ) + " - " cMsg += GetResultStatus( nResultStatus, 3 ) + CRLF + CRLF WaitWindowError(cMsg + CRLF) cErr := "Ошибка добавления строки: " + HB_UTF8TOSTR( oServer:ErrorMsg() ) + CRLF + CRLF cErr += "Запрос, вызвавший ошибку: " + HB_UTF8TOSTR( cQuery ) HB_MemoWrit( ChangeFileExt( cFile, ".err" ), cErr ) ENDIF PQexec( oServer:pDB, "END" ) lRet := .t. ELSE lRet := .f. cMsg := "Ошибка сервера: " + GetPingResult( res ) cMsg += CRLF + "Запись с XID="+HB_NtoS(nIdz) + " не проведена !" ? cMsg WaitWindowError(cMsg) // вывести в журнал отладку cMsg := "Ошибка сервера: " + GetPingResult( res ) cMsg += CRLF + "Запись с XID="+HB_NtoS(nIdz)+" не проведена !" cMsg += " -> Oператор: " + HB_NtoS(M->nOperat) ENDIF[/pre2]

Vlad04: Andrey Блин, что за SQL такая непростая штука... Чтобы записать в базу несколько полей Харбоур на SQL и не ориентирован. Вот пример запроса на обновление, на отбор данных. Строится с помощью построителя Обновление PARAMETERS SourceId Long, DestId Long; INSERT INTO DocAdd ( KOD, SCHET1, SCHET2, AmortSum, Skl, KOL2, Norma, BalSt, OBECT1, golov, id ) SELECT DocAdd.KOD, DocAdd.SCHET1, DocAdd.SCHET2, DocAdd.NDS, DocAdd.Skl, DocAdd.KOL, DocAdd.Price, DocAdd.SUMMA, DocAdd.OBECT1, DocAdd.golov, [DestId] AS Выражение1 FROM DocAdd WHERE (((DocAdd.id)=[SourceId])); ВЫборка SELECT treb.SCHET1, Sum(treb.SUMMA) AS Summa, treb.SCHET2, Org.REMNAME AS Org FROM PubVar, Org INNER JOIN treb ON Org.NPP = treb.Org2 WHERE (((treb.SCHET1) Like [PubVar].[Sch]) AND ((treb.SCHET2) Like [PubVar].[SchK]) AND ((treb.DATA) Between [PubVar].[NData] And [PubVar].[EData])) GROUP BY treb.SCHET1, treb.SCHET2, Org.REMNAME;

SergKis: Andrey пишет целые простыни писать приходиться.... кто мешает сделать как то так [pre2] Func SqlData( dD, cT ) Local cRet := "NULL" If empty(dD); RETURN cRet EndIf cRet := TRANSFORM( DTOS(dD),"@R 9999-99-99" ) If !Empty(cT); cRet += TRANSFORM(cT,"@R 99:99") + ":00'" EndIf RETURN cRet для др. типов данных так же сделать преобразовани для команды sql Func SqlExec( cQuery, cMsg ) Local ... // сам определишь res := PQping( M->cPubPgConnInfo ) // проверка доступности сервера IF res == PQPING_OK PQexec( oServer:pDB, "BEGIN" ) // oServer:StartTransaction() res := PQexec( oServer:pDB, cQuery ) nResultStatus := PQresultStatus( res ) M->oServer:cError := PQresultErrorMessage( res ) IF nResultStatus == PGRES_COMMAND_OK cMsg += "Результат: " + GetResultStatus( nResultStatus, 2 ) + CRLF + CRLF //WaitWindowOk(cMsg + CRLF) cErr := "Добавление строки: " + HB_UTF8TOSTR( oServer:ErrorMsg() ) + CRLF + CRLF cErr += "Запрос: " + HB_UTF8TOSTR( cQuery ) //HB_MemoWrit( ChangeFileExt( cFile, ".ok" ), cErr ) ELSE cMsg += "Результат: " + GetResultStatus( nResultStatus, 2 ) + " - " cMsg += GetResultStatus( nResultStatus, 3 ) + CRLF + CRLF WaitWindowError(cMsg + CRLF) cErr := "Ошибка добавления строки: " + HB_UTF8TOSTR( oServer:ErrorMsg() ) + CRLF + CRLF cErr += "Запрос, вызвавший ошибку: " + HB_UTF8TOSTR( cQuery ) HB_MemoWrit( ChangeFileExt( cFile, ".err" ), cErr ) ENDIF PQexec( oServer:pDB, "END" ) lRet := .t. ELSE lRet := .f. cMsg := "Ошибка сервера: " + GetPingResult( res ) cMsg += CRLF + "Запись с XID="+HB_NtoS(nIdz) + " не проведена !" ? cMsg WaitWindowError(cMsg) // вывести в журнал отладку cMsg := "Ошибка сервера: " + GetPingResult( res ) cMsg += CRLF + "Запись с XID="+HB_NtoS(nIdz)+" не проведена !" cMsg += " -> Oператор: " + HB_NtoS(M->nOperat) ENDIF Retrun и твой набор команд сократиться. Еще делаем шаблоны sql команд и hash с блоками кодов для получения значений полей табл.: hBlock := {"^01" => {|| ...}, ; "^02" => {|| ...}, ; ... ; } cMaska := '"cnza"=^01, "dtza"=^02, "kmaster"=^03, "qadres"=^04, "qdop"=^05, "qoborud"=^06, "qneispr"=^07, "qsrokza"=^08, "qoperat"=^09, "qvipza"=^10, "kdate"=^11, "kvipza"=^12, "datesrok"=^13, "datepere"=^13, "rem"=^15' aDim := HB_ATokens( cMaska, ',') aOut := {} For i := 1 To len(aDim) a := HB_ATokens(aDim[ i ], "=") b := hb_HGetDef(nBlock, a[ i ][2], Nil) If hb_IsBlock(b) s := EVal(b) // возврат всегда строка If len(s) > 0; AAdd(aOut, a[ i ][1]+"="+s // есть резултат (длина > 0) EndIf EndIf Next cQuery := 'UPDATE test SET ' k := len(aOut) For i := 1 To k; cQuery += aOut[ i ] + iif( i < k, ", ", "" ) Next ? cQuery [/pre2] Это схема, а не отлаженный код.

Andrey: SergKis пишет: кто мешает сделать как то так Да я только начал с синтаксисом разбираться. Идея отличная. Буду впоследствии так и делать. Спасибо !

Vlad04: Буду впоследствии так и делать. Лучше в построителе строить запрос с ПАРАМЕТРАМИ. Они (построители) для Postgres то же есть. Строишь запрос, проверяешь , а потом одну (всего одну строку) , возможно длинную, копируешь в свою программу. Добавляешь передачу параметров и все ок

Andrey: Vlad04 пишет: Лучше в построителе строить запрос с ПАРАМЕТРАМИ. Они (построители) для Postgres то же есть. Я его ещё в глаза не видел. Где его смотреть ?

SergKis: Vlad04 пишет Лучше в построителе строить С формы ввода (изменено несколько Getbox данных) перегонять на сервер всю запись, можно, но ... можно гнать только реально измененные значения, создав sql команду на лету (как показано выше)

Vlad04: Andrey Я его ещё в глаза не видел. Самый доступный посмотреть, это в MSACCESS. Для Postgres то же есть, поищи в Интернете. SergKis Да все возможно.Это хорошо, когда есть варианты.

Andrey: Запускаю свою прогу на МиниГуи + PgSql на ХР (libpq.dll от версии 9.5 и соответственно libpq.lib этой версии) Требует intl.dll при запуске. Добавил его и ещё libeay32.dll + ssleay32.dll Далее требует msvcr120.dll Нашёл сайте Майкрософт vcredist_x86.exe 2012 года Поддерживаемая операционная система Windows 7 Service Pack 1; Windows 8; Windows 8.1; Windows Server 2003; Windows Server 2008 R2 SP1; Windows Server 2008 Service Pack 2; Windows Server 2012; Windows Vista Service Pack 2; Windows XP Установил его в ХР, всё равно не работает программа, не запускается !!! Под 7-кой приложение нормально запускается. Вопрос: как запустить под ХР ????

Pasha: Наверное, надо установить msvc runtime соответствующей версии. Какой - не знаю. Выдал у себя команду: dir/s msvcr*.dll >e:\msv.txt нашлось много чего: Содержимое папки C:\Windows\System32 01.10.2012 21:30 829 264 msvcr100.dll 11.09.2013 19:39 18 000 msvcr100_clr0400.dll 05.11.2012 23:26 849 360 msvcr110.dll 11.09.2013 19:39 855 664 msvcr110_clr0400.dll 24.07.2014 23:47 869 544 msvcr120_clr0400.dll 16.12.2011 11:46 634 880 msvcrt.dll 6 файлов 4 056 712 байт Содержимое папки C:\Windows\SysWOW64 13.06.2014 10:23 773 968 msvcr100.dll 11.09.2013 21:21 18 000 msvcr100_clr0400.dll 06.11.2012 02:20 875 472 msvcr110.dll 11.09.2013 21:21 863 344 msvcr110_clr0400.dll 25.07.2014 02:35 875 688 msvcr120_clr0400.dll 18.03.2002 16:01 344 064 msvcr70.dll 21.02.2003 15:42 348 160 msvcr71.dll 16.12.2011 10:52 690 688 msvcrt.dll 14.07.2009 04:15 253 952 msvcrt20.dll 14.07.2009 04:07 60 928 msvcrt40.dll 10 файлов 5 104 264 байт это все для разных версий msvc, многие продукты требуют для работы свою версию. Ну и традиционное общее замечание: Невозможно писать программу на "МиниГуи + PgSql" Можно писать на Harbour + bcc или скажем mingw, и использовать какие-то дополнительные библиотеки, те же minugui и hbpqsql.

Dima: Andrey Отсюда бери https://rutracker.org/forum/viewtopic.php?t=4594892

Andrey: Pasha пишет: Наверное, надо установить msvc runtime соответствующей версии. Какой - не знаю. Это точно так. Я понял, что здесь собака и зарыта. Методом проб и ошибок нашёл что нужно для XP чтобы прога "Harbour + bcc + minugui + hbpqsql" заработала. Нужно в систему ставить Microsoft Visual C++ 2013 Redistributable (x86) 12.0.30501 - 6,3Mb всего. После этого прога в ХР заработала.... Блин и как теперь можно сделать замену этого малопонятного окна у себя в программе ?

Петр: Andrey пишет: Блин и как теперь можно сделать замену этого малопонятного окна у себя в программе ? Чтоб сделать замену именно этого придется немало поучиться С другой стороны ничто не мешает проверить наличие установленной версии MS runtime Примерно во так как здесь Detect if Visual C++ Redistributable for Visual Studio 2013 is installed

SergKis: Andrey перепиши все нужные dll из vc к своему exe и так устанавливай. А что у кого (версии ms) стоит\нет - не всегда поможет решить проблемму, то админа нет, то прав и т.д.

Andrey: Петр пишет: С другой стороны ничто не мешает проверить наличие установленной версии MS runtime Да делал такое уже один раз в своём почтовике. Ехе-ник проверял Redistributable for Visual Studio 2008 если нет, то давал возможность ставить его по ссылке с сайта, а если есть, то выгружал из своих ресурсов второй ехе-ник, уже отправляющий почту. Люблю проги из одного ехе-ника ! Девиз: всё своё ношу с собой !

Andrey: Для работы PostgreSql на МиниГуи в проект добавляю следующие библиотеки: [pre2]# extension *.Lib PostgreSQL -lhbpgsql -llibpq[/pre2] Для работы ехе-ника необходимы 4 dll-ки: libpq.dll (версии 9.5) intl.dll libeay32.dll ssleay32.dll Можно как то отказаться от intl.dll чтобы далее не требовалась msvcr120.dll, т.е. обойтись без Microsoft Visual C++ 2013 Redistributable (x86) 12.0.30501 ?

Петр: Chapter 16. Installation from Source Code 16.7.4. MinGW/Native Windows

Andrey: Всем привет ! Имею такой код отправки на сервер: [pre2] res := PQping( M->cPubPgConnInfo ) // проверка доступности сервера IF res == PQPING_OK PQexec( oServer:pDB, "BEGIN" ) // oServer:StartTransaction() res := PQexec( oServer:pDB, cQuery ) nResultStatus := PQresultStatus( res ) // строка 657 M->oServer:cError := PQresultErrorMessage( res ) IF nResultStatus == PGRES_COMMAND_OK cMsg += "Результат: " + GetResultStatus( nResultStatus, 2 ) + CRLF + CRLF //WaitWindowOk(cMsg + CRLF) cErr := "Добавление строки: " + HB_UTF8TOSTR( oServer:ErrorMsg() ) + CRLF + CRLF cErr += "Запрос: " + HB_UTF8TOSTR( cQuery ) //HB_MemoWrit( ChangeFileExt( cFile, ".ok" ), cErr ) ELSE cMsg += "Результат: " + GetResultStatus( nResultStatus, 2 ) + " - " cMsg += GetResultStatus( nResultStatus, 3 ) + CRLF + CRLF WaitWindowError(cMsg + CRLF) cErr := "Ошибка добавления строки: " + HB_UTF8TOSTR( oServer:ErrorMsg() ) + CRLF + CRLF cErr += "Запрос, вызвавший ошибку: " + HB_UTF8TOSTR( cQuery ) HB_MemoWrit( ChangeFileExt( cFile, ".err" ), cErr ) ENDIF PQexec( oServer:pDB, "END" ) lRet := .t. ELSE lRet := .f. cMsg := "Ошибка сервера: " + GetPingResult( res ) cMsg += CRLF + "Запись с XID="+HB_NtoS(nIdz) + " не проведена !" ? cMsg WaitWindowError(cMsg) // вывести в журнал отладку cMsg := "Ошибка сервера: " + GetPingResult( res ) cMsg += CRLF + "Запись с XID="+HB_NtoS(nIdz)+" не проведена !" [/pre2] Периодически у ОДНОГО заказчика (другие не жаловались) вылетает прога с такой ошибкой: Судя по коду - ошибка в С-функции... Как исправить это ? Почему только у одного заказчика вылетает ( Операционка Win7) ?

Петр: Andrey пишет: Как исправить это ? все функции проверять на код возврата, тогда и вопросов меньше будет. Andrey пишет: Почему только у одного заказчика вылетает Странно, что у всех работает У этого банально может сеть глючить. Andrey пишет: Судя по коду - ошибка в С-функции... там же написано - неверный аргумент. все функции проверять на код возврата, по возможности применять async api

Andrey: Петр пишет: все функции проверять на код возврата, по возможности применять async api Подскажи пожалуйста как это сделать правильно ? А то сомневаюсь я что сделаю правильно.

Петр: Andrey пишет: Подскажи пожалуйста как это сделать правильно ? А то сомневаюсь я что сделаю правильно. Во-первых извините за задержку с ответом, не всегда есть время отвечать. Во-вторых, чего непонятного я написал? Каждая функция возвращает результат и желательно (а иногда и просто необходимо) его проверить на допустимость перед тем как передавать на обработку в другую функцию. В случае связки клиент-сервер такую проверку нужно проводить всегда, если не хотите терять данные.

Петр: Andrey пишет: [pre2] 1)res := PQping( M->cPubPgConnInfo ) // проверка доступности сервера 2)IF res == PQPING_OK 3) PQexec( oServer:pDB, "BEGIN" ) // oServer:StartTransaction() 4) res := PQexec( oServer:pDB, cQuery ) 5) nResultStatus := PQresultStatus( res ) // строка 657 и т.д.[/pre2] Вы же проверки делаете через раз и проверки делаете формально. В строке 1) проверка вроде есть, допустим сервер пингуется. Но в строке 3) перед вызовом PQexec состояние соединения (PQstatus) не определяется, после вызова состояние результата (PQresultStatus) игнорируется, состояние транзакции (PQTransactionStatus) игнорируется. В строке 5) проводится проверка, но она приводит к плачевным результатам (плачевным для существуюшей реализации, но относительно корректным вообще), потому, что игнорируется возможный результат возврата функции PQexec() и поведение функции PQresultStatus(). Корректная проверка должна выглядеть как-то так [pre2] res := PQexec( oServer:pDB, cQuery ) if Empty( res ) nResultStatus := PGRES_FATAL_ERROR else nResultStatus := PQresultStatus( res ) endif [/pre2] или в более компактной версии nResultStatus := if( Empty( res ), PGRES_FATAL_ERROR, PQresultStatus( res ) )

Петр: Чтобы меньше букафф писать и исходя из описания The PQresultStatus function should be called to check the return value for any errors (including the value of a null pointer, in which case it will return PGRES_FATAL_ERROR). функция [pre2] HB_FUNC( PQRESULTSTATUS ) { PGresult * res = hb_PGresult_par( 1 ); if( res ) hb_retni( PQresultStatus( res ) ); else hb_errRT_BASE( EG_ARG, 2020, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } [/pre2] может быть реализована так [pre2] HB_FUNC( PQRESULTSTATUS ) { PGresult * res = hb_PGresult_par( 1 ); hb_retni( PQresultStatus( res ) ); } [/pre2] напишите разработчикам (Виктору)

Andrey: Петр СПАСИБО БОЛЬШОЕ !

Andrey: Переделал проверку. Всё прекрасно работает у всех. Только у одного (у этого же клиента, про которого писал ранее) периодически вешается программа 3-4 раза в день. Ошибка отправки - вот лог: [pre2]Результат: PGRES_FATAL_ERROR - сбой запроса Ошибка добавления строки: server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request. Запрос, вызвавший ошибку: INSERT INTO ......[/pre2] Странная ошибка очень... И только у одного клиента. И почему вешается программа после отправки (или во время следующей отправки) ?



полная версия страницы