Форум » LetoDB, HbNetio. » Вопросы новичка... (продолжение) » Ответить

Вопросы новичка... (продолжение)

Andrey: Взял последнюю версию с "Новая страница с бинарниками", установил на Win2008 Server, чуток помучился с портом... Собрал на МиниГуи+BCC 551 - \MiniGui\batch\hbmk2.bat rddleto.hbp Получил rddleto.lib - 131072 байт - правильный ли размер ? И еще Warning-и лезут: lib\.hbmk\win\bcc\rddsys.c: source\client\letocl.c: source\client\leto1.c: source\client\letomgmn.c: source\common\blowfish.c: source\common\common_c.c: source\common\hbip.c: TLIB 4.5 Copyright (c) 1987, 1999 Inprise Corporation /P32 lib\rddleto.lib -+ lib\.hbmk\win\bcc\rddsys.obj -+ lib\.hbmk\win\bcc\letocl.obj -+ lib\.hbmk\win\bcc\leto1.obj -+ lib\.hbmk\win\bcc\letomgmn.obj -+ lib\.hbmk\win\bcc\blowfish.obj -+ lib\.hbmk\win\bcc\common_c.obj -+ lib\.hbmk\win\bcc\hbip.objWarning: 'rddsys' not found in library Warning: 'letocl' not found in library Warning: 'leto1' not found in library Warning: 'letomgmn' not found in library Warning: 'blowfish' not found in library Warning: 'common_c' not found in library Warning: 'hbip' not found in library Так должно быть или нет ? Вопрос сразу напрашивается с путями - как писать правильно "\" или "/" : Local cPathServer := "//127.0.0.1:2812/" cPathServer := cPathServer +"DATE_TEST_PATH\test.dbf" Помню что где то обсуждали, а результат не запомнил...

Ответов - 48, стр: 1 2 3 All

SergKis: Pasha Спасибо.

SergKis: Pasha Можно ли более информанивным сделать сообщение в log ERROR! UDF: not a valid name ? Добавить имя функции и источник, адрес

Петр: Извините за возможно глупый вопрос, а откуда можно скачать обновленные исходники, а то с sourceforge что-то не совсем свежее качается.

SergKis: Петр https://sourceforge.net/p/letodb/code/ci/master/tree/

Петр: Спасибо за ссылку. [pre2] nParam = leto_GetParam( szData, &pp2, &pp3, NULL, NULL ); // leto_writelog( NULL, 0, "UDF: %s, CMD=%d\r\n", pp2, uiCommand ); [/pre2] Павел не добавил закомментированную строку. Добавьте у себя, тогда сравнивая letodb.log и letodb_Х.log [pre2]Leto DB Server v.2.17b2 ! INIT: DataPath=f:\leto\data, ShareTables=0, MaxUsers=500, MaxTables=5000, CacheRecords=10 08/02/16 23:51:17: F:\leto\letoudf.hrb has been loaded. UDF: str, CMD=3 UDF: udf_diskSpace, CMD=3 UDF: str, CMD=2 UDF: udf_diskSpace, CMD=2 [/pre2] [pre2]127.0.0.1 MASTER-H test_udf.exe ERROR! UDF: not a valid name ERROR! UDF: not a valid name [/pre2] вы б получили необходимую информацию. Как по мне, leto_wUsLog() нужно модифицировать для передачи дополнительной информации по типу leto_writelog() Ну и лог сервера вести без указания времени события как-то некрасиво, что-ли

SergKis: Петр пишет нужно модифицировать для передачи дополнительной информации ... лог сервера вести без указания времени события как-то некрасиво Согласен. К имени функции и времени в доп. инф. важно идентифицировать и пользователя (имя, адрес, exe) по возможности ...

SergKis: Pasha Вопросик. В UDF применяются след. ф-ии для тек.записи leto_rec( nUserStru ) и потом на клиенте Leto_ParseRec( cRecBuf ) для списка записей leto_dbEval( nUserStru ) и потом на клиенте leto_ParseRecords( cRecs ) варианта превратить array в cRecs не увидел, типа a := {} For i := 1 To 10 dbAppend() AADD(a, RecNo()) Next cRecs := ???( a ) или остается только вариант (без BM фильтра) a := {} For i := 1 To 10 dbAppend() AADD(a, leto_rec( nUserStru )) Next Return a и на клиенте по массиву делать Leto_ParseRec( aRecs[ i ] ) или надо обязательно применять BM filter для такой ситуации ?

Pasha: Вызов leto_ParseRecords заполняет skip-буфер, который затем можно в цикле обработать. Пример как раз показан в комментариях к UDF_dbEval: leto_ParseRecords( leto_Udf('UDF_dbEval', <xScope>, <xScopeBottom>, <xOrder>, <cFilter>, <lDeleted> ) ) while ! eof() ... skip enddo dbInfo( DBI_CLEARBUFFER ) В случае набора произвольных записей такой способ был бы неправильным, так как это не является набором записей, следующих друг за другом последовательно. Поэтому лучше всего будет как раз возврат в udf массива записей с последующей их обработкой на клиенте: aRecs := leto_udf("udf_func", ...) for each cRec in aRecs leto_ParseRec(cRec) // обработка next

SergKis: Pasha пишет Поэтому лучше всего будет как раз возврат в udf массива записей с последующей их обработкой на клиенте: Это понятный механизм В случае набора произвольных записей такой способ был бы неправильным, так как это не является набором записей, следующих друг за другом последовательно. Имеем на сервере [pre2] FUNCTION UDF_dbEval( nUserStru, xScope, xScopeBottom, xOrder, cFilter, lDeleted ) LOCAL cRecs leto_SetEnv( xScope, xScopeBottom, xOrder, cFilter, lDeleted ) GO TOP cRecs := leto_dbEval( nUserStru ) leto_ClearEnv( xScope, xScopeBottom, cFilter ) RETURN cRecs [/pre2] в результате cRecs (на клиенте), после leto_setenv и leto_clearenv мы имеем как раз произвольный набор записей, т.к. Env устанавливалась на сервере, а на клиенте как было так и осталось, т.е. cRecs полученный leto_dbeval и array recno => cResc, обработка клиентом одинакова leto_ParseRecords( leto_Udf('UDF_Append2cRecs", 10 ) ) // добавлено 10 записей while ! eof() ... skip enddo dbInfo( DBI_CLEARBUFFER )

SergKis: PS Пояснение. Имеем [pre2] USE ( cPath+"test3" ) New INDEX ON NUM TAG KOD FOR ! deleted() INDEX ON NAME TAG NAM FOR ! deleted() INDEX ON NUM TAG DEL FOR deleted() USE ... USE ( cPath+"test3" ) New SHARED If OrdCount() > 0 OrdSetFocus(2) // по наименованию на клиенте EndIf сейчас делаем так For i := 1 To 10 cRecBuf := Leto_Udf("UDF_AppendRec", "NUM", {'KOD', 'DEL'}, 10) // по тэгу KOD добавление на сервере Leto_ParseRec( cRecBuf ) IF RLock() REPL NAME with "Name_"+strzero(RecNo(), 7), ; INFO with "Info_"+iif(j == "N", hb_ntos(NUM), NUM)+"-"+j dbUnLock() ENDIF ? i, RecNo(), NUM, NAME Next в чем разница, если сразу добавить 10 записей на сервере (присвоив код) и вернув cResc (на сервере можно и leto_dbeval для новых записей получить в cRecs), сделать leto_ParseRecords(cRecs) и заполнить их в цикле ? Теоретически, вроде, ни что не мешает ? На клиенте ордер 2, на сервере отработали по ордеру 1 или тут камень есть ? [/pre2]

SergKis: SergKis пишет Теоретически, вроде, ни что не мешает ? На клиенте ордер 2, на сервере отработали по ордеру 1 или тут камень есть ? Pasha пишет Поэтому лучше всего будет как раз возврат в udf массива записей с последующей их обработкой на клиенте: aRecs := leto_udf("udf_func", ...) for each cRec in aRecs leto_ParseRec(cRec) // обработка next Pasha прав В итоге сделал так [pre2] FUNCTION UDF_AddRecID( nUserStru, cFieldName, xOrder, aFldVal, xMin ) LOCAL nPos := FieldPos( cFieldName ), nLen, a, p LOCAL xKey, lApp, lOver := .F., xOrd1, xOrd2, nDec IF ! Empty( xOrder ) IF Valtype(xOrder) == "A" xOrd1 := xOrder[1] xOrd2 := xOrder[2] ELSE xOrd1 := xOrder ENDIF OrdSetFocus( xOrd1 ) ENDIF IF leto_TableLock( nUserStru, 1 ) dbGoBottom() xKey := FieldGet( nPos ) IF Empty(xKey) .and. ! Empty(xMin) xKey := xMin IF ValType( xKey ) == "C" nLen := hb_FieldLen( nPos ) If left(xKey, 1) == "0" .and. ! "." $ xKey xKey := left(xKey+space(nLen), nLen) Else xKey := right(space(nLen)+xKey, nLen) EndIf ENDIF ENDIF IF ValType( xKey ) == "N" xKey ++ IF hb_FieldType(nPos) $ 'NF' lOver := xKey > Val( Replicate( "9", hb_FieldLen( nPos ) ) ) ELSEIF hb_FieldLen( nPos ) == 2 lOver := xKey > 0x7FFF ELSEIF hb_FieldLen( nPos ) == 4 lOver := xKey > 0x7FFFFFFF ENDIF ELSEIF ValType( xKey ) == "C" nLen := Len(xKey) If "." $ xKey nDec := nLen - RAt(".", xKey) xKey := Str( Val(xKey) + 1, nLen, nDec ) ElseIf left(xKey, 1) == "0" xKey := StrZero( Val(xKey) + 1, nLen ) Else xKey := Str( Val(xKey) + 1, nLen ) EndIf lOver := ('*' $ xKey) ENDIF IF lOver lApp := .F. ELSE lApp := ( UDF_AddRec( nUserStru, xOrd2 ) != Nil ) ENDIF IF lApp If ! empty(aFldVal) FOR EACH a IN aFldValue IF ( p := FieldPos(a[1]) ) > 0 IF ! ( p == nPos .or. hb_FieldType(p) $ "+=^" ) FieldPut(p, a[2]) ENDIF ENDIF NEXT EndIf FieldPut( nPos, xKey ) dbCommit() ENDIF leto_TableUnLock( nUserStru, 1 ) ELSE lApp := .F. ENDIF RETURN if( lApp, leto_rec( nUserStru ), Nil ) FUNCTION UDF_AddRec( nUserStru, xOrder ) LOCAL lApp, lSetDel, xRet IF xOrder != Nil OrdSetFocus( xOrder ) ENDIF lSetDel := Set( _SET_DELETED, .f. ) dbGoTop() Set( _SET_DELETED, lSetDel ) IF ! Eof() .and. Deleted() .and. Empty( OrdKeyVal() ) IF( lApp := leto_RecLock( nUserStru ) ) dbRecall() ENDIF ELSE dbAppend() IF ( lApp := ! NetErr() ) leto_RecLock( nUserStru, RecNo() ) ENDIF ENDIF IF lApp xRet := leto_rec( nUserStru ) ENDIF RETURN xRet на клиенте DO WHILE ! EOF() aRec := RecGet() // {{cFieldName, xFieldValue}, ... } cRec := Leto_Udf("UDF_AddRecID", 'IDREC', {'IDR', 'DEL'}, aRec) If cRec = Nil ? "error ...." EndIf SKIP ENDDO [/pre2]

Andrey: Всем привет ! Вопрос возник по эксплуатации ЛетоДб. Перед отправкой записей в базу на сервер, я проверяю в папке наличие файла и считываю оттуда его содержимое. Типа ключа для каждой фирмы. Код в программе: IF !LETO_FILE(cFile) MsgStop( "Нет файла КЛЮЧА на сервере!" ) RETURN .F. ENDIF Периодически юзера жалуются на появление такой ошибки ! Проверяю в это же время сервер - доступен. Пока юзер не перегрузит комп, ошибка не уходит. Иногда и после перезагрузки остаётся. Как с этим бороться ?

Pasha: Можно описать ситуацию подробнее ? Сервер находится тырнете или в локалке ? Коннект к серверу до выполнения leto_file выполнялся или нет ? Файл ключа все время существует или нет ? Что в cFile ? Коннект с сервером может прерваться или связь стабильная ? Без такого контекста отвечать на подобный вопрос трудно.

Andrey: Pasha пишет: Можно описать ситуацию подробнее ? Сервер в инете. Программа делает коннект до сервера и работает дальше, т.е. отправляет записи на сервер ЛетоДб через 1-5 минут. Спустя 1 час или 5 часов - начинается такая фигня. Инет стабильный, коннект вроде не прерывается. Содержимое в cFile - 20-40 символов. В момет появления ошибки, захожу со своего компа - файлы все на месте и сервер ЛетоДб нормально отвечает.

Pasha: Если сервер живой, и файл на сервере существует, то логично предположить, что неудача leto_file связана с нарушением связи с сервером с этого клиента. В таком случае после if !LETO_FILE можно поставить проверку связи, например, вызовом функции LETO_MGGETINFO

alkresin: Pasha пишет: В таком случае после if !LETO_FILE можно поставить проверку связи, например, вызовом функции LETO_MGGETINFO Надо будет для проверки связи сделать ф-ю leto_Ping() - тем более, что команду такую сервер обрабатывает. Помнится, это чуть-ли не первая команда, которую я в свое время сделал.

alkresin: Andrey пишет: Пока юзер не перегрузит комп, ошибка не уходит. Иногда и после перезагрузки остаётся. Вот это и в самом деле странно. Я бы до перезагрузки компа проверил ping к серверу - обычную команду ping, ну и если он проходит, то проверил бы как отрабатывает leto_Connection(). Перед отправкой записей в базу на сервер, я проверяю в папке наличие файла и считываю оттуда его содержимое. Немного не в тему, но: а почему бы не использовать здесь leto_var...() функции ?

Pasha: alkresin пишет: Надо будет для проверки связи сделать ф-ю leto_Ping() - тем более, что команду такую сервер обрабатывает. Помнится, это чуть-ли не первая команда, которую я в свое время сделал. Еще в файловых функциях вроде LetoFileExist можно добавить обработку: if( uiRes ) { ... } else s_iError = 1000; Можно вместо этого перенести установку if( !lRet ) s_iError = 1000; из функции leto_SendRecv в функцию leto_DataSendRecv Тогда ошибку связи с сервером во многих функциях, в том числе файловых, можно будет проверить вызовом LETO_FERROR()

Andrey: alkresin пишет: Немного не в тему, но: а почему бы не использовать здесь leto_var...() функции ? Да наверно из-за не знания. Я когда начал изучать документацию по Лето, то не понял, для чего они. Самостоятельно не всегда знаешь/понимаешь что нужно в том или ином случае. Желательно бы в документацию включить доп.материалы для тех или иных действий и код приводить полностью. Например: 1) Коннект к серверу (это есть вроде) 2) Проверка доступности сервера и переподключение к серверу. 3) Проверка доступа клиента к базе, т.е. разрешение к записи/чтения к базе. Это я реализовал простой проверкой наличия файла (у каждой фирмы свой файл) и содержимого самого файла (типа ключа проверки). 4) Работа с базами на двух и более серверах ЛетоДБ 5) Синхронизация по таймеру ( и событию) локальной и серверной базы и наоборот с сервера на локальную. и т.д.

alkresin: Pasha пишет: Можно вместо этого перенести установку Так и сделал. И Leto_Ping() добавил: возвращает .T., если все в порядке.



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