Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  13:57[Войти] | [Зарегистрироваться]
Ответ на вопрос № 83899

26-09-2024 05:09
Потребовалось мне разработать UDF для Firebird. которая возвращала бы значение типа BLOB. Причём, бинарный, а не текстовый. Сделал по образу и подобию. Получение входных данных,  их преобразование и сохранение результирующих данных в буфер проблем не вызвало. А вот с переносом данных в выходной параметр возникли проблему.

Код примерно вот такой

procedure Buf2Blob(BufPtr: Pointer; BufLen: Integer; Blob: PBlob);
begin
  Blob^.blob_put_segment(blob^.blob_handle, PISC_UCHAR(BufPtr), BufLen);
end;


где BufPtr — указатель на данные, BufLen — размер буфера, а Blob — указатель на структуру BLOBCALLBACK.
Всё работает нормально за исключением пустяка: в выходной BLOB попадают данные только до первого нулевого байта. То есть получается, что данные воспринимаются как строка с терминальным символом. Как запихать в выходной BLOB все данные из буфера, ориентируясь на размер данных из BufLen?

Вопрос не критичный, так как проблему решили другим способом. Но если кто знает ответ, поделитесь, плиз. А то осталась заноза в голове.

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

04-10-2024 07:03 | Комментарий к предыдущим ответам
>>>Обычная строка, состоящая исключительно из печатных однобайтных символов. Скажем так — #$21..#$FE
  У нас с вами, здесь произошла небольшая терминологическая путаница.
  Функция get_code(), предназначена для вызова из sql запросов и объявляется как UDF (с помощью ddl). Собственно, на такие функции и налагаются жёсткие ограничения по типам параметров и механизму их передачи.
  Но здесь, вы всё правильно сделали. Передали строку посредством параметра типа CString.
  А вот "вспомогательная функция", для которой строка из первой функции "подаётся на вход другой функции, которая выделяет память и загоняет туда некий бинарник, полученный на основании этой строки" - хоть и находится в той же dll, предназначенной для FB, но уже UDF являться на может (поскольку не предполагает вызова из sql). Поэтому, для неё вы вольны использовать параметры любого типа (доступные в Delphi). И в общем-то, даже можно в параметрах передавать вместо PBlob, указатель на буфер обрабатываемых данных, предназначенных для PutSegment(). Другими словами, это обычная функция Delphi (и даже не cdecl, и не export).
  Я полагал, что у вас возникла ошибка именно в функции предназначенной для UDF.

04-10-2024 04:46 | Сообщение от автора вопроса
Обычная строка, состоящая исключительно из печатных однобайтных символов. Скажем так — #$21..#$FE
Даже пробелов нет. А вот потом эта строка подаётся на вход другой функции, которая выделяет память и загоняет туда некий бинарник, полученный на основании этой строки. И вот там уже могут быть все 255 возможных байт.

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

04-10-2024 01:33 | Вопрос к автору: запрос дополнительной информации
>>>//здесь некоторый код, который для строки S ...
  А под "строкой S" понимается именно текстовая строка (#$20..#$FF) и или же (#$00..#$FF)?

03-10-2024 13:50 | Сообщение от автора вопроса
>>> В вашем вопросе топика, функция была объявлена в библиотеке dll Delphi так
Ничуть того ни бывало. Это была вспомогательная процедура. А экспортировалась примерно такая процедура

procedure get_code(S: PAnsiChar; Blob: PBlob);
var
  BufPtr: Pointer;
  BufLen: Integer;
begin
// здесь некоторый код, который для строки S
// создаёт некоторый код, который загоняет в
// выделенную память размера BufLen, на которую
// указывает указатель BufPtr.
  try
    BufToBlob(BufPtr, BufLen, Blob);
  finally
    FreeMem(BufPtr);
  end;
end;



И объявлялась UDF в БД как-то так

DECLARE EXTERNAL FUNCTION GET_CODE
    CSTRING(255),
    BLOB
RETURNS PARAMETER 2
ENTRY_POINT 'get_code' MODULE_NAME 'coding';


За абсолютную точность не поручусь. Примерно так.

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

Какой точно был код раньше, и почему он загонял в BLOB только данные до первого нулевого байта, теперь уже установить не получится, так как в процессе экспериментов код многократно переписан. Главное — я всё же достиг нужного результата. Хотя бы для 32 разрядов

03-10-2024 11:36
>>>Про объявление понятно: я ж говорю, что у меня работает, только данные не все переносит, если есть нулевые байты.
  Если я правильно вас понял, то данные у вас передаются через параметр функции.
 
  Поэтому повторю.
  UDF - это функция, в терминологии Firebird. Вы создаёте библиотеку dll в Delphi. В этой dll создаёте экспортируемую функцию (или процедуру). Параметры этой функции записываются согласно синтаксису и типам языка Delphi. Затем, вы в FB выполняете скрипт ddl в котором создаёте метаданные в БД для этой функции (уже UDF). Параметры этой функции записываются согласно синтаксису и типам доступным в FB. (Таблица соответствия типов FB и Delphi приведена по ссылке в Обзорной статье).
  При использовании созданной библиотеки, она грузится в адресное пространство FB, как обычная dll. Но при вызове функции (UDF) из запроса, происходит вызов кода функции из dll не напрямую, а через некоторый промежуточный механизм. В частности, "типы данных Delphi" интерпретируются как "типы данных FB". А перед тем, как выполнить UDF, FB создаёт копии входных переменных в памяти, и передаёт указатели именно на эти копии.

  В вашем вопросе топика, функция была объявлена в библиотеке dll Delphi так:

procedure Buf2Blob(BufPtr: Pointer; BufLen: Integer; Blob: PBlob); cdecl;


  Соответствующее, предполагаемое описание этой UDF на ddl FB:

declare external function Buf2Blob
  cstring(254),
  integer,
  blob
  returns parameter 3


  При таком описании, первый параметр BufPtr, будет интерпретирован в UDF как строка с нулевым окончанием. И видимо, поэтому и "попадают данные только до первого нулевого байта".

  Попробуйте использовать вот такое описание:

procedure Buf2Blob(BlobSrc: PBlob; var BufLen: Integer; BlobDest: PBlob); cdecl; export;


  Соответствующее, описание этой UDF на ddl FB:

declare external function Buf2Blob
  blob,
  integer,
  blob
  returns parameter 3


03-10-2024 07:35
Про объявление понятно: я ж говорю, что у меня работает, только данные не все переносит, если есть нулевые байты.

Понял, что ничего не понял :-) Почему-то если экспортируемую функцию объявить в dpr-файлу, то не работает. А вот если вынести в отдельный юнит, то работает. Сделал тестовую UDF с тестовыми данными (похожими на настоящие) на Delphi-7 под 32-разрядный FireBird 2.5.

unit Funcs;

interface

type
  TBLOBGetSegmentFunc = function(Handle, BufPtr: Pointer; BufSize, MaxLength: Integer; var ReadLength: Integer): WORDBOOL; cdecl;
  TBLOBPutSegmentFunc = procedure(Handle, BufPtr: Pointer; BufSize: Integer); cdecl;
  TBLOBSeekFunc = function(Handle: Pointer; Mode, Offset: Integer): Integer; cdecl;

  TBLOB = record
    GetSegment: TBLOBGetSegmentFunc;
    Handle: Pointer;
    SegCount: Integer;
    MaxSegLength: Integer;
    TotalLength: Integer;
    PutSegment: TBLOBPutSegmentFunc;
    Seek: TBLOBSeekFunc;
  end;

procedure GetCode(I: Integer; var Blob: TBLOB); cdecl;

implementation

const
  DATA_SIZE = 12;
  DATA: array[0..(DATA_SIZE-1)] of Byte = (
    $78, $DA, $33, $34, $32, $36, $01, $00, $01, $F8, $00, $CB
  );

procedure GetCode(I: Integer; var Blob: TBLOB);
begin
  Blob.PutSegment(Blob.Handle, @DATA, DATA_SIZE);
end;

exports
  GetCode;

end.


Не факт, что правильно объявил все функции, но в PutSegment, судя по результату, угадал.

Вот такое объявление в базе данных

DECLARE EXTERNAL FUNCTION GETCODE
    INTEGER,
    BLOB
RETURNS PARAMETER 2
ENTRY_POINT 'GetCode' MODULE_NAME 'test_udf32';


Работает корректно, возвращает все 12 байт. Проверил на вот таком запросе
SELECT getcode(2) FROM rdb$database
Считаем вопрос решённым. Нужно просто очень аккуратно определять типы, выбирать правильную платформу и не забывать всюду совать CDECL (в FireDuck callback-функции определены с моделью вызова stdcall).

Предыдущий некорректно работающий пример привести не могу, так как я с ним экспериментировал до состояния полной неработоспособности :)

02-10-2024 02:54
>>>Получение входных данных, их преобразование и сохранение результирующих данных в буфер проблем не вызвало.
  Предполагается, что функции UDF будут вызываться внутри FB сервера. Поэтому кроме описания функции в исходном коде (*.pas), требуется ещё и её объявление на sql (declare external function ...). В "sql объявлении" допускаются только те типы, которые известны FB. Ожидается, что параметры в "исходном коде" функции и в её "sql объявлении" будут сопоставимы. Поскольку такой текст "sql объявления" вы не привели, предположу:
  - поскольку у вас первый аргумент функции имеет тип pointer, которого нет среди типов FB, он был преобразован к одному из строковых типов.
  - что в "sql объявлении", тип первого аргумента указан как CString. А CString – это строка символов, оканчивающаяся нулевым символом.
 
>>>Сделал по образу и подобию.
  Если не сложно, поделитесь ссылкой.

>>>Как запихать в выходной BLOB все данные из буфера, ориентируясь на размер данных из BufLen?
  1. Обзорная статья "об UDF на Delphi". В конце статьи, есть пример функции загрузки blob из файла:
http://www.ibase.ru/udf_ok/ 
  2. Библиотека FreeUDFLib. В файле BlobFncs.pas можно посмотреть примеры функций, использующих как входные, так и выходные параметры типа blob:
http://www.ibase.ru/d_udf/

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Вода мокрая или сухая?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования