Chuyển đến nôi dung chính

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 (tiếng Anh).

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.

  • Đóng [x]

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.

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 (tiếng Anh).

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

  • Đóng [x]

Chuẩn bị cho Kỳ thi 733 về Phát triển ứng dụng DB2 9, Phần 5: Lập trình CLI/ODBC

Roger Sanders, Quản lý cao cấp, EMC
Roger E.Sanders là nhà quản lý cao cấp của phòng Ứng dụng mạng thuộc Liên khoa học công nghệ IBM, Inc. Ông đã và đang làm thiết kế và phát triển cơ sở dữ liệu cũng như về các ứng dụng cơ sở dữ liệu trong hơn 20 năm qua, và hiện nay vẫn đang làm việc với DB2 Universal Database (Cơ sở dữ liệu vạn năng DB2) kể từ phiên bản đầu tiên OS/2 1.3 Extendend Edition. Ông đã viết các bài báo cho IDUG Solutions Journal, Certification Magazine, và developerWorks, đồng thời ông cũng tham gia giảng dạy tại các hội nghị IDUG và RUG, ông cũng tham gia vào phát triển các bài kiểm tra chứng chỉ DB2 và ông là tác giả của 9 quyển sách về DB2 UDB
(Tác giả đóng góp cho IBM developerWorks)

Tóm tắt:  Hướng dẫn này giới thiệu cho bạn về lập trình DB2 CLI (Call-Level Interface - giao diện mức gọi)/lập trình ODBC và dẫn bạn qua các bước cơ bản được sử dụng để xây dựng một ứng dụng CLI/ODBC. Hướng dẫn này cũng giới thiệu cho bạn quá trình sử dụng để 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 các lời gọi hàm CLI/ODBC thành một ứng dụng sẵn sàng để chạy. Đây là hướng dẫn thứ năm trong một loạt bài 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 UDB V9.1 (kỳ thi 733).

Xem thêm bài trong loạt bài này

Ngày:  06 11 2009
Mức độ:  Trung bình

Hoạt động:  5307 lần đọc

Các chẩn đoán và xử lý lỗi

Các mã trả về

Mỗi khi một hàm CLI/ODBC được gọi, một giá trị đặc biệt được gọi là một mã trả về được trả về cho ứng dụng gọi hàm đó để biểu thị hàm đã thi hành như mong đợi hay không. Nếu, vì một vài lý do, hàm này đã không thi hành thành công, giá trị của mã trả về đã sinh ra sẽ biểu thị nguyên nhân làm cho hàm không thực hiện thành công. Một danh sách các mã có khả năng có thể được trả về bởi một hàm CLI/ODBC có thể xem trong Bảng 2:


Bảng 2. Các mã trả về của hàm CLI/ODBC
Mã trả về Ý nghĩa
SQL_SUCCESS Hàm CLI/ODBC thực hiện thành công.
SQL_SUCCESS_WITH_INFO Hàm CLI/ODBC thực hiện thành công, tuy nhiên, đã gặp phải một điều kiện cảnh báo hay điều kiện lỗi không trầm trọng.
SQL_NO_DATA or SQL_NO_DATA_FOUND Hàm CLI/ODBC thực hiện thành công, nhưng không tìm thấy có dữ liệu có liên quan.
SQL_INVALID_HANDLE Hàm CLI/ODBC không được thực hiện thành công, vì đã cho một thẻ điều khiển môi trường, kết nối, câu lệnh, hoặc bộ mô tả không hợp lệ. Mã trả về này chỉ được trả về khi thẻ điều khiển đã cho hoặc chưa được cấp phát hoặc kiểu thẻ điều khiển sai (ví dụ, nếu cung cấp một thẻ điều khiển kết nối khi mong đợi là một thẻ điều khiển môi trường). Bởi kiểu lỗi này là một lỗi lập trình, không có thông tin bổ sung nào được cung cấp.
SQL_NEED_DATA Hàm CLI/ODBC không thực hiện thành công bởi vì dữ liệu mà hàm này mong đợi có sẵn vào thời gian thi hành (ví dụ như dữ liệu các dấu tham số hoặc thông tin kết nối) đã bị thiếu. Mã trả về này thường được tạo ra khi các tham số hoặc cột được kết buộc như là các tham số/các cột dữ liệu-lúc-thi hành (SQL_DATA_AT_EXEC).
SQL_STILL_EXECUTING Một hàm CLI/ODBC đã được bắt đầu không đồng bộ vẫn còn đang thực hiện.
SQL_ERROR Hàm CLI/ODBC không thực hiện thành công.

Việc xử lý lỗi là một phần quan trọng của bất kỳ ứng dụng nào và các ứng dụng CLI/ODBC không là ngoại lệ. Ít nhất, một ứng dụng CLI/ODBC sẽ luôn luôn kiểm tra để xem xem một hàm CLI/ODBC có thực hiện thành công không bằng cách kiểm tra lại mã trả về đã sinh ra. Bất cứ khi nào một hàm không thực hiện thành công như mong đợi, những người dùng sẽ được thông báo rằng một điều kiện lỗi hay cảnh báo đã xuất hiện và mỗi khi có thể, họ sẽ được cung cấp các thông tin chẩn đoán để giúp họ nhanh chóng xác định vị trí và sửa chữa lại tình hình.


Các SQLSTATE

Mặc dù một mã trả về thông báo cho một chương trình ứng dụng rằng đã bắt gặp một điều kiện lỗi hay cảnh báo, nhưng nó không cung cấp cho ứng dụng (hoặc nhà phát triển, hoặc người dùng) thông tin cụ thể về nguyên nhân gây ra điều kiện lỗi hay cảnh báo đã xuất hiện. Bởi vì các thông tin bổ sung thêm về một điều kiện lỗi hay cảnh báo thường là cần thiết để giải quyết vấn đề, DB2 (giống như các sản phẩm cơ sở dữ liệu quan hệ khác) sử dụng một bộ các mã thông báo lỗi được gọi là các SQLSTATE để cung cấp các thông tin chẩn đoán bổ sung cho các cảnh báo và các lỗi. Các SQLSTATE là các chuỗi vừa có chữ vừa có số có năm ký tự (các byte) theo chiều dài và có định dạng ccsss, ở đây cc chỉ thị lớp thông báo lỗi và sss chỉ thị lớp con thông báo lỗi. Bất kỳ SQLSTATE nào có một lớp là 01 tương ứng với một cảnh báo; Bất kỳ SQLSTATE nào có một lớp là HY tương ứng với một lỗi do DB2 CLI tạo ra và bất kỳ SQLSTATE nào có một lớp IM tương ứng với một lỗi do Trình quản lý của trình điều khiển ODBC tạo ra. (Bởi vì các máy chủ cơ sở dữ liệu khác nhau thường có các mã thông báo chẩn đoán khác nhau, các SQLSTATE tuân theo các tiêu chuẩn được nêu trong đặc tả kỹ thuật tiêu chuẩn X/Open CLI. Việc tiêu chuẩn hóa các giá trị SQLSTATE này cho phép các nhà phát triển ứng dụng xử lý các lỗi và các cảnh báo một cách nhất quán trên các sản phẩm cơ sở dữ liệu quan hệ khác nhau).

Không giống như mã trả về, các SQLSTATE thường được xử lý như các hướng dẫn và các trình điều khiển không bắt buộc phải trả về chúng. Vì vậy, trong khi các trình điều khiển nên luôn luôn trả về SQLSTATE đúng đối với bất kỳ lỗi hay cảnh báo nào mà chúng có khả năng phát hiện, các ứng dụng không nên trông mong rằng điều đó luôn luôn xảy ra. Do các SQLSTATE không chắc chắn sẽ được trả về, nên hầu hết các ứng dụng chỉ hiển thị chúng cho người sử dụng cùng với bất kỳ thông báo chẩn đoán tương ứng nào và mã lỗi nguyên sinh sẵn có.


Thu nhận thông tin chẩn đoán

Vậy thì làm thế nào để nhận được các giá trị SQLSTATE, các thông báo chẩn đoán và các mã lỗi nguyên sinh khi một hàm CLI/ODBC không thi hành đúng? Thông tin này được thu thập bằng cách gọi hàm SQLGetDiagRec(), hàm SQLGetDiagField() hoặc cả hai. Các hàm này nhận đầu vào là một thẻ điều khiển môi trường, thẻ điều khiển kết nối, thẻ điều khiển câu lệnh, hoặc thẻ điều khiển bộ mô tả và trả về các thông tin chẩn đoán về hàm CLI/ODBC cuối cùng vừa được thi hành, sử dụng thẻ điều khiển đã chỉ rõ. Nếu nhiều bản ghi chẩn đoán đã được sinh ra, một ứng dụng phải gọi một hoặc cả hai hàm này lặp lại nhiều lần cho đến khi tất cả các thông tin chẩn đoán có sẵn được thu nhận. (Tổng số các bản ghi chẩn đoán có sẵn có thể được xác định bằng cách gọi hàm SQLGetDiagField() với số hiệu bản ghi là 0 -- đó là số hiệu của bản ghi tiêu đề -- và chỉ rõ tùy chọn SQL_DIAG_NUMBER).

Các thông tin chẩn đoán được lưu trong bộ nhớ như là các bản ghi chẩn đoán. Các ứng dụng có thể lấy ra các giá trị SQLSTATE, các thông báo chẩn đoán và các mã lỗi nguyên sinh từ một bản ghi chẩn đoán trong chỉ một bước bằng cách gọi hàm SQLGetDiagRec(). Tuy nhiên, hàm này không thể được sử dụng để lấy ra thông tin từ bản ghi tiêu đề chẩn đoán. Thay vào đó, các ứng dụng phải sử dụng hàm SQLGetDiagField() để lấy ra các thông tin được lưu trữ trong bản ghi tiêu đề chẩn đoán. Hàm SQLGetDiagField() cũng có thể được sử dụng để thu nhận được các giá trị của các trường trong từng bản ghi chẩn đoán riêng lẻ. (Ví dụ, hàm SQLGetDiagField() có thể được sử dụng để thu nhận thông tin về số hàng bị ảnh hưởng bởi một hoạt động chọn, chèn, cập nhật hoặc xóa).


Ví dụ về xử lý chẩn đoán/lỗi

Bạn đã thấy các mã trả về có thể được sử dụng như thế nào để phát hiện khi một điều kiện lỗi hay cảnh báo xuất hiện và các bản ghi chẩn đoán có thể được sử dụng như thế nào để cung cấp các thông tin phản hồi. Bây giờ bạn sẽ thấy việc lấy ra các thông tin chẩn đoán và xử lý lỗi thường được thực hiện trong một ứng dụng CLI/ODBC như thế nào. Ứng dụng CLI/ODBC dưới đây, được viết bằng ngôn ngữ lập trình C, minh họa cách các hàm SQLGetDiagRec()SQLGetDiagField() có thể được sử dụng để hiển thị các thông tin chẩn đoán như thế nào, cả cho trường hợp khi một lỗi xảy ra lẫn khi cần nhiều thông tin hơn về việc xử lý kết hợp với một câu lệnh SQL SELECT.


Liệt kê 4. Sử dụng các hàm SQLGetDiagField() và SQLGetDiagRec()
                     
#include <stdio.h>
#include <string.h>
#include <sqlcli1.h>

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC Application Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	

5 của 9 | Trang trước | Trang sau

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Information Management
ArticleID=444790
TutorialTitle=Chuẩn bị cho Kỳ thi 733 về Phát triển ứng dụng DB2 9, Phần 5: Lập trình CLI/ODBC
publish-date=11062009
author1-email=
author1-email-cc=