Xử lý lỗi khi nhúng SQL vào C/C++ trên các hệ thống IBM z/OS

Hướng dẫn này để phát hiện ra các lỗi SQL trong các ứng dụng C/C++ với SQL nhúng trên nền tảng z/OS bao gồm mã ví dụ mẫu để thực hiện việc kiểm tra lỗi đơn giản và một kỹ thuật tiên tiến hơn trong việc phân tích lỗi chuyên sâu. Tất cả tư liệu đều dựa trên và được thử nghiệm với Các phiên bản 8 đến 10 của IBM z/OS DB2 và V1R11 đến V1R13 của các trình biên dịch z/OS XL C/C++.

Francesco Cassullo, Nhà phát triển phần mềm, IBM

Ảnh của Francesco CassulloFrancesco Cassullo là một nhà phát triển phần mềm trong nhóm Các trình biên dịch XL của IBM. Anh làm việc tại IBM từ năm 2008 và đã làm về các trình biên dịch Fortran, C/C++ và COBOL.



Igor Todorovski, Nhà phát triển phần mềm, IBM

Ảnh của Igor TodorovskiIgor Todorovski là một nhà phát triển phần mềm trong nhóm Các trình biên dịch XL của IBM. Anh làm việc tại IBM từ năm 2008 và chuyên về các trình biên dịch C/C++ z/OS.



16 04 2013

Giới thiệu về xử lý lỗi SQL

Lĩnh vực truyền thông SQL (SQLCA - SQL communication area) rất cần thiết để xác định trạng thái của bất kỳ câu lệnh SQL nào. SQLCA là một cấu trúc kiểu-C (struct) để lưu trữ dữ liệu về trạng thái thực hiện của một câu lệnh SQL. Cơ sở dữ liệu IBM® DB2® điền vào SQLCA các dữ liệu dựa trên câu lệnh SQL vừa được thực hiện gần nhất. Để khai báo SQLCA vào ứng dụng của bạn, bạn phải đưa vào câu lệnh sau:

 EXEC SQL INCLUDE SQLCA;

Từ các thành phần của cấu trúc SQLCA, bạn có thể trích ra các chi tiết của câu lệnh SQL được thực hiện gần nhất. SQLCODE và SQLSTATE là một số trong số những thành phần quan trọng hơn. SQLCODE lưu trữ mã trả về của câu lệnh SQL. Giá trị này là mã lỗi của một câu lệnh SQL được DB2 báo cáo. Các mã lỗi theo mẫu được thể hiện trong Bảng 1.

Bảng 1. Mô tả SQLCODE
Các mã lỗiHành vi
SQLCODE < 0 Việc thực hiện câu lệnh thất bại
SQLCODE = 0 Việc thực hiện câu lệnh đã thành công
SQLCODE > 0 Việc thực hiện câu lệnh đã thành công với một cảnh báo

DB2 đặt từng lỗi SQL vào các nhóm riêng biệt. SQLSTATE lưu trữ lỗi thuộc về nhóm nào. Cũng giống như với SQLCODE, một giá trị 0 có nghĩa là câu lệnh SQL được thực hiện thành công.

SQLCA chỉ lưu trữ dữ liệu của câu lệnh SQL vừa được thực hiện gần nhất và nó được cập nhật với mỗi câu lệnh SQL tiếp theo. Vì vậy, để xác nhận hợp lệ trạng thái của các câu lệnh SQL của bạn, bạn cần kiểm tra trạng thái của SQLCODE và SQLSTATE sau mỗi cuộc gọi. Liệt kê 1 cho thấy ví dụ về cách thực hiện việc kiểm tra này.

Liệt kê 1. Cách dùng cơ bản của SQLCODE và SQLSTATE
EXEC SQL INSERT INTO PRODUCT VALUES (11, 'RED', '0098');
if (sqlca.sqlcode != 0)
{
    printf("SQL ERROR CODE = %d\n", sqlca.sqlcode);
    printf("SQL ERROR CLASS = %s\n", sqlca.sqlstate);
}

Ví dụ, nếu chạy câu lệnh INSERT này và bảng PRODUCT (Sản phẩm) không tồn tại, bạn sẽ thấy kết quả đầu ra sau:

SQL ERROR CODE = -204
SQL ERROR CLASS = 42704

"DB2 codes information center - Trung tâm thông tin các mã DB2" được trích dẫn trong phần Tài nguyên cho z/OS nói rằng lỗi SQL - 204 cho biết PRODUCT không tồn tại trong cơ sở dữ liệu. Mô tả này cũng được dùng cho lỗi SQLSTATE 42704. Khi sử dụng hai chữ số đầu tiên của SQLSTATE, bạn có thể trích ra lớp lỗi. Trong trường hợp này, lớp lỗi là 42 và là một Lỗi cú pháp (Syntax Error) hoặc lỗi Vi phạm quy tắc truy cập (Access Rule Violation). Ở đây là lỗi Vi phạm quy tắc truy cập vì PRODUCT không tồn tại.

Xem hướng dẫn "Lập trình ứng dụng DB2 và SQL" được trích dẫn trong phần Tài nguyên để biết các chi tiết về các thành phần khác của SQLCA.

Liệt kê 2. Mã ví dụ mẫu để xử lý lỗi cơ bản
#include <stdio.h>
EXEC SQL INCLUDE SQLCA;

int main(void)
{
      int status = 55;
      
      /* Create Table */
      EXEC SQL CREATE TABLE TABLE_1
      (
            COLOUR   CHAR(6) NOT NULL,
            ID       INTEGER NOT NULL
      ) IN DATABASE DSNUCOMP;
      
      /* Check for SQL error on Create Table */
      if (sqlca.sqlcode != 0) 
      {
            printf(">> SQLCODE = %d SQLSTATE = %s: in file %s on line #%d -- %s <<\n", \
                  sqlca.sqlcode, sqlca.sqlstate, __FILE__, __LINE__, "Failed to CREATE");
            status = -1;
      }
      
      /* Insert row into table. 
      Note this SQL command is purposely wrong to trigger an SQL error at run-time. */
      EXEC SQL INSERT INTO TABLE_1 VALUES ('RED');
      /* Check for SQL error on Insert */
      if (sqlca.sqlcode != 0) 
      {
            printf(">> SQLCODE = %d SQLSTATE = %s: in file %s on line #%d -- %s <<\n", \
                  sqlca.sqlcode, sqlca.sqlstate, __FILE__, __LINE__, "Failed to INSERT");
            status = -1;
      }
      
      /* Drop Table */
      EXEC SQL DROP TABLE TABLE_1;
      /* Check for SQL error on Drop Table */
      if (sqlca.sqlcode != 0) 
      {
            printf(">> SQLCODE = %d SQLSTATE = %s: in file %s on line #%d -- %s <<\n", \
                  sqlca.sqlcode, sqlca.sqlstate, __FILE__, __LINE__, "Failed to DROP");
            status = -1;
      }
      
      return status;
}

Cách xử lý lỗi tốt hơn

Phương pháp ở trên dễ sử dụng nhưng chỉ dành cho các lập trình viên đã biết mã lỗi. Điều này không tiện lắm, trừ khi bạn tra tìm nó trong DB2 codes information center - trung tâm thông tin các mã DB2 (xem phần Tài nguyên). Một trình xử lý lỗi đầy đủ hơn cần cung cấp cho các lập trình viên nhiều thông tin phản hồi về lỗi hơn, như thông báo lỗi chẳng hạn.

Thường trình DB2 DSNTIAR là một mô-đun có sử dụng cấu trúc SQLCA để đưa ra một chẩn đoán SQL đầy đủ về một câu lệnh SQL bị lỗi. Nó cung cấp SQLCODE, SQLSTATE, thông báo lỗi và v.v. Để biết thêm thông tin về DSNTIAR, xem chủ đề "statements in C programs - Các câu lệnh SQL trong chương trình C" trong các hướng dẫn lập trình ứng dụng của DB2. Đây là dạng câu lệnh cơ bản để gọi hàm DSNTIAR:

 rc = DSNTIAR(&sqlca, &error_message, &line_length);
Bảng 2. Mô tả các đối số của hàm DSNTIAR
Biến Mô tả
sqlca Cấu trúc SQLCA
error_message Một cấu trúc đặc biệt để lưu trữ thông báo chẩn đoán SQL đầy đủ
line_length Độ dài của dòng trong error_message (thông báo_lỗi)

error_message là một cấu trúc đặc biệt có chứa hai thành phần: length (chiều dài) và msg (thông báo): Người dùng định nghĩa error_message theo một cách thích ứng với cấu trúc này để tuân thủ:

msg
Một mảng ký tự hai chiều để lưu kết quả đầu ra thông báo từ DB2
 
length
Kích thước của mảng msg để báo cho DB2 viết các ký tự có chiều dài tối đa vào msg

data_lendata_dim kiểm soát các chiều của msg. data_len là chiều dài của mỗi dòng và data_dim là số dòng để lưu trữ. Mã ví dụ mẫu trong Liệt kê 3 sử dụng data_len là 200 và data_dim là 10. Có thể thay đổi chúng theo sở thích của người dùng, nhưng hãy nhớ data_len phải nằm giữa 72 và 240 ký tự. Vì vậy, chiều dài của msg là data_len * data_dim.

Liệt kê 3. Xác định khả năng lưu trữ cho các thông báo lỗi
#define data_len 200
#define data_dim 10

struct SQL_error_block
{
    short int length;
    char text[data_len][data_dim];
} error_message = {data_len * data_dim};

Để có mối liên kết tìm ra mô-đun DSNTIAR, bạn cần bao gồm mã trong Liệt kê 4.

Liệt kê 4. Đưa mô-đun DSNTIAR vào ứng dụng của bạn
#ifdef __cplusplus
    extern "OS"
#endif
short int DSNTIAR(struct sqlca *sqlca, struct SQL_error_block *error_message, \
int *msg_len);
#ifndef __cplusplus
    #pragma linkage (DSNTIAR,OS)
#endif

error_message cần phải được điều chỉnh chút ít để có một định dạng thân thiện với người dùng. Đầu trang ví dụ mẫu trong Liệt kê 5 định nghĩa một hàm dễ sử dụng để kiểm tra trạng thái của một câu lệnh SQL và cung cấp một thông báo chẩn đoán đúng định dạng nếu nó có lỗi.

Liệt kê 5. Đầu trang ví dụ mẫu để soạn các thông báo lỗi SQL chi tiết
#include <stdio.h>
#include <string.h>
#include <ctype.h>

EXEC SQL INCLUDE SQLCA;
void trim_sql_error_message(char *sql_full_msg);

#define data_len 200
#define data_dim 10
int sql_rc = 55;

struct SQL_error_block
{
    short int length;
    char text[data_len][data_dim];
} error_message = {data_len * data_dim};

#ifdef __cplusplus
    extern "OS"
#endif
short int DSNTIAR(struct sqlca *sqlca, struct SQL_error_block *error_message, \
int *msg_len);
#ifndef __cplusplus
    #pragma linkage (DSNTIAR,OS)
#endif

/*
    Checks the return code of the SQL command and fetches the SQL message if erroneous
    ARG1 is the SQLCA struct
    ARG2 is used to store the formatted SQL message

  Returns 0 if there is no error
  Returns -1 if there is an SQL error that is properly handled
  Returns -2 if DSNTIAR function fails
*/
int error_handler(struct sqlca *sqlca, char *sql_full_msg)
{
    short rc = 0;
    int lrecl = data_len;

    if (sqlca->sqlcode != 0)
    {
        rc = DSNTIAR(sqlca, &error_message, &lrecl);
        if (rc != 0)
        {
            printf("DSNTIAR ERROR: call failed with RC = %d\n", rc);
            return -2;
        }

        error_message.text[data_len - 1][data_dim - 1] = '\0';
        trim_sql_error_message(sql_full_msg);
        return -1;
    }
    else
        return 0;
}

#define CHECK_ERROR(sqlca, error_msg) \
    if (error_handler(sqlca, error_msg) != 0) { \
        printf("ERROR: in file %s on line %d\n", __FILE__, __LINE__); \
        printf("%s\n", error_msg); \
        sql_rc = -1; \
    }
	
/*
    Format the SQL message block into a readable string
    ARG1 is used to store the formatted message
*/
void trim_sql_error_message(char *sql_full_msg)
{
    int i = 0, j = 0, pos = 0, space_count = 0;

    for (i = 0; i < data_len; i++)
    {
        for (j = 0; j < data_dim; j++)
        {	
            if ( isspace(error_message.text[i][j]) )
                space_count++;
            else
                space_count = 0;
			
            if (space_count <= 2)
            {
                sql_full_msg[pos] = error_message.text[i][j];
                pos++;
            }
        }
    }
}

Chương trình ví dụ mẫu trong Liệt kê 6 trình bày cách kiểm tra các lỗi SQL và gọi hàm của trình xử lý lỗi.

Liệt kê 6. Mã ví dụ mẫu để gọi hàm của trình xử lý lỗi SQL chi tiết
#include <stdio.h>
#include "dsntiar.h"
#define BUF_SIZE 2000

int main()
{
    char sql_error_log[BUF_SIZE];
	
    /* Create Table */
    EXEC SQL CREATE TABLE COLOUR_TABLE
     (
        COLOUR   CHAR(6) NOT NULL,
        ID       INTEGER NOT NULL
    ) IN DATABASE DSNUCOMP;
    /* Check for and output any SQL errors from attempting to create the table */
    CHECK_ERROR(&sqlca, sql_error_log);
	
    /* Insert row into table.  
        Note this SQL command is purposely wrong to trigger an SQL error at runtime. */
        EXEC SQL INSERT INTO COLOUR_TABLE VALUES ('RED');
    /* Check for SQL error on Insert */
    CHECK_ERROR(&sqlca, sql_error_log);
	
    /* Drop Table */
    EXEC SQL DROP TABLE COLOUR_TABLE;
    /* Check for and output any SQL errors from attempting to drop the table */
    CHECK_ERROR(&sqlca, sql_error_log);

    return sql_rc;
}

Lời cảm ơn

Chúng tôi xin cảm ơn những người sau đây đã giúp thực hiện bài viết này: Zibi Sarbinowski, Rajan Bhakta và Kobi Vinayagamoorthy.


Các tải về

Mô tảTênKích thước
DSNTIARdsntiar.zip7KB
SQL codesqlcode.zip5KB

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

  • Tải về một phiên bản dùng thử miễn phí của phần mềm Rational.
  • Đánh giá sản phẩm của IBM theo cách phù hợp với bạn nhất: Tải về một bản dùng thử sản phẩm, dùng thử một sản phẩm trực tuyến, sử dụng một sản phẩm trong một môi trường điện toán đám mây hoặc dành một vài giờ trong SOA Sandbox để học cách thực hiện kiến trúc hướng dịch vụ một cách hiệu quả.

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Khi bạn đăng ký với trang developerWorks lần đầu tiên, một tiểu sử của của bạn được tạo ra. Chọn các thông tin về tiểu sử của bạn (tên, nước/vùng, và nơi làm việc) đã được hiện lên màn hình, thông tin này sẽ được hiện kèm với nội dung mà bạn đăng tải. Bạn có thể cập nhật thông tin này bất kỳ lúc nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Rational
ArticleID=870552
ArticleTitle=Xử lý lỗi khi nhúng SQL vào C/C++ trên các hệ thống IBM z/OS
publish-date=04162013