Пишу информационную систему на Free Pascal и PostgreSQL.
Изначально использовал стандартные компоненты (TPQConnection, TSQLQuery и т.д.).
Для того чтобы было проще рулить механизмами взаимодействия с БД - написал диспетчер компонентов.
Суть диспетчера - приведение любого компонента работающего с БД к единому интерфейсу. Таким образом, если мне понадобилось заменить компоненты доступа - надо для этих компонентов написать несколько наследников диспетчера. Для маленьких проектов это не рационально, а вот для больших... Очень даже. Такой подход так же подразумевает создание всех объектов доступа динамически, Но это уже другая история... Которую я опишу позже...
Итак, Zeos*.
Стандартные компоненты хорошо справлялись с поставленными тривиальными задачами, но наступил момент когда нам понадобилась обратная связь с сервером БД. Обратная связь средствами исключений не годится по понятным, думаю, причинам.
Конкретно мне было необходимо автоматически обновлять датасет на клиенте при наступлении определенных событий в базе данных.
Помимо Zeos, такими способностями обладает PostgreDAС... Но он платный - неприемлемо.
Для того чтобы использовать Zeos в совокупности с PostgreSQL, придется немного переделать исходники самого зеоса. Эта малая плата за бесплатность функционала который он предоставляет :).
Проблема в том что из-за синтаксических особенностей диалекта SQL который использует PostgreSQL, Zeos не всегда понимает, что выполняемый запрос синтаксически правильный. Придется подправить парсер следующим образом:
В модуле ZSQLStrings нужно заменить тело метода TZSQLStrings.RebuildAll:
Исходник (c) Oldwayder.
После этих манипуляций Zeos будет воспринимать все запросы корректно.
Далее столкнулся с проблемой длинны поля типа Float.
По умолчанию длинна равно 10 символам, включая знак числа и разделитель целой и дробной части. Т.е. числа с десятичной точностью величиной более миллиона будут отображаться некорректно. Это проблема пока не побеждена, т.к. запросы все динамические, а при каждом открытии осуществлять поиск вещественного числа и изменять количество символов отображения - это не выход...
Если кто знает как решить вопрос - буду благодарен за помощь. Ибо как раз сейчас с этим борюсь...
*в данной статье рассматривается Zeos 7.0
Изначально использовал стандартные компоненты (TPQConnection, TSQLQuery и т.д.).
Для того чтобы было проще рулить механизмами взаимодействия с БД - написал диспетчер компонентов.
Суть диспетчера - приведение любого компонента работающего с БД к единому интерфейсу. Таким образом, если мне понадобилось заменить компоненты доступа - надо для этих компонентов написать несколько наследников диспетчера. Для маленьких проектов это не рационально, а вот для больших... Очень даже. Такой подход так же подразумевает создание всех объектов доступа динамически, Но это уже другая история... Которую я опишу позже...
Итак, Zeos*.
Стандартные компоненты хорошо справлялись с поставленными тривиальными задачами, но наступил момент когда нам понадобилась обратная связь с сервером БД. Обратная связь средствами исключений не годится по понятным, думаю, причинам.
Конкретно мне было необходимо автоматически обновлять датасет на клиенте при наступлении определенных событий в базе данных.
Помимо Zeos, такими способностями обладает PostgreDAС... Но он платный - неприемлемо.
Для того чтобы использовать Zeos в совокупности с PostgreSQL, придется немного переделать исходники самого зеоса. Эта малая плата за бесплатность функционала который он предоставляет :).
Проблема в том что из-за синтаксических особенностей диалекта SQL который использует PostgreSQL, Zeos не всегда понимает, что выполняемый запрос синтаксически правильный. Придется подправить парсер следующим образом:
В модуле ZSQLStrings нужно заменить тело метода TZSQLStrings.RebuildAll:
procedure TZSQLStrings.RebuildAll;
var
Tokens: TStrings;
TokenValue: string;
TokenType: TZTokenType;
TokenIndex: Integer;
ParamIndex: Integer;
ParamIndices: TIntegerDynArray;
ParamIndexCount: Integer;
ParamName, SQL: string;
Tokenizer: IZTokenizer;
procedure NextToken;
begin
TokenType := TZTokenType({$IFDEF FPC}Pointer({$ENDIF}
Tokens.Objects[TokenIndex]{$IFDEF FPC}){$ENDIF});
TokenValue := Tokens[TokenIndex];
Inc(TokenIndex);
end;
begin
FParams.Clear;
FStatements.Clear;
SQL := '';
ParamIndexCount := 0;
SetLength(ParamIndices, ParamIndexCount);
{ Optimization for empty query. }
If Length(Trim(Text)) = 0 then
Exit;
{ Optimization for single query without parameters. }
if (not FParamCheck or (Pos(FParamChar, Text) = 0))
and (not FMultiStatements or (Pos(';', Text) = 0)) then
begin
FStatements.Add(TZSQLStatement.Create(Text, ParamIndices, FParams));
Exit;
end;
Tokenizer:=GetTokenizer;
Tokens := Tokenizer.TokenizeBufferToList(Text,
[toSkipComments, toUnifyWhitespaces]);
try
TokenIndex := 0;
repeat
NextToken;
{ Processes parameters. }
if ParamCheck and (TokenValue = FParamChar) then
begin
NextToken;
if (TokenType <> ttEOF) and (TokenValue <> FParamChar) and (TokenValue <> '=') then
begin
{ Check for correct parameter type. }
if not (TokenType in [ttWord, ttQuoted]) then
raise EZDatabaseError.Create(SIncorrectToken);
SQL := SQL + '?';
ParamName := TokenValue;
if (ParamName <> '') and (ParamName[1] in [#39, '`', '"', '[']) then
begin
ParamName := Tokenizer.GetQuoteState.
DecodeString(ParamName, ParamName[1]);
end;
ParamIndex := FindParam(ParamName);
if ParamIndex < 0 then
ParamIndex := FParams.Add(ParamName);
Inc(ParamIndexCount);
SetLength(ParamIndices, ParamIndexCount);
ParamIndices[ParamIndexCount - 1] := ParamIndex;
Continue;
end
else
if (TokenType <> ttEOF) and ((TokenValue = ':') or (TokenValue = '=')) then
SQL := SQL + ':';
end;
{ Adds a DML statement. }
if (TokenType = ttEOF) or (FMultiStatements and (TokenValue = ';')) then
begin
SQL := Trim(SQL);
if SQL <> '' then
FStatements.Add(TZSQLStatement.Create(SQL, ParamIndices, FParams));
SQL := '';
ParamIndexCount := 0;
SetLength(ParamIndices, ParamIndexCount);
end
{ Adds a default token. }
else
SQL := SQL + TokenValue;
until TokenType = ttEOF;
finally
Tokens.Free;
end;
end;
Исходник (c) Oldwayder.
После этих манипуляций Zeos будет воспринимать все запросы корректно.
Далее столкнулся с проблемой длинны поля типа Float.
По умолчанию длинна равно 10 символам, включая знак числа и разделитель целой и дробной части. Т.е. числа с десятичной точностью величиной более миллиона будут отображаться некорректно. Это проблема пока не побеждена, т.к. запросы все динамические, а при каждом открытии осуществлять поиск вещественного числа и изменять количество символов отображения - это не выход...
Если кто знает как решить вопрос - буду благодарен за помощь. Ибо как раз сейчас с этим борюсь...
*в данной статье рассматривается Zeos 7.0
Has this problem been reported to (and solved by) the zeoslib project for the upcoming stable release?
ОтветитьУдалитьI do not have such information... Sorry.
Удалить