Автор | Сообщение |
|
| постоянный участник
|
Пост N: 4156
Зарегистрирован: 12.09.06
|
|
Отправлено: 04.05.15 22:44. Заголовок: Вопросы новичка... (продолжение)
Взял последнюю версию с "Новая страница с бинарниками", установил на 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" Помню что где то обсуждали, а результат не запомнил...
| |
|
Ответов - 54
, стр:
1
2
3
All
[только новые]
|
|
|
| постоянный участник
|
Пост N: 1225
Зарегистрирован: 09.10.06
|
|
Отправлено: 02.08.16 23:20. Заголовок: Pasha пишет: Вызыва..
Pasha пишет: цитата: | Вызывать можно функции, указанные в request, ну и некоторые другие. Я пересматривал этот набор - он вполне безопасен. Впрочем, я уже добавил параметр EnableUDF в letodb.ini, для возможности отключения udf. |
| Для себя внес изменения в letofunc.c цитата: | const char * szErrUDF = "-UDF"; .. void leto_udf( PUSERSTRU pUStru, const char* szData ) // mt? .. if( uiCommand == 0 ) { leto_wUsLog(pUStru,"ERROR! UDF: not a valid command\r\n", 0); return; } nParam = leto_GetParam( szData, &pp2, &pp3, NULL, NULL ); // leto_writelog( NULL, 0, "UDF: %s, CMD=%d\r\n", pp2, uiCommand ); if( strlen( pp2 ) < 5 || hb_strnicmp( pp2, "UDF_", 4 ) != 0 ) { leto_wUsLog(pUStru,"ERROR! UDF: not a valid name\r\n", 0); leto_SendAnswer( pUStru, szErrUDF, 4 ); pUStru->bAnswerSent = 1; return; } if( nParam < ( uiCommand == 1 ? 3 : ( uiCommand == 3 ? 1 : 2 ) ) ) leto_SendAnswer( pUStru, szErr2, 4 ); else .. |
| Т.е. имя UDF функции должно начинаться с UDF_ (UDF_() - не проходит) - хак с выполнением стандартных и функций leto через механизм leto_udf на сервере отсекается. Ну и сделал более осмысленным описание ошибки для leto_wUsLog. Мне кажется такое решение более логичным существующего.
| |
|
|
| постоянный участник
|
Пост N: 1129
Зарегистрирован: 17.02.12
|
|
Отправлено: 04.08.16 18:08. Заголовок: Pasha Скачал letodb-..
Pasha Скачал letodb-code-618295e5b48bf8ef2a50ca089ba73af8f1b57b85б : цитата: | ... + added EnableUDF option in letodb.ini |
| но в HAPP нет считывания с letodb.ini EnableUGF и нет установки leto_SetAppOptions( iif( Empty(::DataPath ),Nil,::DataPath ), ::nDriver, ::lFileFunc, ; ::lAnyExt, ::lPass4L, ::lPass4M, ::lPass4D, ::cPassName, ::lCryptTraffic, ; ::lShare, ::lNoSaveWA, nMaxVars, nMaxVarSize, nCacheRecords, nTables_max, nUsers_max, ; nDebugMode, lOptimize, nAutOrder, nMemoType, lForceOpt, ::cTrigger, ::cPendingTrigger, lSetTrigger ) // нет 25 элемента или я не там смотрю. цитата: | EnableUDF = 1 - если 1 (по умолчанию), разрешено использование udf-функций; |
| EnableUDF = 0 что делает, отключает все вызовы udf ? Если да, то чем отличается услановка в 0 и работа сервера без letoudf.hrb ?
| |
|
|
| Администратор
|
Пост N: 3475
Зарегистрирован: 23.05.05
|
|
Отправлено: 05.08.16 08:21. Заголовок: Прошу прощения, проп..
Прошу прощения, пропустил при коммите server.prg. Поправлю. Да, EnableUDF запрещает вызовы UDF. Может быть, имеет смысл еще добавить флаг UDFPrefix, который позволял бы вызовы только функций с именами UDF_*
| |
|
|
| постоянный участник
|
Пост N: 1231
Зарегистрирован: 09.10.06
|
|
Отправлено: 05.08.16 08:39. Заголовок: Как вариант, еще вме..
Как вариант, еще вместо одного letoudf.hrb можно использовать 2 (или более), например, letoudf_st.hrb и letoudf_us.hrb. Запуск letoudf_st.hrb не зависит от EnableUDF, запуск letoudf_us.hrb (и остальных), соответственно, зависит.
| |
|
|
| постоянный участник
|
Пост N: 1232
Зарегистрирован: 09.10.06
|
|
Отправлено: 05.08.16 08:41. Заголовок: Pasha пишет: Может ..
Pasha пишет: цитата: | Может быть, имеет смысл еще добавить флаг UDFPrefix |
| Имеет, мой голос - за
| |
|
|
| постоянный участник
|
Пост N: 1130
Зарегистрирован: 17.02.12
|
|
Отправлено: 05.08.16 09:48. Заголовок: Pasha пишет Может бы..
Pasha пишет цитата: | Может быть, имеет смысл еще добавить флаг UDFPrefix |
| Я тоже за Но можно просто обойтись режимом 0 1 2 - спрефиксоом udf_ (пока не вижу причин нескольких префиксов, но может ошибаюсь) а то возникнет желание на каждого user уст. разрешено\нет udf, как с файловыми, mg ф-ими
| |
|
|
| постоянный участник
|
Пост N: 1234
Зарегистрирован: 09.10.06
|
|
Отправлено: 05.08.16 10:17. Заголовок: SergKis пишет: а то..
SergKis пишет: цитата: | а то возникнет желание на каждого user уст. разрешено |
| можно и на уровне функций, т.е. доступна ли функция a() пользователю b
| |
|
|
| постоянный участник
|
Пост N: 1131
Зарегистрирован: 17.02.12
|
|
Отправлено: 05.08.16 11:01. Заголовок: Петр пишет можно и н..
Петр пишет цитата: | можно и на уровне функций, т.е. доступна ли функция a() пользователю b |
| Скорее возникает желание в udf знать что то с LETO_USERGETRIGHTS( nUserStru ) (такой нет) + доп. установку на user в Pass_File = "leto_users" доплнительных данных (байт 10-20). Например так на клиенте LETO_USERPARAM( cUserName, cParam ) --> lSuccess LETO_USERPARAM( cUserName ) --> cParam и на сервере LETO_USERPARAM( nUserStru [, cUserName ] ) --> cParam LETO_USERGETRIGHTS( nUserStru[, cUserName ] ) --> cRights
| |
|
|
| постоянный участник
|
Пост N: 1132
Зарегистрирован: 17.02.12
|
|
Отправлено: 05.08.16 11:06. Заголовок: Еще такая есть хотел..
Еще такая есть хотелка - класс для работы с Hash массивом с синхронизированными методами доступа к его элементам, для работы в udf
| |
|
|
| постоянный участник
|
Пост N: 1134
Зарегистрирован: 17.02.12
|
|
Отправлено: 05.08.16 11:51. Заголовок: И еще есть желание (..
И еще есть желание (многие сервера обеспечивают) иметь алиасные пути к файлам и таблицам, например секция в letodb.ini (привязка разработки к реальном данным на сервере) [ALIAS] \TMP\ = \TEST\TABL\BLS\ \WRK\ = \TEST\WRK\ \MY1\ = \TEST\MY1\ \MY2\ = \TEST\MY2\ на клиенте пишем \tmp\table01.dbf \tmp\table02.dbf на сервере происходит подмена на реальное значение \TMP\ и т.д. в 2-х поточной версии для dbf я это делал, для файловых ф-й ( C ) сложновато для меня
| |
|
|
| постоянный участник
|
Пост N: 1135
Зарегистрирован: 17.02.12
|
|
Отправлено: 05.08.16 13:22. Заголовок: И последнее. Не хват..
И последнее. Не хватает команды типа ( если стоит EnableFileFunc = 0 и нет hrb, а теперь и режим 0 для udf) 1. CRATE TABLE myTable ... IF NOT EXISTS - трудно управлять созданием таблицы, особенно если нет созданных каталогов к ней, возможно по установке в ini (а может и всегда) разрешать автосоздание дирректорий при их отсутсвии 2. DROP TABLE myTable - удалить таблицу вместе с индексами
| |
|
|
|
| постоянный участник
|
Пост N: 1136
Зарегистрирован: 17.02.12
|
|
Отправлено: 05.08.16 15:15. Заголовок: PS Реализация CREATE..
PS Реализация CREATE TABLE ... IF NOT EXISTS могла бы выглядеть к примеру так: FUNCTION hs_createtable( nUserStru, cCommand ) ... LOCAL cRecData LOCAL lTable := .F., lAutoCreate := leto_GetAppOptions( 26 ) // к примеру ... IF Lower(cName) = "/mem:" cDataPath := "" cName := Substr(cName, 2) ELSE cDataPath := leto_GetAppOptions( 1 ) ENDIF cFileName := cDataPath + cName IF !empty(cDataPath) // обработка алиаса, если использовать механизм cFileName := SetAlias2Path( cFileName ) // заменяем ALIAS (если есть) на реальный путь // If lAutoCreate lTable := hb_FileExists(cFileName) If ! lTable CreateDir(cFileName) EndIf EndIf ENDIF If ! lTable BEGIN SEQUENCE WITH { |e|break( e ) } leto_SetUserEnv( nUserStru ) dbCreate( cFileName, aStru, leto_Driver( nDriver ), .T. , cRealAlias ) RECOVER USING oError lres := .F. END SEQUENCE EndIf ... STATIC FUNCTION CreateDir( cDBF ) LOCAL aCt := {} LOCAL i := RAt(DEF_SEP, cDBF) LOCAL cCt := Left(cDBF, i-1) DO WHILE ! hb_DirExists( cCt ) i := RAt(DEF_SEP, cCt) IF i == 0 ; EXIT ENDIF AAdd( aCt , subs(cCt, i+1) ) cCt := Left( cCt, i-1) ENDDO i := Len( aCt ) DO WHILE i > 0 cCt += (DEF_SEP + aCt[i--]) MakeDir( cCt ) ENDDO RETURN .T.
| |
|
|
| Администратор
|
Пост N: 3476
Зарегистрирован: 23.05.05
|
|
Отправлено: 05.08.16 20:00. Заголовок: SergKis пишет: Еще ..
SergKis пишет: цитата: | Еще такая есть хотелка - класс для работы с Hash массивом с синхронизированными методами доступа к его элементам, для работы в udf |
| Добавил request на сервере для хеш-функций. Сделал префикс UDF_* обязательным по умолчанию для вызовов udf, с возможностью отключения этого режима. А функция hb_dbDrop поддерживается letodb уже давно, т.к. метод letoDrop реализован на клиенте.
| |
|
|
| постоянный участник
|
Пост N: 1137
Зарегистрирован: 17.02.12
|
|
Отправлено: 05.08.16 20:39. Заголовок: Pasha :sm36: А что..
Pasha А что по поводу варианта цитата: | CREATE TABLE ... IF NOT EXISTS |
|
| |
|
|
| постоянный участник
|
Пост N: 1138
Зарегистрирован: 17.02.12
|
|
Отправлено: 05.08.16 21:51. Заголовок: Pasha HApp разсогла..
Pasha HApp разсогласовался по переменным DATA и LOCAL в Method New, потому прошла ошибка ELSEIF aIni[i,2,j,1] == "ENABLEUDF" ::lUDF := ( aIni[i,2,j,2] == '1' ) ... leto_SetAppOptions( iif( Empty(::DataPath ),Nil,::DataPath ), ::nDriver, ::lFileFunc, ; ::lAnyExt, ::lPass4L, ::lPass4M, ::lPass4D, ::cPassName, ::lCryptTraffic, ; ::lShare, ::lNoSaveWA, nMaxVars, nMaxVarSize, nCacheRecords, nTables_max, nUsers_max, ; nDebugMode, lOptimize, nAutOrder, nMemoType, lForceOpt, ::cTrigger, ::cPendingTrigger, lSetTrigger, lUDF ) Предлагаю Скрытый текст
CLASS HApp DATA nPort INIT 2812 DATA ip DATA nTimeOut INIT -1 DATA DataPath INIT "" DATA LogFile INIT "" DATA lLower INIT .F. DATA lFileFunc INIT .F. DATA lAnyExt INIT .F. DATA lShare INIT .F. // .T. - new mode, which allows share tables with other processes DATA lNoSaveWA INIT .F. // .T. - new mode, which forces dbUseArea() each time "open table" is demanded DATA nDriver INIT 0 DATA lPass4M INIT .F. DATA lPass4L INIT .F. DATA lPass4D INIT .F. DATA cPassName INIT "leto_users" DATA lCryptTraffic INIT .F. DATA cTrigger DATA cPendingTrigger DATA nMaxVars DATA nMaxVarSize DATA nCacheRecords INIT 10 DATA nTables_max DATA nUsers_max DATA nDebugMode INIT 0 DATA lOptimize INIT .F. DATA nAutOrder DATA nMemoType DATA lForceOpt INIT .F. DATA lSetTrigger INIT .F. DATA lUDF INIT .T. METHOD New() ENDCLASS METHOD New() CLASS HApp LOCAL cIniName := "letodb.ini" LOCAL aIni, i, j, cTemp, cPath, nDriver LOCAL nPort := ::nPort // LOCAL nMaxVars, nMaxVarSize LOCAL nCacheRecords := ::nCacheRecords LOCAL nTables_max := NIL LOCAL nUsers_max := NIL LOCAL nDebugMode := 0 // LOCAL lOptimize := .F. // LOCAL nAutOrder LOCAL nMemoType // LOCAL lForceOpt := .F. // LOCAL lSetTrigger := .F. // LOCAL lUDF := .T. #ifdef __LINUX__ IF File( cDirBase + cIniName ) aIni := rdIni( cDirBase + cIniName ) ELSEIF File( "/etc/" + cIniName ) aIni := rdIni( "/etc/" + cIniName ) ENDIF #else IF File( cDirBase + cIniName ) aIni := rdIni( cDirBase + cIniName ) ENDIF #endif IF !Empty( aIni ) FOR i := 1 TO Len( aIni ) IF aIni[i,1] == "MAIN" FOR j := 1 TO Len( aIni[i,2] ) IF aIni[i,2,j,1] == "PORT" IF ( nPort := Val( aIni[i,2,j,2] ) ) >= 2000 ::nPort := nPort ENDIF ELSEIF aIni[i,2,j,1] == "IP" ::ip := aIni[i,2,j,2] ELSEIF aIni[i,2,j,1] == "TIMEOUT" ::nTimeOut := Val( aIni[i,2,j,2] ) ELSEIF aIni[i,2,j,1] == "DATAPATH" ::DataPath := StrTran( aIni[i,2,j,2], DEF_CH_SEP, DEF_SEP ) IF Right( ::DataPath, 1 ) $ DEF_SEP ::DataPath := Left( ::DataPath, Len( ::DataPath ) - 1 ) ENDIF ELSEIF aIni[i,2,j,1] == "LOGPATH" ::LogFile := StrTran( aIni[i,2,j,2], DEF_CH_SEP, DEF_SEP ) IF !EMPTY( ::LogFile ) IF Right( ::LogFile, 1 ) != DEF_SEP ::LogFile += DEF_SEP ENDIF leto_setDirBase( ::LogFile ) ENDIF ELSEIF aIni[i,2,j,1] == "LOWER_PATH" ::lLower := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "ENABLEFILEFUNC" ::lFileFunc := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "ENABLEANYEXT" ::lAnyExt := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "ENABLEUDF" ::lUDF := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "SHARE_TABLES" ::lShare := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "NO_SAVE_WA" ::lNoSaveWA := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "DEFAULT_DRIVER" ::nDriver := iif( Lower( aIni[i,2,j,2] ) == "ntx", LETO_NTX, 0 ) ELSEIF aIni[i,2,j,1] == "PASS_FOR_LOGIN" ::lPass4L := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "PASS_FOR_MANAGE" ::lPass4M := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "PASS_FOR_DATA" ::lPass4D := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "PASS_FILE" ::cPassName := aIni[i,2,j,2] ELSEIF aIni[i,2,j,1] == "CRYPT_TRAFFIC" ::lCryptTraffic := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "MAX_VARS_NUMBER" ::nMaxVars := Val( aIni[i,2,j,2] ) ELSEIF aIni[i,2,j,1] == "MAX_VAR_SIZE" ::nMaxVarSize := Val( aIni[i,2,j,2] ) ELSEIF aIni[i,2,j,1] == "CACHE_RECORDS" IF ( nCacheRecords := Val( aIni[i,2,j,2] ) ) <= 0 nCacheRecords := 10 ENDIF ::nCacheRecords := nCacheRecords ELSEIF aIni[i,2,j,1] == "TABLES_MAX" IF ( nTables_max := Val( aIni[i,2,j,2] ) ) <= 100 .OR. nTables_max > 200000 nTables_max := NIL ENDIF ::nTables_max := nTables_max ELSEIF aIni[i,2,j,1] == "USERS_MAX" IF ( nUsers_max := Val( aIni[i,2,j,2] ) ) <= 10 .OR. nUsers_max > 100000 nUsers_max := NIL ENDIF ::nUsers_max := nUsers_max ELSEIF aIni[i,2,j,1] == "DEBUG" IF ( nDebugMode := Val( aIni[i,2,j,2] ) ) <= 0 nDebugMode := 0 ENDIF ::nDebugMode := nDebugMode ELSEIF aIni[i,2,j,1] == "OPTIMIZE" ::lOptimize := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "AUTORDER" ::nAutOrder := Val( aIni[i,2,j,2] ) ELSEIF aIni[i,2,j,1] == "MEMO_TYPE" IF Lower( aIni[i,2,j,2] ) = 'dbt' nMemoType := DB_MEMO_DBT ELSEIF Lower( aIni[i,2,j,2] ) = 'fpt' nMemoType := DB_MEMO_FPT ELSEIF Lower( aIni[i,2,j,2] ) = 'smt' nMemoType := DB_MEMO_SMT ENDIF ::nMemoType := nMemoType ELSEIF aIni[i,2,j,1] == "FORCEOPT" ::lForceOpt := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "ENABLESETTRIGGER" ::lSetTrigger := ( aIni[i,2,j,2] == '1' ) ELSEIF aIni[i,2,j,1] == "TRIGGER" ::cTrigger := aIni[i,2,j,2] ELSEIF aIni[i,2,j,1] == "PENDINGTRIGGER" ::cPendingTrigger := aIni[i,2,j,2] ENDIF NEXT ELSEIF aIni[i,1] == "DATABASE" cPath := nDriver := Nil FOR j := 1 TO Len( aIni[i,2] ) IF aIni[i,2,j,1] == "DATAPATH" cPath := StrTran( aIni[i,2,j,2], DEF_CH_SEP, DEF_SEP ) IF Right( cPath, 1 ) $ DEF_SEP cPath := Left( cPath, Len( cPath ) - 1 ) ENDIF ELSEIF aIni[i,2,j,1] == "DRIVER" nDriver := iif( ( cTemp := Lower( aIni[i,2,j,2] ) ) == "cdx", ; 0, iif( cTemp == "ntx", LETO_NTX, Nil ) ) ENDIF NEXT IF cPath != Nil cPath := StrTran( cPath, DEF_CH_SEP, DEF_SEP ) IF Left( cPath,1 ) != DEF_SEP cPath := DEF_SEP + cPath ENDIF IF Right( cPath,1 ) != DEF_SEP cPath += DEF_SEP ENDIF leto_AddDataBase( cPath, iif( nDriver == Nil,::nDriver,nDriver ) ) ENDIF ENDIF NEXT ENDIF IF ::lLower SET( _SET_FILECASE, 1 ) SET( _SET_DIRCASE, 1 ) ENDIF IF ::lNoSaveWA ::lShare := .T. ENDIF leto_SetAppOptions( iif( Empty(::DataPath ),Nil,::DataPath ), ::nDriver, ::lFileFunc, ; ::lAnyExt, ::lPass4L, ::lPass4M, ::lPass4D, ::cPassName, ::lCryptTraffic, ; ::lShare, ::lNoSaveWA, ::nMaxVars, ::nMaxVarSize, ::nCacheRecords, ::nTables_max, ::nUsers_max, ; ::nDebugMode, ::lOptimize, ::nAutOrder, ::nMemoType, ::lForceOpt, ::cTrigger, ::cPendingTrigger, ; ::lSetTrigger, ::lUDF ) RETURN Self
|
| |
|
|
| постоянный участник
|
Пост N: 1140
Зарегистрирован: 17.02.12
|
|
Отправлено: 07.08.16 00:26. Заголовок: Pasha Что то в посл..
Pasha Что то в последней версии udf не работает. Сборка borland, hb из последнего Minigui. клиент Function Test_Udf( cPath ) Local c,i,j,k,lRes IF Empty( cPath ) cPath := "//127.0.0.1:2812/" ELSE cPath := "//" + cPath + Iif( Right(cPath,1) $ "/\", "", "/" ) ENDIF ? "Connect to " + cPath + " - " IF ( leto_Connect( cPath ) ) == -1 nRes := leto_Connect_Err() ?? "Error", nRes IF nRes == LETO_ERR_LOGIN ?? "Login failed" ELSEIF nRes == LETO_ERR_RECV ?? "Recv Error" ELSEIF nRes == LETO_ERR_SEND ?? "Send Error" ELSE ?? "No connection" ENDIF Return Nil ELSE ?? "Ok" ENDIF ? If leto_UdfExist("leto_GetAppOptions") ? "leto_GetAppOptions found" Else ? "not found "+"leto_GetAppOptions" EndIf If leto_UdfExist('hb_DiskSpace') ? "hb_DiskSpace found", leto_udf( "hb_DiskSpace", "C:\", HB_DISK_FREE ) Else ? "not found "+"hb_DiskSpace" EndIf If leto_UdfExist('UDF_AppendRec') ? 'UDF_AppendRec - found' Else ? 'UDF_AppendRec - not found' EndIf ? "Press any key to finish..." ? Inkey(0) Return Nil результат Connect to //127.0.0.1:2812/ - Ok not found leto_GetAppOptions not found hb_DiskSpace UDF_AppendRec - not found Press any key to finish... letodb.ini Port = 2812 DataPath = . EnableFileFunc = 1 EnableUDF = 1 letodb.log 08/07/16 00:04:18: Leto DB Server has been started. Leto DB Server v.2.17b2 ! INIT: DataPath=., ShareTables=0, MaxUsers=500, MaxTables=5000, CacheRecords=10 08/07/16 00:04:18: C:\LETO\letodb-code-0324bd6820c3d9644f815b7dac76309859220501\bin\letoudf.hrb has been loaded. 08/07/16 00:11:54: Send STOP to server... 08/07/16 00:11:57: Server has been closed. сборка leto-core-6bc3... тот же пример ---------------------------------------------- letodb.ini Port = 2812 DataPath = . EnableFileFunc = 1 результат Connect to //127.0.0.1:2812/ - Ok leto_GetAppOptions found hb_DiskSpace found 422226853888 UDF_AppendRec - found Press any key to finish... letodb.log 08/06/16 23:47:17: Leto DB Server has been started. Leto DB Server v.2.17b2 ! INIT: DataPath=., ShareTables=0, MaxUsers=500, MaxTables=5000, CacheRecords=10 08/06/16 23:47:17: C:\LETO\letodb-code-6bc3e8f667ff4d65caeb620eafca574aba1bd166\bin\letoudf.hrb has been loaded. 08/06/16 23:49:51: Send STOP to server... 08/06/16 23:49:54: Server has been closed.
| |
|
|
| Администратор
|
Пост N: 3478
Зарегистрирован: 23.05.05
|
|
Отправлено: 07.08.16 08:56. Заголовок: Почему-то не был вид..
Почему-то не был виден коммит, который я сделал позавчера, хотя у меня он прошел нормально. Сейчас я его повторил.
| |
|
|
| постоянный участник
|
Пост N: 1141
Зарегистрирован: 17.02.12
|
|
Отправлено: 07.08.16 09:21. Заголовок: Pasha Что не то le..
Pasha Что не то letodb.ini Port = 2812 DataPath = . EnableFileFunc = 1 EnableUDF = 1 letodb.log 08/07/16 09:10:27: Leto DB Server has been started. Leto DB Server v.2.17b2 ! INIT: DataPath=., ShareTables=0, MaxUsers=500, MaxTables=5000, CacheRecords=10 08/07/16 09:10:27: C:\LETO\letodb-code-7e89fed2f632e34d814bf8518ec08707be6b0e45\bin\letoudf.hrb has been loaded. 08/07/16 09:17:03: Send STOP to server... 08/07/16 09:17:06: Server has been closed. letodb_0.log 127.0.0.1 LENOVO Test_Udf.exe ERROR! UDF: not a valid name ERROR! UDF: not a valid name клиент пересобран с rddleto.lib из этой сборки результат Connect to //127.0.0.1:2812/ - Ok not found leto_GetAppOptions not found hb_DiskSpace UDF_AppendRec - found Press any key to finish...
| |
|
|
| постоянный участник
|
Пост N: 1142
Зарегистрирован: 17.02.12
|
|
Отправлено: 07.08.16 09:42. Заголовок: Pasha Не очень пони..
Pasha Не очень понимаю режим с EnableUDF = 0 Для меня важно, что бы удаленный "продвинутый" user не смог через вызов leto_udf("...") сломать инфу сервера (сборку всех серверов не проконтролируешь на request функций), т.е. leto_ferase, leto_fRename, leto_drop, leto_memowrit,leto_FileWrite, leto_dirremove, Leto_FileAttr, ... dbCreate, fErase, fRename, fCreate, hb_memowrit, StrFile, hb_DirBase, hb_progname, exename, ... leto_getAppOptions( ... ), что дает доступ к путям, файлам настройки, паролей сервера может еще какие, сразу не вспомнишь. Все это, если надо можно организовать в hrb
| |
|
|
| Администратор
|
Пост N: 3479
Зарегистрирован: 23.05.05
|
|
Отправлено: 07.08.16 09:57. Заголовок: Из readme: Ena..
Из readme: EnableUDF = 1 - если 1 (по умолчанию), разрешено использование udf-функций с префиксом "UDF_", если 2, разрешено использование udf-функций с любыми именами, если 0, вызовы udf-функций запрещены; По умолчанию, при значении параметра 1, разрешены только вызовы функций с префиксом udf_, т.е. вызов UDF_AppendRec разрешен, а hb_DiskSpace, dbCreate и пр. - нет. При значении 2 разрешены вызовы всех функций. При значении 0 вызовы udf запрещены. Если хочется ограничить вызовы опасных функций, то пусть будет значение по умолчанию, в для hb_DiskSpace и пр. надо сделать обертки в letoudf.hrb: например udf_DiskSpace
| |
|
|
| постоянный участник
|
Пост N: 1143
Зарегистрирован: 17.02.12
|
|
Отправлено: 07.08.16 10:54. Заголовок: Pasha Спасибо. :sm..
Pasha Спасибо.
| |
|
|
|
| постоянный участник
|
Пост N: 1150
Зарегистрирован: 17.02.12
|
|
Отправлено: 08.08.16 19:51. Заголовок: Pasha Можно ли более..
Pasha Можно ли более информанивным сделать сообщение в log ERROR! UDF: not a valid name ? Добавить имя функции и источник, адрес
| |
|
|
| постоянный участник
|
Пост N: 1238
Зарегистрирован: 09.10.06
|
|
Отправлено: 08.08.16 20:26. Заголовок: Извините за возможно..
Извините за возможно глупый вопрос, а откуда можно скачать обновленные исходники, а то с sourceforge что-то не совсем свежее качается.
| |
|
|
| постоянный участник
|
Пост N: 1151
Зарегистрирован: 17.02.12
|
|
Отправлено: 08.08.16 21:01. Заголовок: Петр https://source..
| |
|
|
| постоянный участник
|
Пост N: 1239
Зарегистрирован: 09.10.06
|
|
Отправлено: 08.08.16 21:23. Заголовок: Спасибо за ссылку. ..
Спасибо за ссылку. цитата: | nParam = leto_GetParam( szData, &pp2, &pp3, NULL, NULL ); // leto_writelog( NULL, 0, "UDF: %s, CMD=%d\r\n", pp2, uiCommand ); |
| Павел не добавил закомментированную строку. Добавьте у себя, тогда сравнивая letodb.log и letodb_Х.log цитата: | 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 |
| цитата: | 127.0.0.1 MASTER-H test_udf.exe ERROR! UDF: not a valid name ERROR! UDF: not a valid name |
| вы б получили необходимую информацию. Как по мне, leto_wUsLog() нужно модифицировать для передачи дополнительной информации по типу leto_writelog() Ну и лог сервера вести без указания времени события как-то некрасиво, что-ли
| |
|
|
| постоянный участник
|
Пост N: 1152
Зарегистрирован: 17.02.12
|
|
Отправлено: 09.08.16 07:37. Заголовок: Петр пишет нужно мод..
Петр пишет цитата: | нужно модифицировать для передачи дополнительной информации ... лог сервера вести без указания времени события как-то некрасиво |
| Согласен. К имени функции и времени в доп. инф. важно идентифицировать и пользователя (имя, адрес, exe) по возможности ...
| |
|
|
| постоянный участник
|
Пост N: 1153
Зарегистрирован: 17.02.12
|
|
Отправлено: 09.08.16 07:59. Заголовок: Pasha Вопросик. В UD..
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 для такой ситуации ?
| |
|
|
| Администратор
|
Пост N: 3481
Зарегистрирован: 23.05.05
|
|
Отправлено: 09.08.16 08:32. Заголовок: Вызов leto_ParseReco..
Вызов 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
| |
|
|
| постоянный участник
|
Пост N: 1154
Зарегистрирован: 17.02.12
|
|
Отправлено: 09.08.16 09:37. Заголовок: Pasha пишет Поэтому ..
Pasha пишет цитата: | Поэтому лучше всего будет как раз возврат в udf массива записей с последующей их обработкой на клиенте: |
| Это понятный механизм цитата: | В случае набора произвольных записей такой способ был бы неправильным, так как это не является набором записей, следующих друг за другом последовательно. |
| Имеем на сервере 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 в результате 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 )
| |
|
|
| постоянный участник
|
Пост N: 1156
Зарегистрирован: 17.02.12
|
|
Отправлено: 09.08.16 11:22. Заголовок: PS Пояснение. Имеем ..
PS Пояснение. Имеем 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 или тут камень есть ?
| |
|
|
| постоянный участник
|
Пост N: 1157
Зарегистрирован: 17.02.12
|
|
Отправлено: 10.08.16 15:33. Заголовок: SergKis пишет Теоре..
SergKis пишет цитата: | Теоретически, вроде, ни что не мешает ? На клиенте ордер 2, на сервере отработали по ордеру 1 или тут камень есть ? |
| Pasha пишет цитата: | Поэтому лучше всего будет как раз возврат в udf массива записей с последующей их обработкой на клиенте: aRecs := leto_udf("udf_func", ...) for each cRec in aRecs leto_ParseRec(cRec) // обработка next |
| Pasha прав В итоге сделал так Скрытый текст
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
|
| |
|
|
|
| постоянный участник
|
Пост N: 5124
Зарегистрирован: 12.09.06
|
|
Отправлено: 08.10.16 10:18. Заголовок: Всем привет ! Вопрос..
Всем привет ! Вопрос возник по эксплуатации ЛетоДб. Перед отправкой записей в базу на сервер, я проверяю в папке наличие файла и считываю оттуда его содержимое. Типа ключа для каждой фирмы. Код в программе: IF !LETO_FILE(cFile) MsgStop( "Нет файла КЛЮЧА на сервере!" ) RETURN .F. ENDIF Периодически юзера жалуются на появление такой ошибки ! Проверяю в это же время сервер - доступен. Пока юзер не перегрузит комп, ошибка не уходит. Иногда и после перезагрузки остаётся. Как с этим бороться ?
| |
|
|
| Администратор
|
Пост N: 3496
Зарегистрирован: 23.05.05
|
|
Отправлено: 08.10.16 14:15. Заголовок: Можно описать ситуац..
Можно описать ситуацию подробнее ? Сервер находится тырнете или в локалке ? Коннект к серверу до выполнения leto_file выполнялся или нет ? Файл ключа все время существует или нет ? Что в cFile ? Коннект с сервером может прерваться или связь стабильная ? Без такого контекста отвечать на подобный вопрос трудно.
| |
|
|
| постоянный участник
|
Пост N: 5125
Зарегистрирован: 12.09.06
|
|
Отправлено: 08.10.16 21:20. Заголовок: Pasha пишет: Можно ..
Pasha пишет: цитата: | Можно описать ситуацию подробнее ? |
| Сервер в инете. Программа делает коннект до сервера и работает дальше, т.е. отправляет записи на сервер ЛетоДб через 1-5 минут. Спустя 1 час или 5 часов - начинается такая фигня. Инет стабильный, коннект вроде не прерывается. Содержимое в cFile - 20-40 символов. В момет появления ошибки, захожу со своего компа - файлы все на месте и сервер ЛетоДб нормально отвечает.
| |
|
|
| Администратор
|
Пост N: 3497
Зарегистрирован: 23.05.05
|
|
Отправлено: 09.10.16 08:57. Заголовок: Если сервер живой, и..
Если сервер живой, и файл на сервере существует, то логично предположить, что неудача leto_file связана с нарушением связи с сервером с этого клиента. В таком случае после if !LETO_FILE можно поставить проверку связи, например, вызовом функции LETO_MGGETINFO
| |
|
|
| moderator
|
Пост N: 1032
Зарегистрирован: 06.07.06
|
|
Отправлено: 09.10.16 09:29. Заголовок: Pasha пишет: В тако..
Pasha пишет: цитата: | В таком случае после if !LETO_FILE можно поставить проверку связи, например, вызовом функции LETO_MGGETINFO |
| Надо будет для проверки связи сделать ф-ю leto_Ping() - тем более, что команду такую сервер обрабатывает. Помнится, это чуть-ли не первая команда, которую я в свое время сделал.
| |
|
|
| moderator
|
Пост N: 1033
Зарегистрирован: 06.07.06
|
|
Отправлено: 09.10.16 09:37. Заголовок: Andrey пишет: Пока ..
Andrey пишет: цитата: | Пока юзер не перегрузит комп, ошибка не уходит. Иногда и после перезагрузки остаётся. |
| Вот это и в самом деле странно. Я бы до перезагрузки компа проверил ping к серверу - обычную команду ping, ну и если он проходит, то проверил бы как отрабатывает leto_Connection(). цитата: | Перед отправкой записей в базу на сервер, я проверяю в папке наличие файла и считываю оттуда его содержимое. |
| Немного не в тему, но: а почему бы не использовать здесь leto_var...() функции ?
| |
|
|
| Администратор
|
Пост N: 3498
Зарегистрирован: 23.05.05
|
|
Отправлено: 09.10.16 14:43. Заголовок: alkresin пишет: Над..
alkresin пишет: цитата: | Надо будет для проверки связи сделать ф-ю leto_Ping() - тем более, что команду такую сервер обрабатывает. Помнится, это чуть-ли не первая команда, которую я в свое время сделал. |
| Еще в файловых функциях вроде LetoFileExist можно добавить обработку: if( uiRes ) { ... } else s_iError = 1000; Можно вместо этого перенести установку if( !lRet ) s_iError = 1000; из функции leto_SendRecv в функцию leto_DataSendRecv Тогда ошибку связи с сервером во многих функциях, в том числе файловых, можно будет проверить вызовом LETO_FERROR()
| |
|
|
| постоянный участник
|
Пост N: 5126
Зарегистрирован: 12.09.06
|
|
Отправлено: 09.10.16 14:51. Заголовок: alkresin пишет: Нем..
alkresin пишет: цитата: | Немного не в тему, но: а почему бы не использовать здесь leto_var...() функции ? |
| Да наверно из-за не знания. Я когда начал изучать документацию по Лето, то не понял, для чего они. Самостоятельно не всегда знаешь/понимаешь что нужно в том или ином случае. Желательно бы в документацию включить доп.материалы для тех или иных действий и код приводить полностью. Например: 1) Коннект к серверу (это есть вроде) 2) Проверка доступности сервера и переподключение к серверу. 3) Проверка доступа клиента к базе, т.е. разрешение к записи/чтения к базе. Это я реализовал простой проверкой наличия файла (у каждой фирмы свой файл) и содержимого самого файла (типа ключа проверки). 4) Работа с базами на двух и более серверах ЛетоДБ 5) Синхронизация по таймеру ( и событию) локальной и серверной базы и наоборот с сервера на локальную. и т.д.
| |
|
|
| moderator
|
Пост N: 1035
Зарегистрирован: 06.07.06
|
|
Отправлено: 10.10.16 14:26. Заголовок: Pasha пишет: Можно ..
Pasha пишет: цитата: | Можно вместо этого перенести установку |
| Так и сделал. И Leto_Ping() добавил: возвращает .T., если все в порядке.
| |
|
|
| постоянный участник
|
Пост N: 5127
Зарегистрирован: 12.09.06
|
|
Отправлено: 10.10.16 17:57. Заголовок: Тогда код делать так..
Тогда код делать такой ? IF Leto_Ping() IF !LETO_FILE(cFile) MsgStop( "Нет файла КЛЮЧА на сервере!" ) RETURN .F. ELSE // передача записей на сервер MyWriteRecnoLetoDb() ENDIF ELSE MsgStop("Ошибка соединения с сервером LetoDB !") ENDIF А где коды ошибок для LETO_FERROR() ?
| |
|
|
|
| moderator
|
Пост N: 1036
Зарегистрирован: 06.07.06
|
|
Отправлено: 10.10.16 18:32. Заголовок: Andrey пишет: Тогда..
Andrey пишет: Пойдет. цитата: | А где коды ошибок для LETO_FERROR() ? |
| В тексте исходников :). 1000 - как раз сбой соединения.
| |
|
|
| постоянный участник
|
Пост N: 5129
Зарегистрирован: 12.09.06
|
|
Отправлено: 11.10.16 14:13. Заголовок: alkresin пишет: В т..
alkresin пишет: Спасибо ! Можно ли сделать следующие: при изменении базы на сервере - получать событие клиентам, что база изменилась ? Желательно бы и номер изменённой записи получать.
| |
|
|
| постоянный участник
|
Пост N: 1279
Зарегистрирован: 27.01.07
|
|
Отправлено: 11.10.16 14:25. Заголовок: Andrey пишет: Можно..
Andrey пишет: цитата: | Можно ли сделать следующие: при изменении базы на сервере - получать событие клиентам, что база изменилась ? |
| Клиент-серверная архитектура подразумевает следующий подход: клиент запросил - сервер ответил и забыл про клиента. Сам сервер не должен никому ничего слать без запроса. Т.е., для того, чтобы клиент знал про изменение баз, он должен сам об этом побеспокоиться.
| |
|
|
| moderator
|
Пост N: 1037
Зарегистрирован: 06.07.06
|
|
Отправлено: 11.10.16 14:57. Заголовок: Andrey пишет: при и..
Andrey пишет: цитата: | при изменении базы на сервере - получать событие клиентам, что база изменилась ? Желательно бы и номер изменённой записи получать. |
| Правильно тут написали: общение с сервером всегда происходит по схеме запрос - ответ, причем запрос может послать только клиент. Можно записывать информацию об изменениях в базе, например, в переменную LetoDB (leto_Var...() функции), это может делать как клиент, изменивший базу, так, наверное, и сервер в соответствующем триггере. Но чтобы другой клиент об этом узнал, ему надо время от времени, по таймеру например, читать эту переменную с сервера.
| |
|
|
| постоянный участник
|
Пост N: 5131
Зарегистрирован: 12.09.06
|
|
Отправлено: 12.10.16 00:42. Заголовок: alkresin пишет: Но ..
alkresin пишет: цитата: | Но чтобы другой клиент об этом узнал, ему надо время от времени, по таймеру например, читать эту переменную с сервера. |
| Тогда наверное алгоритм SergKis - построение индекса на сервере по полю TimeStamp (в базе) даёт более простой результат синхронизации БД на сервере и клиенте. Я алгоритм уже попробовал. Хотелось бы понять и другие. alkresin пишет: цитата: | Можно записывать информацию об изменениях в базе, например, в переменную LetoDB (leto_Var...() функции), это может делать как клиент, изменивший базу, так, наверное, и сервер в соответствующем триггере. |
| Не представляю как это сделать. Покажите пожалуйста схему как это делать.
| |
|
|
| moderator
|
Пост N: 1039
Зарегистрирован: 06.07.06
|
|
Отправлено: 12.10.16 10:07. Заголовок: Andrey пишет: Покаж..
Andrey пишет: цитата: | Покажите пожалуйста схему как это делать. |
| Схема самая простая. Есть Leto-переменные, каждая имеет свое имя, они собраны по группам, каждая группа тоже имеет свое имя. Предположим, вы решили сделать по группе для каждой базы - base1, base2, base3, ... и в каждой группе переменную modtime (modification time), куда будете записывать дату и время последнего изменения в том формате, который вам нравится. Программа при записи данных в базу пишет одновременно и в соответствующую переменную: leto_varSet( "base1", "modtime", xTime, LETO_VCREAT ) здесь xTime - текущие дата/время, LETO_VCREAT означает, что если переменная еще не существует, ее надо создать. Вот и все. А по таймеру читайте ее: IF !Empty( xTime := leto_varGet( "base1","modtime" ) ) ... ENDIF и предпринимайте соответствующие действия.
| |
|
|
| |
Пост N: 24
Зарегистрирован: 22.01.14
|
|
Отправлено: 13.10.16 14:18. Заголовок: Похожую ситуацию когда-то приходилось отрабатывать
Что-то подобное я делал(было дело!!): ... Здесь код изменения записи пользователем и сохранение в базе а далее отработка .... Leto_varDel("KRS",""),; leto_varSet( "KRS","var_cDate",DToC(Date()),LETO_VCREAT ),; // дата текущая создаем если нет переменную leto_varSet( "KRS","var_cTime",Time(),LETO_VCREAT ),; // время текущее создаем если нет переменную leto_varSet( "KRS","var_cCBU",cCBU,LETO_VCREAT ),; // CBU пользователя создаем если нет переменную IIF(lSchedul,(MsgTray("Изменение купли-продажи!", "Обновление!") , SysWait(3) , MsgTray(""), Popup_Var()),nil) // всплывающее сообщение пользователю ..... Функция Popup_Var() вызывается в таймере //---------------------------работаем с переменными сервера----------- //-----------------проверка для отправки сообщения пользователям Function Popup_Var() If !Empty(Secs( leto_varGet( "KRS","var_cTime" ))) IF (Secs(Time()) - Secs( leto_varGet( "KRS","var_cTime" ) )) > 2 MsgTray("Данные обновлены!" , "КЦ - " + leto_varGet( "KRS","var_cCBU" )) ; SysWait(5) ; MsgTray("") leto_varDel( "KRS","" ) // удаляет всю группу с переменными EndIf Else leto_varDel( "KRS","" ) // удаляет всю группу с переменными EndIf Return nil ... Функция MsgTray - выдает сообщение нужным пользователям об изменениях. Вот такой алгоритм. Правда все на FiveWin, но это сути не меняет.
| |
|
|
| |
Пост N: 1
Зарегистрирован: 11.01.24
|
|
Отправлено: 12.02.24 14:48. Заголовок: Помогите, пожалуйста, чайнику.
Первая установка letodb. Команда File не работает (файл есть, пишет .F.). Команда leto_file - тоже, т.к., по-моему, не читает letodb.ini (там разрешил файловые функции). Там путь прописан:DataPath ="/MYwrk/", а в log пишет DataPath =. Где копать?
| |
|
|
| постоянный участник
|
Пост N: 4515
Зарегистрирован: 17.02.12
|
|
Отправлено: 12.02.24 15:12. Заголовок: VI Вот рабочий вари..
VI Вот рабочий вариант установки Leto2011.exe (2-х поточная) и LetoDbF.exe (в ней изменены имена ini и log файлов на LetoDbF.*), совместная работа (это local работа - отладка, у клиента так же, но с адресами своими) Скрытый текст
Volume in drive D is DATA Volume Serial Number is E86E-69F5 Directory of D:\BK19\MiniGui\1_PRJ\EAlarm_1.3\INF 12.02.2024 13:53 <DIR> . 12.02.2024 13:53 <DIR> .. 20.12.2021 21:49 <DIR> BAK 19.12.2021 14:06 <DIR> BAKS 28.06.2022 11:36 <DIR> BIN 06.04.2022 16:29 <DIR> FDB 20.12.2021 22:05 <DIR> HBK 22.12.2021 15:56 <DIR> KLI 21.12.2021 18:44 902 656 leto2011.exe 06.04.2022 15:06 71 letodb.ini 21.04.2023 16:27 526 letodb.log 09.04.2021 06:25 1 450 496 letodbf.exe 21.12.2021 17:56 360 letodbf.ini 19.04.2023 20:38 1 335 letodbf.log 22.12.2021 15:49 899 072 LetoStart.exe 22.12.2021 15:51 898 048 LetoStart1.exe 19.04.2023 15:30 224 leto_users 19.04.2023 15:30 266 leto_users.cfg 19.12.2021 14:06 <DIR> LICENSE 18.04.2023 14:22 <DIR> WRK 15.02.2023 01:37 <DIR> XML 12.02.2024 13:53 0 _0.txt 05.04.2023 14:32 2 990 592 _ealarm.exe 19.12.2021 15:14 733 _ealarm.ini 16.09.2022 17:31 390 _test_ps1.bat 14 File(s) 7 144 769 bytes 11 Dir(s) 16 562 417 664 bytes free LetoDb.ini для Leto2011.exe [MAIN] Share_Tables = 1 Port = 2812 DataPath = . PathRun = . LetoDbF.ini для LetoDbF.exe [MAIN] Port = 2816 DataPath = .\ Default_Driver = CDX Share_Tables = 1 No_Save_WA = 1 Lower_Path = 0 EnableFileFunc = 1 EnableAnyExt = 1 Allow_UDF = 1 Pass_for_Login = 1 Cache_Records = 21 Debug = 0 Optimize = 1 DataBase = / Backup = /tmp/backup Mask = *.dbf,*.dbt,*.ntx Lock = 1 Seconds = 30 Wait = 1 ArcCmd = tar -cvzf /tmp/backup/leto.tar.gz /tmp/backup/* рабочее место клиента Volume in drive D is DATA Volume Serial Number is E86E-69F5 Directory of D:\BK19\MiniGui\1_PRJ\EAlarm_1.3\INF\KLI 12.02.2024 14:15 <DIR> . 12.02.2024 14:15 <DIR> .. 22.12.2021 15:59 <DIR> WRK 22.12.2021 15:56 <DIR> XML 21.12.2021 17:59 2 982 400 _ealarm.exe 22.12.2021 15:55 116 _ealarm.ini 3 File(s) 2 982 516 bytes 4 Dir(s) 16 562 417 664 bytes free ini рабочего места клиента [COM] PathXml = .\XML ; directory for excel reporting Host = 127.0.0.1 ; Port = 2816 ;
| Всегда работаю от текущего каталога, т.е. везде в путях стоят точки или .\ LetoDbF всегда добавляет DataPath к исп. именам файлов на клиенте эту добавку, попробуйте задать (внутри имя приводятся к одному разделителю, как надо). DataPath = C:\Mywrk от такого задания отказался из за копирования, так от текущего все забрал, вместе с настройками и ...
| |
|
|
| |
Пост N: 2
Зарегистрирован: 11.01.24
|
|
Отправлено: 12.02.24 15:48. Заголовок: Спасибо за то, что попытались помочь.
Как вижу, основная проблема в том, что функции Leto_file (и другие файловые) у меня не работают, хотя в .ini разрешены. И вообще, ни одна установка, отличная от заданного значения по умолчанию, не меняется (например, CDX/NTX). Letodb.ini лежит там же, где и запускаемый letodb.exe. Впрочем, и функция File() не работает тоже (а должна ли?), причем перебраны все возможные сочетания путей.
| |
|
|
| постоянный участник
|
Пост N: 4516
Зарегистрирован: 17.02.12
|
|
Отправлено: 12.02.24 16:02. Заголовок: VI Может дело в сбо..
VI Может дело в сборке сервера, у меня никогда не было такой штуки. Посмотрите в MiniGui пример SAMPLES\Advanced\LetoDbf, там был рабочий вариант сервера
| |
|
|
| постоянный участник
|
Пост N: 7682
Зарегистрирован: 12.09.06
|
|
Отправлено: 12.02.24 18:32. Заголовок: VI пишет: Впрочем, ..
VI пишет: цитата: | Впрочем, и функция File() не работает тоже (а должна ли?), причем перебраны все возможные сочетания путей. |
| Всё работает. Активно им пользовался раньше, и сейчас до сих пор работает.
| |
|
|
| |
Пост N: 3
Зарегистрирован: 11.01.24
|
|
Отправлено: 12.02.24 19:58. Заголовок: Спасибо. Буду пробовать дальше.
| |
|
Ответов - 54
, стр:
1
2
3
All
[только новые]
|
|
|