Kemampuan RAD (Rapid Application Development) bahasa Pascal –tepatnya Delphi atau Lazarus– dikenal sangat memudahkan dalam pembuatan aplikasi database. Namun ternyata banyak juga pemrogram Pascal yg masih kesulitan membuat program database dengan Pascal tanpa bantuan RAD. Beberapa rekan pemrogram Pascal di komunitas Pascal Indonesia masih sering bertanya bagaimana membuat aplikasi database jika tidak menggunakan fitur RAD di Delphi atau Lazarus.
Salah satu kelemahan dari pemrograman RAD ala Delphi atau Lazarus adalah kemudahan yg menyembunyikan cara kerja sebenarnya di balik kemudahan tersebut. Pemrogram tinggal drag-n-drop komponen ke atas form, klik sana-sini, atur-atur propertinya, tulis kode-kode seperlunya, lalu voila… program pun bekerja. Nyaris semuanya bekerja secara otomatis. Apa yg terjadi di balik komponen dan bagaimana komponen bekerja, banyak pemrogram yg tidak paham. Komponen visual ala VCL atau LCL itu seperti kotak televisi yg kita terima apa adanya tanpa perlu tahu apa isi di dalamnya, yg penting televisi itu bekerja, titik. Mudah dan memanjakan, tetapi tidak memberikan ilmu.
Kelemahan tersebut baru terasa ketika pemrogram harus meninggalkan pola pemrograman RAD. Contohnya adalah ketika pemrogram harus menggunakan komponen database di aplikasi web atau console, yg tidak memiliki GUI (Graphical User Interface). Di pemrograman RAD, akses ke database bisa dilakukan nyaris tanpa menulis kode program. Cukup dengan menghubungkan komponen-komponennya, sesuaikan setting sana-sini, tuliskan query-nya, lalu data pun muncul dalam tabel (grid). Tanpa GUI, komponennya masih bisa digunakan sebagai class, tapi pemrogram RAD biasanya bingung bagaimana menggunakan komponen secara “manual”. Mereka bingung bagaimana melakukan koneksi ke database, menjalankan query dan mengambil datanya, menampilkan data yg diterima ke pengguna, dan lain sebagainya.
Nah… untuk itu, mari kita belajar membuat aplikasi database sederhana dengan cara “manual” menggunakan class yg tersedia di Free Pascal. Kita akan gunakan class-class dari unit SQLdb dan database-nya kita gunakan SQLite (versi 3). Kita menggunakan SQLdb karena merupakan bagian dari paket Free Pascal sehingga jika kita sudah memasang Free Pascal maka SQLdb pun (seharusnya) juga telah tersedia. Bagi pengguna Delphi, bisa menggunakan komponen dbExpress yg prinsip kerjanya agak mirip dengan SQLdb yaitu akses ke database melalui pustaka asli (native) yg disediakan database yg bersangkutan. Kita menggunakan SQLite karena SQLite mudah pemasangannya, kecil, cepat, ringan, dan mendukung fitur-fitur SQL yg baku dan umum. Di Linux atau Unix terbaru, SQLite biasanya sudah terpasang. Sementara di Windows, pemasangannya juga cukup mudah.
Sebelum kita mulai menulis program, pastikan terlebih dulu sudah terpasang Free Pascal dan SQLite di komputer kita. Lebih baik jika kita menggunakan versi yg terbaru. Untuk penyunting program, silakan gunakan aplikasi apa pun yg Anda suka untuk menulis program Pascal. Mungkin Lazarus yg paling umum, tetapi saya sendiri menggunakan VS Code.
Kita kali ini akan belajar dari sebuah contoh program yg sudah saya siapkan. Silakan unduh kode program dan berkas database dari gist di sini. Klik tombol Download ZIP
di sisi kanan atas laman tersebut, atau langsung unduh saja dari sini, lalu bongkar (extract) berkas .zip
yg diperoleh. Sudah? Mari kita bahas…
Database yg akan kita gunakan dalam program, saya ambil dari contoh yg disediakan oleh situs SQLite Tutorial di sini. Contoh database berupa berkas bernama chinook.db
dengan struktur data seperti dalam diagram berikut:
Database tersebut berisi 11 tabel dengan beberapa ribu baris data. Jumlah yg cukup bagi kita untuk belajar mengolah data dengan perintah-perintah SQL. Namun dalam tulisan ini saya hanya akan membahas pemrograman database dengan komponen SQLdb di Free Pascal. Sedang pemrograman dengan bahasa SQL di SQLite bisa Anda pelajari secara mandiri di situs SQLite Tutorial.
Contoh program hanya terdiri dari 1 berkas saja bernama chinook.lpr
. Saya namakan demikian karena program tersebut hanya untuk mengakses berkas data chinook.db
saja. Mari kita bahas isi dari program tersebut.
Pemrograman database dengan SQLdb dan SQLite membutuhkan setidaknya 2 unit, yaitu:
sqldb.pas
berisi komponen-komponen berikut:
TSQLConnection
untuk koneksi ke sistem database.TSQLTransaction
untuk manajemen transaksi data.TSQLQuery
untuk menjalankan perintah SQL.sqlite3conn.pas
berisi komponen berikut:
TSQLite3Connection
untuk akses data ke berkas SQLite. Class ini adalah turunan dari class TSQLConnection
dengan implementasi khusus untuk SQLite (versi 3).Di Lazarus, penambahan unit dilakukan otomatis jika kita meletakkan komponen-komponen visual SQLdb dari palet SQLdb ke form. Namun kali ini kita harus menambahkan sendiri di blok uses
di program Pascal kita. Masih ada beberapa unit lain dari paket komponen SQLdb untuk kegunaan dan manfaat yg berbeda, misalnya db.pas
, namun itu tidak dibutuhkan dalam program kita ini.
INFO: Selain SQLite, SQLdb juga menyediakan komponen untuk koneksi ke berbagai jenis sistem database seperti yg ditunjukan dalam gambar palet SQLdb di atas. Misalnya ke mySQL (atau MariaDB), Firebird, PostgreSQL, Oracle, MS SQL (melalui ODBC), dan lain sebagainya.
Selanjutnya mari kita bahas mulai dari bagian utama program. Silakan lompat ke baris nomor 235, kode yg kita lihat adalah sebagai berikut:
//# main program
begin
try
if openDB('chinook.db') then
begin
showTables(false);
repeat runQuery until quit;
end;
finally
closeDB;
end;
end.
Cukup singkat, jelas, dan mudah dimengerti, bukan? Bagian utama program berisi pasangan try...finally
yg mencoba membuka berkas data chinook.db
sebagai parameter pada pemanggilan fungsi openDB
, menampilkan tabel melalui prosedur showTables
, dan perulangan repeat...until
yg menjalankan query melalui prosedur runQuery
hingga selesai yg ditunjukkan oleh peubah quit
. Sebelum program berakhir, pastikan database ditutup melalui prosedur closeDB
.
CATATAN: Kita asumsikan berkas data
chinook.db
berada dalam folder yg sama dengan program sehingga cukup disebut nama berkasnya saja. Namun jika berbeda lokasi, sertakan tujuan (path) berkas dengan benar.
Hal pertama dalam olah data adalah tentu saja membuka koneksi ke sistem database yg akan digunakan. Untuk melakukan itu, perhatikan fungsi openDB
yg dimulai pada baris 21. Kodenya adalah sebagai berikut:
function openDB(const dbName: string): boolean;
begin
// create components
sqlite3 := TSQLite3Connection.Create(nil);
dbTrans := TSQLTransaction.Create(nil);
dbQuery := TSQLQuery.Create(nil);
slNames := TStringList.Create;
// setup components
sqlite3.Transaction := dbTrans;
dbTrans.Database := sqlite3;
dbQuery.Transaction := dbTrans;
dbQuery.Database := sqlite3;
slNames.CaseSensitive := false;
// setup db
sqlite3.DatabaseName := dbName;
sqlite3.HostName := 'localhost';
sqlite3.CharSet := 'UTF8';
// open db
if FileExists(dbName) then
try
sqlite3.Open;
result := sqlite3.Connected;
except
on E: Exception do
begin
sqlite3.Close;
writeln(sqlDBError(E.Message));
end;
end
else
begin
result := false;
writeln('Database file "',dbName,'" is not found.');
end;
end;
Sebelum bisa menggunakan komponen, kita harus membuat obyek dari class-nya terlebih dahulu. Itu yg dilakukan dalam blok komentar // create components
yg berisi pembuatan obyek sqlite3
, dbTrans
, dbQuery
, dan slNames
yg deklarasi variabelnya ada pada blok var
di baris nomor 8. slNames
adalah sebuah TStringList
untuk menampung daftar nama yg nanti akan kita butuhkan.
Selanjutnya adalah mengatur properti-properti penting di tiap obyek komponen tersebut. Itu dilakukan dalam blok komentar //setup components
yg berisi pengaturan properti Transaction
dan Database
di obyek sqlite3
, dbTrans
, dan dbQuery
. Perhatikan dengan baik bagaimana pengisian propertinya. Properti ketiga obyek tersebut harus saling terhubung dengan benar agar bisa saling bekerja sama.
Kemudian adalah mengatur properti koneksi database pada obyek sqlite3
yg dilakukan dalam blok komentar // setup db
. Properti DatabaseName
berisi tujuan (path) lengkap ke berkas data, nilainya diambil dari parameter dbName
. Properti HostName
diisi localhost
karena SQLite bekerja lokal (tanpa server). Properti CharSet
diisi UTF8
karena itu adalah encoding yg paling umum digunakan. Perlu diingat bahwa ini adalah pengaturan untuk SQLite, yg belum tentu sama pada sistem database yg lain. Sistem database yg berbeda bisa jadi membutuhkan pengaturan properti yg berbeda pula.
Setelah semua obyek dibuat, dihubungkan, dan diatur dengan benar, maka kita bisa membuka koneksi ke database dengan menjalankan prosedur Open
di obyek sqlite3
. Itu dilakukan dalam blok komentar // open db
. Menjalankan prosedur Open
perlu dilakukan dalam pasangan try...except
agar jika terjadi kegagalan bisa ditangani. Dalam hal ini jika ada kegagalan maka kita hanya menutup koneksi dan menampilkan pesan kesalahan yg diberikan oleh database.
Namun dalam program di atas, pasangan try...except
dilakukan dalam pengecekan berkas data dengan fungsi FileExists
. Ini perlu dilakukan karena berkas data SQLite bersifat lokal sehingga jika berkas data tidak ada maka kita bisa menampilkan pesan yg sesuai dan tidak perlu repot-repot membuka koneksi ke database. Selain itu juga karena SQLdb akan membuat berkas data baru jika berkas yg diminta tidak ditemukan. Pengecekan keberadaan berkas data mencegah hal tersebut.
Fungsi openDB
mengembalikan nilai bertipe boolean
. Nilai kembalian fungsi berasal dari status koneksi obyek sqlite3
properti Connected
yg dipadukan dengan kembalian fungsi FileExists
. Jika kembalian fungsi bernilai true
maka koneksi ke database sukses, sebaliknya jika bernilai false
maka koneksi gagal.
Apabila koneksi ke database berhasil, program menampilkan daftar tabel yg ada dalam berkas data yg dibuka. Ini dilakukan oleh prosedur showTables
. Prosedur showTables
dimulai pada baris nomor 77 dengan kode sebagai berikut:
procedure showTables(const clear: boolean = true);
var
i,j: integer;
begin
if clear then ClrScr;
// get and print list of tables
sqlite3.GetTableNames(slNames,false);
if slNames.Count > 0 then
begin
writeln('> "',sqlite3.DatabaseName,'" has ',slNames.Count,' table(s):');
j := 0;
for i := 0 to slNames.Count-1 do
// fix included system tables bug
if LowerCase(Copy(slNames[i],1,7)) <> 'sqlite_' then
begin
j := j+1;
writeln(j,'. ',slNames[i]);
end;
writeln('Found ',j,' data table(s).');
end
else
writeln('> "',sqlite3.DatabaseName,'" has no tables.');
end;
Yg pertama dilakukan adalah membersihkan layar jika diperlukan, berdasarkan parameter clear
. Kemudian mengambil daftar nama tabel data dengan memanggil prosedur GetTableNames
dari obyek sqlite3
. Prosedur tersebut mengembalikan daftar tabel melalui parameter pertama bertipe TStringList
di mana kita sudah siapkan variabel slNames
untuk menampungnya. Parameter kedua bertipe boolean
untuk kondisi penyertaan tabel sistem (bersifat internal dan tersembunyi). Kita berikan nilai false
ke parameter kedua yg artinya program tidak butuh tabel sistem disertakan dalam daftar.
Selanjutnya, program melihat apakah berkas data yg kita buka memiliki tabel atau tidak, dengan cara mengecek jumlah baris melalui properti Count
di obyek slNames
. Jika memiliki tabel (properti Count
bernilai lebih dari 0) maka program menampilkan informasi jumlah tabel, diikuti tampilan daftar nama tabel yg ditampung dalam obyek slNames
dengan perulangan for...do
.
Namun rupanya ada sedikit kesalahan (bug) dalam komponen TSQLite3Connection
karena prosedur GetTableNames
dengan parameter kedua bernilai false
masih mengembalikan sebagian tabel sistem. Dalam kasus ini, seharusnya mengembalikan 11 tabel data, ternyata mengembalikan 13 tabel di mana 2 di antaranya adalah tabel sistem. Kesalahan ini terekam dalam video demo program di bawah dan baru saya sadari setelah menontonnya. Kesalahan ini harus kita benahi.
SQLite menamai tabel sistemnya dengan awalan sqlite_
. Maka untuk menyembunyikan tabel sistem yg terikut dalam daftar slNames
cukup mudah, yaitu dengan hanya menampilkan tabel yg namanya tidak berawalan sqlite_
(7 huruf pertama). Blok seleksi if...then
dalam perulangan for...do
di atas yg melakukan itu. Lalu kita tambahkan informasi berapa jumlah tabel data yg sebenarnya. Dengan pengecekan itu maka jumlah tabel data yg tampil pun sesuai dengan berkas data, yaitu 11 tabel.
Kini program siap menerima perintah SQL dari masukan pengguna. Ini dilakukan oleh prosedur runQuery
yg berada di baris 202, yg kodenya sebagai berikut:
procedure runQuery;
var
p: integer;
q,s: string;
begin
if sqlite3.Connected then
begin
// query input
writeln('_____');
writeln('Enter SQL query:');
write('» ');
readln(q);
q := Trim(q);
// filter input to process custom commands
if q <> '' then
begin
// read first word
p := Pos(' ',q);
if p = 0 then p := Length(q) else p := p-1;
s := LowerCase(Copy(q,1,p));
// run query
if (s = 'quit') or (s = 'exit') then quit := true
else if (s = 'clear') and (p = Length(q)) then ClrScr
else if (s = 'tables') and (p = Length(q)) then showTables
else if s = 'schema' then showSchema(q)
else if s = 'select' then openQuery(q)
else execQuery(q);
end;
end;
end;
Prosedur runQuery
selalu mengecek apakah program masih tersambung ke database melalui properti Connected
dari obyek sqlite3
karena tidak mungkin menjalankan perintah SQL jika program terputus dari database. Selanjutnya menampilkan prompt untuk menerima masukan dari pengguna. Masukan pengguna ditampung sebagai string
dalam variabel q
. Ini dilakukan dalam blok komentar // query input
.
Jika ada masukan dari pengguna, yaitu q
tidak berupa string
kosong, maka program menguji jenis perintah apa yg diberikan pengguna lalu memanggil perintah yg sesuai. Jenis perintah ditentukan dari kata pertama dalam kalimat perintah. Pengambilan kata pertama dilakukan dalam blok komentar // read first word
. Pengujian ini diperlukan karena program kita tidak hanya menerima perintah SQL tapi juga beberapa perintah khusus yg tidak disediakan SQLite, yaitu:
quit
atau exit
untuk menghentikan program.clear
untuk membersihkan layar.tables
untuk menampilkan daftar tabel data.schema <table>
untuk menampilkan struktur tabel.Perintah SQL perlu dibedakan juga karena SQLdb punya perintah yg berbeda untuk membaca data dan mengubah data. Perintah SQL untuk membaca data umumnya adalah select
, maka itu harus kita deteksi dalam masukan pengguna. Perintah SQL selain select
kita anggap perintah untuk mengubah data. Pengujian jenis perintah dilakukan dalam blok komentar // run query
.
Jika kata pertama masukan pengguna adalah select
maka program akan memanggil prosedur openQuery
dengan parameter sql
bertipe string
. Prosedur openQuery
bekerja dengan obyek dbQuery
yg dimulai dari baris 127 dengan kode sebagai berikut:
procedure openQuery(const sql: string);
var
i: integer;
begin
try
// fetch data
dbQuery.SQL.Text := sql;
dbQuery.Open;
if dbQuery.Active then
begin
ClrScr;
writeln('> Fetching: "',sql,'"');
// get and print headers
dbQuery.GetFieldNames(slNames);
for i := 0 to slNames.Count-1 do write('| ',UpperCase(slNames[i]),' ');
writeln;
// iterate rows
while not dbQuery.EOF do
begin
// print cell by column
for i := 0 to dbQuery.FieldCount-1 do
write('| ',dbQuery.Fields.Fields[i].AsString,' ');
writeln;
dbQuery.Next;
end;
// print summary
writeln('Found ',dbQuery.RecordCount,' record(s).');
end;
dbQuery.Close;
except
on E: Exception do writeln(sqlDBError(E.Message));
end;
end;
Masukan dari pengguna tidak bisa dijamin selalu benar, oleh karena itu perintah SQL yg diberikan pengguna harus dijalankan dalam pasangan try...except
untuk menangkap kesalahan yg terjadi dan menampilkan pesan kesalahan dari database. Kemudian program memberikan perintah SQL dari parameter sql
ke properti SQL.Text
, lalu menjalankan prosedur Open
. Ini dilakukan dalam blok komentar // fetch data
.
Jika prosedur Open
sukses, ditunjukkan dengan properti Active
bernilai true
, maka program akan menampilkan tabel data. Diawali dengan menampilkan daftar nama kolom tabel, yg dilakukan dalam blok komentar // get and print headers
, yaitu dengan menjalankan prosedur GetFieldNames
yg kembaliannya ditampung dalam slNames
. Kemudian perulangan for...do
untuk menampilkan daftar nama kolom sebagai baris pertama.
Selanjutnya program melakukan perulangan untuk mengambil setiap baris data yg ada, dari baris pertama hingga baris terakhir. Caranya adalah perulangan while...do
dengan mengecek akhir baris melalui properti EOF
(end of file). Tampilkan data pada setiap baris dengan perulangan for..do
untuk membaca data di tiap kolomnya. Jumlah kolom ada di properti FieldCount
dan indeks kolom dimulai dari 0
. Jangan lupa memanggil prosedur Next
di akhir perulangan while...do
agar perulangan tidak tertahan (stuck) di baris pertama.
Setelah tabel, program menampilkan info ringkasan tabel berupa jumlah baris data yg diterima. Jumlah baris data ada di properti RecordCount
. Dan terakhir adalah menutup perintah SQL dengan memanggil prosedur Close
. Selesailah rangkaian proses menampilkan data dari perintah select
.
Jika perintah dari pengguna bukan 5 perintah yg sudah ditentukan di atas, maka program menganggap itu adalah perintah untuk mengubah data. Program menjalankan prosedur execQuery
dengan parameter sql
bertipe string
. Prosedur execQuery
dimulai dari baris nomor 103 dengan kode sebagai berikut:
procedure execQuery(const sql: string);
begin
try
// execute command
dbQuery.SQL.Text := sql;
dbTrans.Active := true;
dbQuery.ExecSQL;
// print info
writeln('> Executing: "',sql,'"');
writeln('Affected ',dbQuery.RowsAffected,' record(s).');
// commit changes
dbTrans.Commit;
except
on E: Exception do
begin
// rollback changes
dbTrans.Rollback;
writeln(sqlDBError(E.Message));
end;
end;
end;
Mengubah data harus dilakukan dalam transaksi agar jika ada kesalahan data bisa dibatalkan. Dalam SQLdb, transaksi data ditangani oleh class TSQLTransaction
yg dalam program ini berupa obyek dbTrans
. Sebagaimana prosedur runQuery
, kode dalam prosedur execQuery
juga dilakukan dalam pasangan try...except
untuk menangkap kesalahan perintah dari pengguna.
Prosedur execQuery
dimulai dengan memberikan perintah SQL dari parameter sql
ke properti SQL.Text
di obyek dbQuery
. Lalu memulai transaksi dengan memberikan nilai true
pada properti Active
di obyek dbTrans
. Kemudian menjalankan prosedur ExecSQL
di obyek dbQuery
. Ini yg dilakukan dalam blok komentar // execute command
.
Jika perintah SQL berhasil dijalankan maka properti RowsAffected
di obyek dbQuery
akan berisi jumlah baris data yg berubah akibat perintah tersebut. Info ini kita tampilkan ke pengguna. Kemudian pastikan perubahan data tersimpan ke berkas data dengan memanggil prosedur Commit
di obyek dbTrans
.
Jika perintah SQL ternyata gagal maka ini ditangkap oleh blok except
yg melakukan pembatalan perubahan data dengan memanggil prosedur Rollback
di obyek dbTrans
. Kemudian menampilkan pesan kesalahan ke pengguna.
SQLdb telah menyediakan beberapa prosedur untuk mengambil info struktur tabel, misalnya prosedur GetTableNames
dan GetFieldNames
di atas. Namun itu hanya mengembalikan namanya saja, tidak termasuk tipe data kolom dan info-info lainnya. Untungnya, SQLite menyediakan fitur membaca struktur tabel melalui perintah SQL. Mari kita gunakan fitur tersebut.
Menampilkan info struktur tabel dilakukan dengan perintah schema
diikuti nama tabel. Perintah itu ditangani oleh prosedur showSchema
yg dimulai pada baris nomor 167 dengan kode sebagai berikut:
procedure showSchema(const sql: string);
var
i,p: integer;
t: string;
begin
// check table name
p := Pos(' ',sql);
if p = 0 then writeln('ERROR: Schema requires a table name.');
if p = 0 then exit;
// check table existence
sqlite3.GetTableNames(slNames,false);
t := LowerCase(Copy(sql, p+1, Length(sql)-p));
p := slNames.IndexOf(t);
if p = -1 then writeln('ERROR: Table "',t,'" is not found.');
if p = -1 then exit;
// fetch table schema
try
ClrScr;
writeln('> Schema of "',t,'"');
// schema command
dbQuery.SQL.Text := 'select name, sql from sqlite_master '+
'where type="table" and name="'+t+'"';
dbQuery.Open;
// print schema
writeln(dbQuery.Fields.Fields[1].AsString);
dbQuery.Close;
except
on E: Exception do writeln(sqlDBError(E.Message));
end;
end;
Karena perintah schema
membutuhkan nama tabel, hal pertama yg dicek adalah parameter kedua. Jika tidak disertakan nama tabel maka perintah dihentikan. Ini dilakukan dalam blok komentar // check table name
. Selanjutnya adalah mengecek keberadaan tabel yg diminta dalam daftar nama tabel. Jika tabel yg diminta tidak ditemukan maka perintah dihentikan. Ini dilakukan dalam blok komentar // check table existence
.
Jika tabel dipastikan ada dan tersedia maka dilakukan pembacaan struktur tabel dengan perintah SQL select
ke tabel sistem bernama sqlite_master
. Caranya sama dengan cara mengambil data di atas. Bedanya tidak perlu dilakukan perulangan karena data yg dikembalikan database bisa dipastikan hanya 1 baris saja.
Setelah menjalankan perintah SQL dari pengguna, program kembali menungggu perintah SQL selanjutnya. Demikian seterusnya hingga pengguna memberikan perintah quit
atau exit
untuk menghentikan program. Jika perintah tersebut diterima maka program memanggil prosedur closeDB
dan program berakhir.
Fungsi openDB
tidak selalu berhasil melakukan koneksi ke database. Karena satu dan lain hal, kegagalan koneksi bisa saja terjadi. Seperti yg ditunjukkan dalam bagian utama program, ketika fungsi openDB
gagal (mengembalikan nilai false
), atau perulangan repeat...until
selesai, maka program akan masuk ke bagian finally
di mana ada pemanggilan prosedur closeDB
. Mari kita perhatikan apa isi dari prosedur tersebut.
Prosedur closeDB
dimulai pada baris nomor 60 dengan kode sebagai berikut:
procedure closeDB;
begin
// disconnect
if sqlite3.Connected then
begin
dbTrans.Commit;
dbQuery.Close;
sqlite3.Close;
end;
// release
slNames.Free;
dbQuery.Free;
dbTrans.Free;
sqlite3.Free;
end;
Cukup singkat saja. Ada 2 hal yg dilakukan dalam prosedur closeDB
, yaitu pertama adalah memutuskan koneksi ke database jika koneksi sedang aktif (yg ditunjukkan oleh properti Connected
di obyek sqlite3
). Pemutusan dilakukan dengan menjalankan prosedur Close
pada obyek dbQuery
dan sqlite3
. Namun sebelum itu, dilakukan perintah Commit
pada obyek dbTrans
untuk menyimpan segala perubahan data yg telah terjadi ke database.
Selanjutnya adalah melepas sumber daya yg digunakan obyek-obyek komponen yg telah dibuat sebelumnya. Caranya dengan memanggil prosedur Free
pada obyek slNames
, dbQuery
, dbTrans
, dan sqlite3
. Dalam RAD, pelepasan sumber daya ini juga dilakukan otomatis oleh “pemilik” (owner) komponen, yg biasanya adalah form tempat komponen berada. Namun kali ini harus kita lakukan manual karena tidak ada “pemilik” komponen.
Berikut demo program chinook.lpr
dalam bentuk video (.gif
) yg direkam saat dijalankan dari VS Code.
CATATAN: Video di atas direkam saat kesalahan
TSQLite3Connection
belum dibenahi sehingga jumlah tabel yg muncul masih berjumlah 13. Kode program yg tersedia di gist telah membenahi kesalahan tersebut.
Dari uraian di atas, cukup jelas bahwa menulis program database secara “manual” tidak semudah drag-n-drop di RAD, tapi juga tidak sulit. Mungkin kodenya agak sedikit lebih panjang, tapi alurnya jelas dan mudah. Contoh program ini saya buat sesederhana mungkin dengan operasi dasar yg umum digunakan agar lebih mudah dipahami. Untuk operasi olah data dengan penanganan yg lebih rumit, silakan pelajari dari tautan-tautan yg disertakan. Namun demikian, secara umum mekanisme dasarnya tidak jauh berbeda dengan yg saya jelaskan di sini.
Contoh program ini masih sangat bisa dikembangkan lebih jauh atau ditambah fitur-fitur lain yg lebih menarik. Tekniknya juga bisa diterapkan dalam aplikasi web atau non-GUI lainnya. Semula contoh program ini akan saya buat sebagai aplikasi web dengan menggunakan unit WebCRT. Namun agar pembaca tidak terganggu dengan kode-kode web yg tidak terkait dengan olah data, maka saya urungkan rencana itu dan menjadikannya sebagai aplikasi console saja.
Bila pembaca menemukan kesalahan atau kekurangan dalam contoh program atau tulisan ini, dengan senang hati saya menerima segala saran, kritik, dan masukan dari Anda semua melalui kolom komentar. Terima kasih.
Demikian. Semoga bermanfaat.
———
💬 I welcome your comment here.
Thank you. 😊