Chuẩn bị cho kỳ thi 733 về Phát triển ứng dụng DB2 9, Phần 4: Lập trình
SQL nhúng
Xây dựng các ứng dụng có tương tác với DB2
Roger Sanders, Quản lý cao cấp, EMC
Tóm tắt: Hướng dẫn này giới thiệu cho bạn về lập trình SQL nhúng và dẫn bạn
qua từng bước làm thế nào để xây dựng một ứng dụng SQL nhúng. Hướng dẫn
này giới thiệu quá trình để chuyển đổi một hoặc nhiều tệp tin mã nguồn của ngôn
ngữ lập trình bậc cao có chứa SQL nhúng thành một ứng dụng có thể chạy được.
Đây là bài viết thứ tư trong một loạt gồm chín hướng dẫn được thiết kế để giúp
bạn chuẩn bị cho kỳ thi lấy chứng chỉ Nhà phát triển ứng dụng DB2 (kỳ thi 733).
Trước khi bạn bắt đầu
Về hướng dẫn này
Hướng dẫn này giới thiệu cho bạn về lập trình SQL nhúng và dẫn bạn qua từng
bước cơ bản làm thế nào để xây dựng một ứng dụng SQL nhúng. Hướng dẫn này
cũng giới thiệu cho bạn về việc chuyển đổi một hoặc nhiều tệp tin mã nguồn của
ngôn ngữ lập trình bậc cao có chứa SQL nhúng thành một ứng dụng có thể chạy
được. Trong hướng dẫn này, bạn sẽ tìm hiểu về:
Các câu lệnh SQL được nhúng vào một tệp tin mã nguồn của ngôn ngữ lập
trình bậc cao như thế nào.
Các bước liên quan đến việc phát triển một ứng dụng SQL nhúng.
Các biến chủ là gì, chúng được tạo ra như thế nào và chúng được sử dụng
như thế nào.
Các biến chỉ thị (indicator) là gì, chúng được tạo ra như thế nào và chúng
được sử dụng khi nào.
Làm thế nào để phân tích các nội dung của một biến cấu trúc dữ liệu của
một SQL Communications Area (SQLCA -Vùng trao đổi thông tin SQL).
Làm thế nào để thiết lập một kết nối cơ sở dữ liệu từ một ứng dụng SQL
nhúng.
Làm thế nào để nắm bắt và xử lý các lỗi khi chúng xuất hiện.
Làm thế nào để chuyển đổi các tệp tin mã nguồn có chứa các SQL nhúng
thành một ứng dụng có thể chạy được.
Trình tối ưu hóa DB2: Là một thành phần của trình tiền biên dịch
(precompiler) SQL chọn một kế hoạch truy cập cho một câu lệnh SQL của Ngôn
ngữ thao tác dữ liệu (DML - Data Manipulation Language) bằng cách mô hình hóa
chi phí thi hành của một số các kế hoạch truy cập thay thế được cho nhau và lựa
chọn kế hoạch có chi phí ước tính thấp nhất.
Giới thiệu về lập trình SQL nhúng
SQL và SQL nhúng
Ngôn ngữ truy vấn có cấu trúc hay SQL (Structured Query Language) là một ngôn
ngữ được tiêu chuẩn hóa để thao tác với các đối tượng cơ sở dữ liệu và dữ liệu
chứa trong chúng. SQL bao gồm một số các câu lệnh khác nhau, được sử dụng để
định nghĩa, thay đổi và hủy bỏ các đối tượng cơ sở dữ liệu và để chèn, sửa đổi, xóa
và lấy ra các giá trị dữ liệu. Nhưng vì SQL về bản chất là không có tính thủ tục,
nên SQL không phải là một ngôn ngữ lập trình mục đích chung. (Các câu lệnh
SQL được thực hiện bởi trình quản lý cơ sở dữ liệu DB2 (DB2 Database
Manager), chứ không phải bởi hệ điều hành). Do vậy, các ứng dụng cơ sở dữ liệu
thường được phát triển bằng cách kết hợp quyết định và kiểm soát tuần tự của một
ngôn ngữ lập trình bậc cao với các khả năng lưu trữ, thao tác và lấy ra các dữ liệu
của SQL. Một số phương pháp có sẵn để kết hợp SQL với một ngôn ngữ lập trình
bậc cao, nhưng cách tiếp cận đơn giản nhất là nhúng các câu lệnh SQL trực tiếp
vào các tệp tin mã nguồn của ngôn ngữ lập trình bậc cao đã được sử dụng để tạo ra
ứng dụng. Kỹ thuật này được gọi là lập trình SQL nhúng.
Một trong những mặt hạn chế khi phát triển các ứng dụng bằng cách dùng SQL
nhúng là ở chỗ các trình biên dịch (compiler) của ngôn ngữ lập trình bậc cao
không nhận ra và do đó không thể diễn giải được, các câu lệnh SQL được nhúng
trong một tệp tin mã nguồn. Do đó, các tệp tin mã nguồn có chứa các câu lệnh
SQL nhúng phải được xử lý trước (bằng một quá trình được gọi là tiền biên dịch)
trước khi chúng có thể được biên dịch và được liên kết để tạo ra một ứng dụng có
thể chạy được. Để tạo điều kiện thuận lợi cho việc tiền xử lý này, mỗi câu lệnh
SQL nhúng trong một tệp tin mã nguồn của ngôn ngữ lập trình bậc cao phải được
(nói cách khác, các kế hoạch truy cập của chúng phải được tạo ra và được lưu trữ
trong cơ sở dữ liệu) trước khi chúng có thể được thi hành. Hơn nữa, các câu lệnh
SQL tĩnh không thể bị thay đổi trong thời gian chạy và mỗi ứng dụng có sử dụng
SQL tĩnh phải kết buộc các gói hoạt động của nó với mọi cơ sở dữ liệu mà ứng
dụng sẽ tương tác. Ngoài ra, bởi vì các ứng dụng SQL tĩnh đòi hỏi biết trước về
các đối tượng cơ sở dữ liệu, các thay đổi được thực hiện cho những đối tượng đó
sau khi một ứng dụng đã được phát triển có thể sinh ra các kết quả không mong
muốn.
Sau đây là những ví dụ về các câu lệnh SQL tĩnh:
SELECT COUNT(*) FROM employee
UPDATE employee SET lastname = 'Jones' WHERE empid = '001'
SELECT MAX(salary), MIN(salary) INTO :MaxSalary, :MinSalary FROM
employee Nói chung, các câu lệnh SQL tĩnh rất phù hợp với các ứng dụng hiệu năng cao, thi
hành các hoạt động định sẵn đối với một tập hợp các đối tượng cơ sở dữ liệu đã
biết. SQL động
Mặc dù các câu lệnh SQL tĩnh tương đối dễ dàng để kết hợp vào một ứng dụng,
việc sử dụng của chúng có một chút bị hạn chế do khuôn dạng của chúng phải
được biết trước. Các câu lệnh SQL động, mặt khác, linh hoạt hơn nhiều, vì chúng
có thể được xây dựng trong thời gian chạy ứng dụng; thông tin về cấu trúc của câu
lệnh SQL động và các đối tượng mà nó có kế hoạch tương tác với các đối tượng
đó không cần phải được biết trước. Hơn nữa, các câu lệnh SQL động không có
một định dạng được mã hóa trước, cố định, các đối tượng dữ liệu mà chúng tham
Bắt đầu của một phần khai báo được định nghĩa bởi câu lệnh BEGIN DECLARE
SECTION, còn kết thúc phần khai báo được định nghĩa bởi câu lệnh END
DECLARE SECTION. Vì vậy, một phần khai báo tiêu biểu trong một tệp tin mã
nguồn C/C++ trông giống như:
// Define The SQL Host Variables Needed
EXEC SQL BEGIN DECLARE SECTION;
char EmployeeID[7];
char WorkDept[4];
char Job[9];
char Sex[2];
double Salary;
double Bonus;
double Commision;
EXEC SQL END DECLARE SECTION;
Một phần khai báo có thể được viết mã bất cứ ở đâu mà các khai báo biến ngôn
ngữ lập trình bậc cao có thể được viết trong một tệp tin mã nguồn. Và mặc dù một
tệp tin mã nguồn thường chỉ chứa một phần khai báo, nhưng có thể cho phép
nhiều phần khai báo. Các biến chủ để chuyển dữ liệu vào một cơ sở dữ liệu được
gọi là các biến chủ đầu vào, trong khi các biến chủ để nhận dữ liệu từ một cơ sở
dữ liệu được gọi là các biến chủ đầu ra. Bất kể một biến chủ được sử dụng cho đầu
vào hay đầu ra, các thuộc tính của nó phải phù hợp với bối cảnh trong đó nó được
sử dụng. Vì vậy, bạn phải định nghĩa các biến chủ sao cho các kiểu dữ liệu của
chúng và các chiều dài của chúng là tương thích với các kiểu dữ liệu và các chiều
dài của các đối tượng cơ sở dữ liệu mà chúng được dự định để làm việc với các
đối tượng cơ sở dữ liệu đó. Ngoài ra, mỗi biến chủ được sử dụng trong một ứng
dụng cũng phải được gán một tên duy nhất không được phép có tên trùng lặp
Trong ví dụ này, khi bạn thi hành câu lệnh SQL SELECT empno, lastname FROM
employee WHERE empno = '000100', các kết quả được chuyển giao tới các biến
chủ EmployeeNo và LastName. Các lệnh và các hàm được sử dụng để làm cho
chuyển giao này thực sự xảy ra được thêm vào khi tệp tin mã nguồn được biên
dịch. Khai báo các biến chỉ thị
Theo mặc định, các cột trong một bảng cơ sở dữ liệu DB2 có thể chứa các giá trị
null. Và do các giá trị null không được lưu trữ giống như cách mà dữ liệu truyền
thống được lưu giữ, nên phải có các điều kiện đặc biệt nếu một ứng dụng dự định
làm việc với các dữ liệu null. Các giá trị null không thể được lấy ra và được sao
chép tới các biến chủ theo cùng một cách giống như có thể làm với các giá trị dữ
liệu khác. Thay vào đó, một cờ đặc biệt phải được kiểm tra để xác định xem liệu
một giá trị cụ thể có nghĩa là null hay không. Và để có được giá trị của cờ này,
một biến chủ đặc biệt được gọi là một biến chỉ thị (hoặc biến chỉ thị null) phải
được kết hợp với một biến chủ đã gán cho một cột có thể nhận giá trị null.
Bởi vì các biến chỉ thị có thể được truy cập bởi cả hai Trình quản lý cơ sở dữ liệu
DB2 lẫn chương trình ứng dụng, chúng cũng phải được định nghĩa trong một phần
khai báo. Chúng cũng phải được gán một kiểu dữ liệu tương thích với kiểu dữ liệu
DB2 SMALLINT. Do đó, mã được sử dụng để định nghĩa một biến chỉ thị trong
tệp tin mã nguồn C/C++ sẽ trông giống như sau:
// Define The SQL Host Variables Needed
EXEC SQL BEGIN DECLARE SECTION;
short SalaryNullIndicator;
EXEC SQL END DECLARE SECTION; Một biến chỉ thị được kết hợp với một biến chủ cụ thể khi nó đứng sau biến chủ
// If The Cursor Was Opened Successfully, Retrieve And
// Display All Records Available
while (sqlca.sqlcode == SQL_RC_OK)
{
// Retrieve The Current Record From The Cursor
EXEC SQL FETCH cursor1 INTO :EmployeeNo, :Salary :SalaryNI;
// If The Salary Value For The Record Is NULL,
if (SalaryNI < 0)
{
printf("No salary information is available for ");
printf("employee %s\n", EmployeeNo);
}
}
// Close The Open Cursor
EXEC SQL CLOSE C1;
Các biến chỉ thị cũng có thể được dùng để gửi các giá trị null tới một cơ sở dữ liệu
khi một hoạt động chèn hoặc cập nhật được thực hiện. Khi xử lý các câu lệnh SQL
INSERT và UPDATE, Trình quản lý cơ sở dữ liệu DB2 kiểm tra đầu tiên các giá
trị của bất kỳ các biến chỉ thị nào được cung cấp, nếu một hoặc nhiều biến chỉ thị
có chứa một giá trị âm, nó gán một giá trị null vào cột thích hợp, với điều kiện là
cột có thể nhận giá trị null. (Nếu biến chỉ thị được gán bằng không hoặc có chứa
một số dương, hoặc nếu không có biến chỉ thị nào được sử dụng, thì thay vào đó,
Trình quản lý cơ sở dữ liệu DB2 gán giá trị được lưu trữ trong biến chủ tương ứng
với cột thích hợp). Do vậy, mã được sử dụng trong tệp tin mã nguồn C/C++ để gán
Mô tả
sqlcaid CHAR(8)
Một dấu hiệu bắt mắt (eye catcher)
dùng cho phần kết xuất nội dung
lưu trữ. Để giúp nhận biết trực
quan cấu trúc dữ liệu, phần tử này
thường chứa giá trị "SQLCA". N
ếu
thông tin số thứ tự dòng được trả
về từ việc phân tích phần thân thủ
tục SQL, byte thứ sáu có chứa ký
tự L.
sqlcabc
INTEGER
Kích cỡ tính theo byte, của chính
cấu trúc dữ liệu SQLCA. Phần tử
này sẽ luôn chứa giá trị 136.
sqlcode
INTEGER
Giá trị mã trả về SQL. Một giá trị
là 0 biểu thị việc thi hành thành
công, một giá trị dương biểu thị
việc thi hành với các cảnh báo và
một giá trị âm biểu thị một lỗi.
Tham khảo DB2 Message
Reference, các tập 1 và 2 hướng
dẫn sử dụng sản phẩm (xem Tài
một mã có ba chữ cái xác định
phiên bản và bản phát hành c
ủa sản
phẩm và tiếp theo là 5 năm ký số
để xác định mức sửa đổi của sản
phẩm. Ví dụ, SQL09010 có nghĩa
là DB2 phiên bản 9, bản phát hành
1, mức sửa đổi 0. Nếu phần tử
sqlcode chứa một giá trị âm, phần
tử này sẽ chứa một mã có tám ký t
ự
để nhận dạng mô-đun đư
ợc báo cáo
có lỗi.
sqlerrd
INTEGER
ARRAY
Một mảng gồm sáu giá trị số
nguyên để cung cấp các thông tin
chẩn đoán thêm khi một lỗi xảy ra.
(Tham khảo Bảng 2 để biết thêm
thông tin về các thông tin chẩn
đoán có thể được trả lại trong phần
tử này).
sqlwarn
CHAR(11)
Một mảng của các giá trị ký tự để
dùng như các chỉ thị cảnh báo; mỗi
phần tử của mảng có chứa hoặc
N
ếu một kết nối được thiết lập thành công,
phần tử này có chứa sự khác biệt dự tính về
chiều dài của dữ liệu ký tự hỗn hợp (các kiểu
dữ liệu CHAR) khi nó được chuyển đổi từ
trang mã của ứng dụng được sử dụng thành
trang mã cơ sở dữ liệu được sử dụng. Một giá
trị là 0 hoặc 1 biểu thị rằng dự đoán trước là
(chiều dài) không được mở rộng thêm; một giá
trị dương lớn hơn 1 biểu thị rằng có khả năng
mở rộng thêm chiều dài và một giá trị âm biểu
thị khả năng giảm chiều dài.
N
ếu một thủ tục SQL được thi hành thành
công, phần tử này có chứa các trạng thái trả về
của thủ tục.
sqlerrd[1]
N
ếu một kết nối được thiết lập thành công,
phần tử này chứa sự khác biệt dự tính về chiều
dài của dữ liệu ký tự hỗn hợp (các kiểu dữ liệu
CHAR) khi nó được chuyển đổi từ trang mã
của cơ sở dữ liệu được sử dụng thành trang mã
của ứng dụng được sử dụng. Một giá trị là 0
hoặc 1 biểu thị rằng dự đoán trước là (chiều
dài) không được mở rộng thêm; một giá trị
dương lớn hơn 1 biểu thị rằng có khả năng mở
rộng thêm chiều dài và một giá trị âm biểu thị
các hàng đã bị ảnh hưởng bởi hoạt động này.
N
ếu cấu trúc dữ liệu SQLCA chứa thông tin
dành cho một câu lệnh SQL OPEN đã thi hành
thành công và con trỏ tương ứng được sử dụng
để thực hiện các hoạt động chèn, cập nhật và
xóa, phần tử này chứa một tổng số đếm các
hàng đã bị ảnh hưởng bởi hoạt động này.
N
ếu cấu trúc dữ liệu SQLCA chứa thông tin
dành cho một câu lệnh SQL CREATE
PROCEDURE đã gặp các lỗi khi phân tích cú
pháp phần thân thủ tục SQL, phần tử này chứa
số thứ tự dòng ở đó đã gặp lỗi phân tích cú
pháp.
N
ếu cấu trúc dữ liệu SQLCA chứa thông tin
dành cho một câu lệnh SQL phức hợp, phần tử
này chứa một tổng số đếm các hàng đã bị ảnh
hư
ởng bởi các câu lệnh con trong khối câu lệnh
SQL phức hợp.
sqlerrd[3]
N
ếu cấu trúc dữ liệu SQLCA chứa thông tin
dành cho một câu lệnh SQL CONNECT SQL
đã thi hành thành công, phần tử này ch
ứa giá trị
0 nếu áp dụng cam kết một pha từ một khách
xử lý; chứa giá trị 4 nếu áp dụng việc xác thực
SERVER_ENCRYPT; chứa giá trị 5 nếu áp
dụng Kết nối DB2 với xác thực mật mã hóa;
giá trị 7 nếu áp dụng xác thực KERBEROS;
chứa giá trị 9 nếu áp dụng xác thực
GSSPLUGIN; chứa giá trị 11 nếu áp dụng xác
thực DATA_ENCRYPT và chứa giá trị 255
nếu cách xử lý xác thực không thể xác định
được.
N
ếu cấu trúc dữ liệu SQLCA chứa thông tin về
bất cứ điều gì khác, phần tử này chứa một tổng
số đếm các hàng đã được chèn vào, được cập
nhật hoặc đã bị xóa như là một kết qu
ả của quy
tắc DELETE của một hay nhiều ràng buộc to
àn
vẹn tham chiếu hoặc sự kích hoạt một hay
nhiều trigger.
N
ếu cấu trúc dữ liệu SQLCA chứa thông tin
dành cho một câu lệnh SQL phức hợp, phần tử
này chứa tổng số đếm tất cả các hàng cho mỗi
câu lệnh con trong khối câu lệnh SQL phức
hợp đã thực thi hành thành công.
sqlerrd[5]
Đối với cơ sở dữ liệu được phân đoạn, phần tử
này chứa số hiệu phân đoạn của phân đoạn đã
gặp lỗi hoặc cảnh báo. Nếu không gặp phải bất