Sabtu, 08 Januari 2011

FIREBIRD

Menulis UDFS untuk Embedded Firebird SQL Server

      Apa UDFS ?
 fungsi User-defined (UDFS) adalah host-bahasa program untuk melaksanakan tugas sering dibutuhkan, melengkapi built-in fungsi SQL seperti MIN () dan MAX (). UDFS adalah ekstensi untuk server Firebird dan melaksanakan sebagai bagian dari proses server. UDFS kata lain dikompilasi fungsi dan terkait dengan perpustakaan-link secara dinamis.
 Apa yang Anda butuhkan
 Untuk membaca artikel ini secara efektif Anda membutuhkan pengetahuan lanjutan dari C + +, C # dan Firebird SQL. Juga Anda memerlukan memiliki VS 2005 dengan C # dan C + + dipasang untuk membangun sampel. sampel telah memiliki "baterai dalam": semua file yang dibutuhkan untuk Firebird embedded server dan penyedia ADO.NET ditempatkan dalam folder Firebird sampel dan digunakan dalam membangun pasca-acara.
 Contoh struktur proyek
 \ Firebird. - Folder dengan semua file yang dibutuhkan untuk Firebird Embedded SQL Server
 |? \ Meliputi. - Folder dengan *. h file yang dibutuhkan untuk mengkompilasi UDFS
 |? \ Lib - folder. Dengan perpustakaan statis diperlukan untuk menghubungkan UDFS
 \ MainApp. - Sampel dikelola aplikasi
 \ SampleUdf. - UDFS sampel dll
 Tentang sampel
 Proyek sampel menunjukkan bagaimana untuk mentransfer data biner (BLOB) dari satu tabel menggunakan parser UDFS objek berbasis ke meja lain:
 [Kode dari] MainApp. \ \ Batch.sql

CREATE TABLE "RowDataTable" (
 "KUNCI Id" INTEGER NOT NULL PRIMARY
 "Nilai" blob
 )

CREATE TABLE "FSTable" (
 "KUNCI Id" INTEGER NOT NULL PRIMARY
 , "Nama" VARCHAR (256)
 , "FullPath" VARCHAR (256)
 , "CreationTime" TIMESTAMP
 , "Atribut" INTEGER
 , "Ukuran" BIGINT
 ) Menciptakan UDFS berbasis data biner parser
 UDFS Deklarasi
 Firebird SQL memiliki sintaks berikut untuk menyatakan UDF:
 MENYATAKAN FUNGSI EKSTERNAL nama [datatype | CSTRING (int)
[, Datatype | CSTRING (int) ...]]
RETURNS (datatype [DENGAN NILAI] | CSTRING (int)) [FREE_IT]
RETURNS [] n PARAMETER
ENTRY_POINT 'entryname'
MODULE_NAME 'modulename'; Argumen
 Deskripsi
 nama
 Nama UDF untuk digunakan dalam pernyataan SQL, dapat berbeda dari nama
 fungsi tertentu setelah kata kunci ENTRY_POINT
 datatype
 Datatype dari masukan atau kembali parameter
 • Semua parameter masukan diteruskan ke UDF dengan referensi
 parameter Kembali • dapat lulus dengan nilai
 • Tidak bisa sebuah elemen array
 RETURNS
 Menentukan nilai kembali dari fungsi. Perhatikan bahwa sintaks tidak memungkinkan untuk menyatakan bahwa tidak ada yang kembali UDF
 DENGAN NILAI
 Menetapkan bahwa nilai kembali harus dilalui oleh nilai bukan oleh referensi
 CSTRING (int)
 Menentukan UDF yang mengembalikan string int byte null-diakhiri panjang
 FREE_IT
 Membebaskan memori dialokasikan untuk nilai kembali setelah selesai menjalankan UDF. Parameter ini harus digunakan dengan alokasi memori ib_util_malloc dalam pelaksanaan fungsi UDF, It's terkandung dalam:
 Header: Perpustakaan ib_util.h: DLL ib_util_ms.lib: ib_util.dll RETURNS PARAMETER n
 Menentukan bahwa fungsi mengembalikan parameter input ke-n; diperlukan untuk kembali
 Gumpalan
 'Entryname'
 Dikutip string menetapkan nama UDF dalam kode sumber dan disimpan dalam
 UDF library
 'Modulename'
 Dikutip file spesifikasi mengidentifikasi dll yang berisi UDF
 Semua dll dengan UDFS harus ditempatkan ke folder UDF di root aplikasi tempat fbembedded.dll disimpan. Ketika permintaan akan deklarasi untuk mesin Firebird eksekusi tidak memerlukan dll UDF untuk ditempatkan dalam folder UDF pada saat itu. Tapi ketika menjalankan beberapa query disimpan prosedur penciptaan yang berisi mesin panggilan UDF diperlukan akan memeriksa fungsi eksternal dalam dll.
 Berikut adalah beberapa contoh deklarasi UDF dari proyek sampel:
 [Kode dari] MainApp. \ \ Batch.sql

 MENYATAKAN FUNGSI EKSTERNAL CreateParser
 Blob
 RETURNS INTEGER DENGAN NILAI
 MODULE_NAME SampleUdf_CreateParser ENTRY_POINT '' 'SampleUdf'

MENYATAKAN FUNGSI EKSTERNAL DestroyParser
 INTEGER
 RETURNS INTEGER DENGAN NILAI
 MODULE_NAME SampleUdf_DestroyParser ENTRY_POINT '' 'SampleUdf'

MENYATAKAN FUNGSI EKSTERNAL GetName
 INTEGER
 RETURNS CSTRING (256)
 MODULE_NAME SampleUdf_GetName ENTRY_POINT '' 'SampleUdf'

MENYATAKAN FUNGSI EKSTERNAL GetCreationTime
 INTEGER
 RETURNS TIMESTAMP FREE_IT
 MODULE_NAME SampleUdf_GetCreationTime ENTRY_POINT '' 'SampleUdf'

MENYATAKAN FUNGSI EKSTERNAL
GetSize
 INTEGER
 RETURNS BIGINT
 ENTRY_POINT 'SampleUdf_GetSize' MODULE_NAME 'SampleUdf' UDFS pelaksanaan
 Seperti yang Anda tebak, saya menggunakan parameter tipe integer untuk mengirim objek parser yang dibuat dalam tumpukan SampleUdf.dll. Dengan parser segala objek sangat sederhana:
 [Kode dari] main.cpp. SampleUdf \ \
 kelas SampleParser
(
 std:: vector _buffer char ;
 size_t _pathLen;
 char * _name;
publik:
 SampleParser (std:: vector char & buffer)
 (
 _buffer.swap (buffer);
 Char * path = (char *) & _buffer.at (0);
 _pathLen = strlen (path);
 if (_pathLen 1 | | _pathLen = _buffer.size ())
 membuang std:: exception ("Invalid format buffer");
 _name = strrchr (path, '\ \');
 if (_name)! _name path =;
 lain + + _name;
 / / ON_MESSAGE ("- SampleParser dibuat -")
 )
 ~ SampleParser ()
 (
 / / ON_MESSAGE ("- SampleParser hancur -")
 )

 Char * GetName () (return _name;)
Char * GetFullPath () (return (char *) dan _buffer.at (0);)
 __int64 * GetCreationTime () (return (__int64 *) & _buffer.at (_pathLen + 1);)
 int * GetAttributes () (return (int *) & _buffer.at (_pathLen + 1 + sizeof (__int64));)
 __int64 * GetSize () (return (__int64 *) & _buffer.at (_pathLen + 1 +
 sizeof (__int64) + sizeof (int));)
);
UDF berikutnya menunjukkan bagaimana parser dibuat dan juga bekerja dengan data blob:
 extern "C" __declspec (dllexport) SampleParser * SampleUdf_CreateParser
(BLOBCALLBACK data)
(
 mencoba
 (
 std:: vector buffer char (data- blob_total_length);
 ISC_UCHAR * p = (ISC_UCHAR *) & buffer.front ();
 untuk (ISC_LONG i = 0; blob_number_segments i data- ; i + +)
 (
 ISC_USHORT panjang = 0;
 data- blob_get_segment (blob_handle data- , p, data- blob_max_segment, & panjang);
 p + = panjang;
 )
 kembali baru SampleParser (buffer);
 )
 catch (std:: exception & ex)
 (
 ON_ERROR (ex.what ());
 )
 menangkap (...)
 (
 ON_ERROR ("Kesalahan tidak diketahui");
 )
 return 0;
)
Dan sekarang mari kita menunjukkan bagaimana menggunakan objek parser. Fungsi berikut juga menunjukkan cara untuk:
 mengubah struktur FILETIME untuk Firebird TIMESTAMP menggunakan server tertanam alokasi memori, saat Anda mentransfer kepemilikan memori ke database engine extern "C" __declspec (dllexport) ISC_TIMESTAMP * SampleUdf_GetCreationTime (int * ptr)
(
 mencoba
 (
 SampleParser * diri = (SampleParser *) (* ptr);

 FILETIME localtime;
 if (::! FileTimeToLocalFileTime ((* FILETIME const) self- GetCreationTime (), & localtime))
 return 0;
 SYSTEMTIME st;
 if (::! FileTimeToSystemTime (& localtime, & st))
 return 0;

 ISC_TIMESTAMP * timestamp = (ISC_TIMESTAMP *) ib_util_malloc (sizeof (ISC_TIMESTAMP));

 timestamp- timestamp_time = (st.wHour * 3.600.000 st.wMinute + * 60.000
+ St.wSecond * 1000 st.wMilliseconds +) * 10;

 KATA hari = st.wDay;
 KATA bulan = st.wMonth;
 KATA tahun = st.wYear;

 / / Perhitungan sihir dari kode Penyedia ADO.NET
 if (bulan 2)
 bulan -= 3;
 lain
 (
 bulan + = 9;
 tahun -= 1;
 )
 KATA c = tahun / 100;
 KATA ya = tahun - 100 * c;

 timestamp- timestamp_date = ((146.097 * c) / 4 + (1.461 * ya) / 4
+ (153 * bulan + 2) / 5 + hari + 1.721.119-2.400.001);
 kembali timestamp;
 )
 catch (std:: exception & ex)
 (
 ON_ERROR (ex.what ());
 )
 menangkap (...)
 (
 ON_ERROR ("Kesalahan tidak diketahui");
 )
 return 0;
)
Seperti yang Anda bisa melihat semua parameter masukan dan keluaran dalam implementasi UDF adalah petunjuk, kecuali parameter output dinyatakan dengan modifier NILAI OLEH. Tapi pengubah ini tidak dapat digunakan dengan semua jenis data (misalnya itu tidak kompatibel dengan TIMESTAMP, tapi kompatibel dengan BIGINT - perilaku aneh ini untuk jenis ukuran yang sama, bukan?)
 Menggunakan UDFS
 Prosedur tersimpan berikutnya menunjukkan cara menggunakan parser dibuat:
 [Kode dari] MainApp. \ \ Batch.sql
 CREATE PROSEDUR TransferData
RETURNS ("counter" INTEGER)
AS
MENYATAKAN VARIABLE "tmp" INTEGER;
MENYATAKAN VARIABLE "parserPtr" INTEGER;
MENYATAKAN VARIABLE "Nilai" blob;
MENYATAKAN VARIABLE "Nama" VARCHAR (256);
MENYATAKAN VARIABLE "FullPath" VARCHAR (256);
MENYATAKAN VARIABLE "CreationTime" TIMESTAMP;
MENYATAKAN VARIABLE "Atribut" INTEGER;
MENYATAKAN VARIABLE "Ukuran" BIGINT;
BEGIN
 "Counter" = 0;
 UNTUK PILIH "Nilai" FROM "RowDataTable" KE: "Nilai" DO BEGIN
 SELECT CreateParser (: "Nilai") FROM RDB database $ KE: "parserPtr";
 JIKA ("parserPtr" IS NOT NULL) THEN BEGIN
 SELECT GetName (: "parserPtr") FROM RDB $ database KE: "Nama";
 SELECT GetFullPath (: "parserPtr") FROM RDB $ database KE: "FullPath";
 SELECT GetCreationTime (: "parserPtr") FROM RDB $ database KE: "CreationTime";
 SELECT GetAttributes (: "parserPtr") FROM RDB $ database KE: "Atribut";
 SELECT GetSize (: "parserPtr") FROM RDB $ database KE: "Ukuran";

 "Tmp GEN_ID" = ("FSTable_Generator", 1);
 INSERT INTO "FSTable" ("Id" Nama, "", "FullPath", "CreationTime",
"Atribut", "Ukuran")
 VALUES (: "tmp",: "Nama",: "FullPath",: "CreationTime",: "Atribut",: "Ukuran");
 "Counter" = "counter" + 1;

 SELECT DestroyParser (: "parserPtr") FROM RDB $ database KE: "tmp";
 AKHIR
 AKHIR
 Suspend;
AKHIR Tentang aneh bentuk panggilan:
 SELECT UDF_Name ( Parameters_List ) FROM RDB $ database KE Output_parameter Ini satu-satunya cara untuk membuatnya bekerja dalam tertanam dll server:)
 Di luar inisialisasi
 Berkat jendela caching ada kemungkinan untuk me-load dan menginisialisasi UDFS dll sebelum dimuat oleh mesin database Firebird. Dalam sampel saya kemungkinan ini digunakan untuk membuat beberapa callback berguna:
 [Kode dari \ MainApp. \ SampleProvider.cs]
 void delegasi swasta MessageCallbackDelegate (
[MarshalAs (UnmanagedType.LPStr)] pesan string);

 swasta statis MessageCallbackDelegate messageCallback;
 swasta statis MessageCallbackDelegate errorCallback;

 [Dllimport ("UDF / SampleUdf")]
 extern void swasta statis RegisterCallbacks (MessageCallbackDelegate
messageCallback, MessageCallbackDelegate errorCallback);

 statis SampleProvider ()
 (
 messageCallback = MessageCallback;
 errorCallback = ErrorCallback;
 RegisterCallbacks (messageCallback, errorCallback);
 )
[Kode dari] main.cpp. SampleUdf \ \
 typedef void (__stdcall * FCallback) (pesan * const char);
FCallback g_messageCallback = 0;
FCallback g_errorCallback = 0;
//------------------------------------------------ ---------------------------
# Define ON_MESSAGE (berantakan) (if (g_messageCallback) g_messageCallback (mess);)
# Define ON_ERROR (berantakan) (if (g_errorCallback) g_errorCallback (mess);)
//------------------------------------------------ ---------------------------
extern "C" __declspec (dllexport) void RegisterCallbacks (FCallback messageCallback,
FCallback errorCallback)
(
 g_messageCallback = messageCallback;
 g_errorCallback = errorCallback;
)
Dan ketika mesin database Firebird akan mencoba untuk UDFS beban dll itu akan menggunakan Anda sudah diambil dan diinisialisasi perpustakaan.
 Kesimpulan
 Maka dengan ini artikel yang Anda lihat, bagaimana proses berbagi ruang nama alamat memungkinkan Anda untuk menggunakan benda-benda asli atau dikelola UDFS Anda.
 Download source code.

Tidak ada komentar:

Posting Komentar