Архив рубрики: Статьи Руденко Олега

Прерывания цикла LOOP

ОАР>> Ну кто-же использует в Виндах обычные циклы для обработки
ОАР>> больших массивов данных?!

ВД> А что надо пользовать?
ВД> Если есть база данных на фоксе, мне надо выбрать из нее записи
ВД> удовлетворяющие определенному условию и поместить записи в мою базу.
ВД> Подсчитать исходя из моей базы некоторые данные и поместить в другие базы.
ВД> Как правильно организовать? Организовал на окне,
ВД> по Ок срабатывает цикл, который обрабатывет первую базу и помещает
ВД> записи в мою. Обыкновенный цикл LOOP. Его нужно прервать в любой
ВД> момент по нажатию Esc.( ну хотелось бы).
ВД> Может правильней было бы пользоваться виртуальными файлами.
ВД> Но я ими никогда не пользовался. И не знаю, где объявлять.
ВД> А потом как виртуальный файл загнать в реальный?
ВД> А пока получается что обработка идет довольно долго.
ВД> Если не сложно всем кто может помочь мне в моей проблеме.
ВД> Можно мылом на меня.

Во-первых, необходимо определиться с использованием ключей. Если есть подходящий ключ, который позволит сузить область сканируемых записей, то следует использовать его. Если мне не изменяет память, то ты писал, что другая програ, написанная на Фоксе, довольно шустро делает необходимую выборку. Если это так, то, скорее всего, подходящий ключ есть.

Ну, а дальше — стандартная выборка. Простенький пример с использованием View и моего класса организации Виндовых циклов.

ScanView  VIEW(FoxFile)
          END
Process   BasicProcessType

Clear(GLO:Order_PaySum)
BIND(‘FirstDate’,GLO:FirstDate)
BIND(‘LastDate’,GLO:LastDate)
BIND(‘MinSum’,GLO:MinSum)
BIND(‘MaxSum’,GLO:MaxSum)

Process.Init(True,’Выборка…’,,,,True,50,Records(FoxFile))
ScanView{PROP:Filter} = ‘(FOX:Date => FirstDate) AND ‘& |
‘(FOX:Date MinSum) AND (FOX:PaySum

Ресурсы из другого модуля

ПВА> Добрый день.
ПВА> Вопрос к О.Руденко:

>>были некоторые глюки, связанные, в частности, еще и со «сьездом»
>>по-горизонтали отчетов.

ПВА> можно поподробнее о «съезде» отчетов.
ПВА> Есть один отчет, который иногда съезжает вправо. Причем это уже видно в
ПВА> препросмотре.
ПВА> Оператору приходиться закрывать и формировать еще раз. Где рыть — непонятно?

ПВА> C4,ШВС

ПВА> Понамарев Виталий Александрович
ПВА> Банк Москва-Сити

С чем это связано я не разбирался. Но, если мне память не изменяет, кто-то из коллег в данной рассылке уже (правда давно) давал обьяснение данному глюку. Там что-то было связано с MDI-аттрибутом последнего открытого окна. Или что-то подобное.

Я, как уже писал, решил эту проблему просто — достаточно обьявить окошко, например глобальное, и открыть/закрыть его ПЕРЕД открытием отчета:

DummyWin WINDOW,AT(,,0,0),CENTER,NOFRAME.
...
Open(DummyWin); Close(DummyWin)
...
Open(Report)
...

С тех пор никаких подобных проблем больше не было.

А для вставки этого кода я себе написал небольшой глобальный шаблончик, который подобный код вставляет во все REPORT-процедуры:

#!------------------------------------------------------------------------------
#!------------------------------------------------------------------------------
#EXTENSION(NoShiftReport,'Предотвращение горизонтального сдвига отчетов'),APPLICATION
#!------------------------------------------------------------------------------
#BOXED('')
  #DISPLAY('Данный шаблон предотвращает возможный')
  #DISPLAY('горизонтальный сдвиг рабочего поля отчета')
  #DISPLAY('вправо.')
  #DISPLAY('Для этого в начало каждого отчета вставляется')
  #DISPLAY('код открытия и закрытия пустого окна:')
  #DISPLAY('     OPEN(DummyWin)')
  #DISPLAY('     CLOSE(DummyWin)')
  #DISPLAY('Данный шаблон обрабатывает только те процедуры,')
  #DISPLAY('в которых явно присутствует структура REPORT.')
  #DISPLAY('В других случаях вышеприведенный код надо явно')
  #DISPLAY('вставлять перед открытием отчета.')
#ENDBOXED
#!
#AT(%GlobalData),FIRST
!===============================================================================
DummyWin WINDOW,AT(,,0,0),CENTER,NOFRAME
         END
!===============================================================================
#ENDAT
#!
#AT(%ProcedureSetup),WHERE(%Report)
OPEN(DummyWin)
CLOSE(DummyWin)
#ENDAT
#!------------------------------------------------------------------------------

Некоторая информация об ANY-полях

bdr> Приветствую тебя Олег!
bdr> Ты писал:

>> Fld ANY
>> Fld &= WHAT(tst,1)
>> Если это действительно тебе или кому другому необходимо, то
>> могу бросить в эху письмо с кодом.
>> Oleg_Rudenko@mail.ru
>> Oleg_Rudenko@mailru.com

bdr> Извени, что с запозданием, но что то никто не захотел, а мне это
bdr> необходимо.
bdr> Если тебе не составит труда, то я бы не отказался от такой информации.
bdr> С уважением Бирюков Александр

ВНИМАНИЕ!!!
Все нижесказанное справедливо ТОЛЬКО для C55!
В версии C50 есть некоторые, незначительные, отличия.
Которые, впрочем, запросто могут привести к GPF!
Правда, надо заметить, что эти отличия касаются ТОЛЬКО правильного определения адреса UFO-обьекта, который в C55 определяетя просто через Address(Any).

В C50 необходимо немного «извратиться».
Если кому необходимо именно для С50 — пишите, подскажу.
Что-же касается описания INTERFACE и всех остальных структур, то они идентичны для обеих версий. Читать далее

Лентяи из SV

Разработчики из SV меня не перестают удивлять!
Они или лентяи, или там вообще планирование  разработок новых версий/исправление ошибок  поставлено «из рук вон плохо».

Начал вот перевод некоторых своих приложений с C50 на C55. И сразу на «H» релиз.
Кстати, что-бы не забыть — после перевода не обнаружил никаких проблем с полями файлов, в именах которых есть символ «_». О чем тут как раз шло обсуждение.

Да и вообще — переход прошел настолько гладко, что даже как-то не посебе:) Так и жду, что где-то  рано или поздно вылезет какая-либо гадость.  Приложения очень большие и практически невозможно их  протестировать за приемлемое время.

Проблема обнаружилась только одна — в одном месте  производится переадресация колонок List-а на разные  поля очереди. И, в связи с тем, что в C55 немного  по другому производится нумерация полей групп/очередей,  то переадресация попала на поля-массивы. Читать далее

С+Clarion

В продолжение обсуждения передачи группы в C-функции  как константы а не по ссылке.  Как удалось выяснить, такие группы действительно  копируются на стек по полям и делает это вызывающая программа.  Так что, увы, нет нормального способа использовать такие  функции из Клариона! Если нет возможности «развернуть»  такие группы по полям, то единственный выход — использовать  переходник.

Кстати! Оказывается есть возможность работы с C-функциями,  которые возвращают в качестве результата структуру.
Типа:

my_struct MyFunc();

Данная функция возвращает структуру my_struct.  На самом деле компилятор С генерит вызов такой функции как Clarion-аналог:

MyFunc(*MY_STRUCT _Struct),LONG,RAW,C,NAME('_MyFunc')

Т.е. в качестве первого (скрытого) параметра такая функция  получает указатель на принимающую структуру и одновременно  такая функция возвращает еще и указатель на эту структуру. Читать далее

Использование Logout/Commit

VAB> Здравствуйте, Олег.
VAB> Ответ на Ваше письмо от 22 сентября 2002 г., 22:38:50
VAB> Большое спасибо за Ваши ответ и мнение.
VAB> И если можно, один маленький вопрос.
VAB> Ранее Андрей Мялин мне уже советовал, правда для драйвера Pervasive
VAB> Btrieve, использовать пару LOGOUT()-COMMIT.
VAB> Теперь Вы советуете эту же пару для драйвера TPS.
VAB> Вопрос вот какой:
VAB> Каким образом применение транзакции влияет НА БУФЕРИЗАЦИЮ данных ?
VAB> Сознаюсь, что я ещс не пробовал этот метод для TPS, но обязательно
VAB> попробую.
VAB> И ещс один вопросик:
VAB> Ваши рекомендации по использованию пары STREAM()-FLUSH() относятся к
VAB> использованию пары LOGOUT()-COMMIT ?
VAB> Вы сами понимаете, что открытие-закрытие транзакции для каждого цикла
VAB> несколько замедлит обработку. Это я уже проходил и не один раз.
VAB> Или одну пару LOGOUT()-COMMIT применять для всех циклов обработки ?

Для драйвера «TopSpeed» (.TPS) транзакция, в отличии от драйвера «Clarion» (.DAT), не замедляет а УСКОРЯЕТ процесс обработки! И значительно! Раньше я как-то уже приводил сравнительные данные. В среднем, транзакция для TPS ускоряет процесс обработки (ADD/PUT/DELETE) ~5-10 раз. Бывает меньше, но бывает и больше! Читать далее

Итак, несколько основных моментов при использовании фильтра:

  • сам по себе VIEW не отличается большим интеллектом.
  • если не задан явно PROP:ORDER и не указан перед открытием VIEW используемый ключ, то при построении выборки игнорируются все ключи и выборка строится по порядку записей. Естественно — очень медленно, т.к. необходимо перебирать ВСЕ записи. В этом случае, перед открытием VIEW можно и не ставить операторы SET(View) или SET(File), но НЕОБХОДИМО ставить один из них  перед первым NEXT()/PREVIOUS()! Иначе, сами понимаете, не будет инициализирован порядок просмотра выборки.
  • если не задан явно PROP:ORDER, но перед открытием VIEW задан ключ просмотра, то именно этот ключ и будет использован при построении выборки. Если ключ не подходит для заданного фильтра, то скорость выборки маленькая. Если задан правильный ключ, то первая и последняя записи выборки будут считаны мгновенно. Скорость самой выборки всего диапазона будет зависеть от ее размера. Но, в любом случае, это будет самый оптимальный вариант. Так что, как видим, VIEW не блещет интеллектом и не выбирает сам подходящий ключ — все делает программист.
  • если задан явно PROP:ORDER, то теперь все зависит от того, совпадает ли он с ключом, оптимальным для фильтра. Дело в том, что независимо от того, какой ключ будет задан перед открытием VIEW, выбирается ВСЕГДА самый оптимальный для заданной сортировки. Вот здесь и проявляется интеллектуальность VIEW. Если выбранный ключ является оптимальным и для заданного фильтра, то такая выборка будет самой оптимальной. В противном случае я даже затрудняюсь сказать, какой ключ используется или используется выборка по порядку записей. По крайней мере, автоматом НЕ ВЫБИРАЕТСЯ первый ключ — это точно. В результате проведенных тестов есть подозрение, что в некоторых случаях (разные фильтры) выбирается оптимальный ключ, т.к. в этих случаях время построения выборки с сортировкой меньше времени полного прохода всех записей.

Подводя итог под вышесказанным, можно рекомендовать следующие Читать далее

Поменял в базе ID записи с Long на String(20)

Фильтры и итоги в бровзе раза в 4 замедлились 🙁
Отвечаю сразу по двум письмам на данную тему (второе от Владимира Смелика).
Замедление — закономерный результат.
И дело даже не в том, что изменился размер самого поля. Все дело — в принципиально разной обработке полей типа LONG и STRING. Если для обработки полей типа LONG компилятор генерит обычный машинный код с простыми ASM-операторами, то даже для простейших операций с переменными типа STRING используется специальный внутренний стек. Например, для выполнения оператора Clip(STR) генерится (упрощенно) следующий код:

  • «затолкнуть» (Push) переменную STR в стек 2 ASM-команды + вызов стековой функции
  • выполнить операцию CLIP() над содержимым вершины стека один вызов стековой функции
  • «вытолкнуть» (Pop) результат из стека в переменную STR 2 ASM-команды + вызов стековой функции А для операции сравнения двух операндов, одним из которых является строка, генерится (без применения CLIP() или UPPER()):
  • PushToStack(STR)
  • PushToStack(STR1)
  • CompareStack()

А если, не дай бог, вторым операндом будет не строка, а, например Читать далее

Как правильно задать имя переменной, находящейся в куче вложенных структур?

Как правильно задать имя переменной, находящейся в куче вложенных структур? Вот простой пример.

g1      group  ! в оригинале - record файла
l       long
         end
q       queue,type
g1      like(g1)
         end

Так работает:

g2      group
q2      &q
         end
     CODE
  g2.q2.g1.l = 1

А так — нет, хотя скобки массива вроде правильно стоят:

g2      group,dim(2)
q2      &q
         end
     CODE
  g2[1].q2.g1.l = 1  ! ERROR: field not found: g1

Что не так? Вообще-то Кларин компилятор очень не любит массивы рефералов!

А у тебя как раз получается такой массив. Так что, возможно, именно из-за этого он и ругается. А если тебе надо сделать что-то типа массива очередей, то самый простой вариант — делать не через массив а через очередь.
Т.е.:

FilesQue  QUEUE
RecsQue     &Q
          END

Если нужен массив на два элемента — делай две записи. И т.д. Такой вариант будет работать и компилятор спокойно его пропустит.

Возвращаюсь у своему вопросу: необходимо подключиться к серверу Velocis программой на Кларионе.

Сразу скажу, что с данным сервером не работал, поэтому мои рекомендации можешь рассматривать просто как мысли вслух программиста с большим стажем работы с БД.

Правильно ли я выбрал формат Dbf. Может, кто предложит что лучше?  Опять-же — для чего «сливаются» данные? Если для дальнейшей работы с ними

прямо в этих базах, то — сойдет. Если же предполагается простая закачка данных из этих баз уже в рабочую базу, то в качестве альтернативы я бы предложил рассмотреть простой ASCII-файл. Чтение из него не медленнее чем из DBF, а то и быстрее. Зато точно не будет никаких сюрпризов, как это бывает при работе с DBF из Клариона. Читать далее