0

次のようなテーブルがあります。

CREATE TABLE book_info (
     book_id                 VARCHAR(32)     not null,
     title                   varchar(255)    not null,
     author                  varchar(255)    not null,
     folder_path         varchar(255)    not null,
     primary key(book_id)
);

そして、私はそれにこのデータを挿入します:

insert into book_info values('BOOK1', 'APUE', 'Richard Stevens', '/home/user1/unix_programming_books');
insert into book_info values('BOOK2', 'Unix Network programming', 'Richard Stevens', '/home/user1/unix_programming_books');
insert into book_info values('BOOK3', 'Core Python Applications Programming', 'Wesley J. Chun', '/home/user1/python_programming_books');

Oracle PRO*C を使用してこのテーブルを更新しようとしていますが、できません。以下は私のコードです:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

EXEC SQL INCLUDE SQLCA;
EXEC SQL INCLUDE ORACA;

#define USER_LEN                        10                          
#define PASS_LEN                        10                          

VARCHAR user[USER_LEN];
VARCHAR pass[PASS_LEN];

#define STRCPY_TO_ORA(dest, source)\
        dest.len = strlen(source);\
        strcpy((char *)dest.arr, (const char *)source)

#define STRCPY_FROM_ORA(dest, source)\
        source.arr[source.len] = 0;\
        strcpy((char *)dest,(const char *)source.arr)

/* Connecting to the database */
int db_connection(char *db_user, char *db_pass)
{
        strncpy((char *) user.arr, db_user, USER_LEN);
        user.len = strlen((char *) user.arr);
        strncpy((char *) pass.arr, db_pass, PASS_LEN);
        pass.len = strlen((char *) pass.arr);

    EXEC SQL CONNECT :user IDENTIFIED BY :pass;
        if (sqlca.sqlcode != 0)
        {
        fprintf(stdout, "Connection failed:%s\n", sqlca.sqlerrm.sqlerrmc);
                return(sqlca.sqlcode);
        }
    fprintf(stdout, "Connected to ORACLE as user:%s\n", user.arr);
        return (sqlca.sqlcode);
}

int book_not_found_function(char *path)
{
    fprintf(stdout, "%s\n", __FUNCTION__);
}

int path_update_success_function(char *book_id, char *new_path)
{
    fprintf(stdout, "Update book %s path to %s\n", book_id, new_path);
}

void other_function(void)
{
    fprintf(stdout, "%s\n", __FUNCTION__);  
}

/* Updating books path */
int books_path_updating(char *old_path, char *new_path) 
{
    char book_id_string[32];
        EXEC SQL BEGIN DECLARE SECTION;
        varchar sql_old_path[255];
        varchar sql_new_path[255];
    varchar sql_book_id[32];
        EXEC SQL END DECLARE SECTION;

        STRCPY_TO_ORA(sql_old_path, old_path);
        STRCPY_TO_ORA(sql_new_path, new_path);

    /* Declare a cursor for the FETCH statement. */
    EXEC SQL DECLARE books_cursor CURSOR FOR
    SELECT BOOK_ID
        FROM BOOK_INFO 
        WHERE FOLDER_PATH = :sql_old_path;

    if (sqlca.sqlcode != 0)
    {
            fprintf(stdout, "Declare cursor failed\n");
        fprintf(stdout, "Oracle error %s\n", sqlca.sqlerrm.sqlerrmc);
            return(sqlca.sqlcode);
    }

    EXEC SQL OPEN books_cursor;

    if (sqlca.sqlcode != 0)
    {
            fprintf(stdout, "Open cursor failed\n");
        fprintf(stdout, "Oracle error %s\n", sqlca.sqlerrm.sqlerrmc);
            return(sqlca.sqlcode);
    }

    for ( ;; )
    {
        //EXEC SQL WHENEVER NOT FOUND DO break; // I used it but still nothing
        //EXEC SQL WHENEVER NOT FOUND GOTO not_found; // I used this too
        //EXEC SQL WHENEVER NOT FOUND DO continue; // I used this too

            /* Fetching data */
            EXEC SQL FETCH books_cursor 
            INTO :sql_book_id;
        if (sqlca.sqlcode == 1403)
        {
            fprintf(stdout, "No book found for this folder %s\n", old_path);    
            book_not_found_function(old_path);

            return 0;
        }

            else if (sqlca.sqlcode != 0)
            {
            fprintf(stdout, "Oracle error %s\n", sqlca.sqlerrm.sqlerrmc);
                    EXEC SQL CLOSE books_cursor;
                    return (sqlca.sqlcode);
            }

        else
        {
            STRCPY_FROM_ORA(book_id_string, sql_book_id);
                fprintf(stdout, "BOOK_ID = %s\n", book_id_string);
            /* Updating the path */
            EXEC SQL UPDATE BOOK_INFO
            SET FOLDER_PATH =:sql_new_path
            WHERE BOOK_ID =:sql_book_id;
            if (sqlca.sqlcode != 0)
                {
                fprintf(stdout, "Oracle error %s\n", sqlca.sqlerrm.sqlerrmc);
                        EXEC SQL CLOSE books_cursor;
                        return (sqlca.sqlcode);
                }
            else
            {
                path_update_success_function(book_id_string, new_path); 
            }
        }
    }
    EXEC SQL CLOSE books_cursor;
    other_function();

    EXEC SQL COMMIT WORK RELEASE;   
    return 0;   
}

int main(int argc, char **argv)
{
    db_connection("evariste", "123456");

    books_path_updating("/home/user1/unix_programming_books", "/home/user1/UNIX_PROGRAMMING_BOOKS");
    books_path_updating("/non_existing_path", "/non_existing_path");

    return 0;
}

このプログラムは次の出力を生成します。

Connected to ORACLE as user:evariste
BOOK_ID = BOOK1
Update book BOOK1 path to /home/user1/UNIX_PROGRAMMING_BOOKS
BOOK_ID = BOOK2
Update book BOOK2 path to /home/user1/UNIX_PROGRAMMING_BOOKS
No book found for this folder /home/user1/unix_programming_books // WHEY THIS?
book_not_found_function // WHY THIS
Declare cursor failed   // WHY THIS 
Oracle error ORA-01403: no data found // WHY THIS

テーブルは更新されず、関数path_update_success_functionおよびother_functionは実行されません! なぜこれ?

ご協力いただきありがとうございます。

4

2 に答える 2

0
Connected to ORACLE as user:evariste
BOOK_ID = BOOK1
Update book BOOK1 path to /home/user1/UNIX_PROGRAMMING_BOOKS
BOOK_ID = BOOK2
Update book BOOK2 path to /home/user1/UNIX_PROGRAMMING_BOOKS
No book found for this folder /home/user1/unix_programming_books // WHEY THIS?

結果セットの最後を超えてフェッチしました。今回は 2 つの行がカーソルに一致するため、最初の 2 つのフェッチは成功します。3 番目はデータを取得しません。これは予期されたものであり、これをエラーとして扱うべきではありません - ループを壊すだけで、これもother_function呼び出されます。

book_not_found_function // WHY THIS

1403 をエラーとして扱うためです。一致するものがないときにこの関数を呼び出したい場合は、ループ内でカウントし、必要に応じて後で呼び出す必要があります。

Declare cursor failed   // WHY THIS 
Oracle error ORA-01403: no data found // WHY THIS

sqlca.sqlcode以前のフェッチからまだ設定されているように見えるので、これは誤解を招きます。

私が覚えている限りでは、通常、関数が呼び出されるたびにではなく、ファイル内でカーソルを 1 回宣言します。Pro*C が再定義を無視するだけかどうかはわかりません。生成されたファイルを見て、それがどのように処理されるかを確認できます。また、これから実行時エラーが発生することもありません。間違っている場合は、(プリ) コンパイルされません。

テーブルは更新されず、関数 path_update_success_function および other_function は実行されません! なぜこれ?

path_update_success最初の 2 つのフェッチに対して呼び出されますが、失敗した 3 番目のフェッチに対しては呼び出されず、2 番目のパスに対しても呼び出されませんdeclare cursorother_functionどちらの呼び出しでも、関数に到達する前に関数から戻るため、呼び出されません。同様に、コミットする前に戻るため、テーブルは更新されていないようです。SQL*Plus とは異なり、Pro*C は終了時に自動的にコミットしないため、暗黙的なロールバックがあります。また、 に到達した場合commit、 はrelease接続を切断するため、2 回目は not-connected-to-Oracle エラーが発生することに注意してください。コミット/ロールバックを実際に 1 回、おそらく最後に行うことを決定する必要がありmainます。


テストされていない変更:

int books_path_updating(char *old_path, char *new_path)
{
    char book_id_string[32];
    int books_found;

    EXEC SQL BEGIN DECLARE SECTION;
        varchar sql_old_path[255];
        varchar sql_new_path[255];
        varchar sql_book_id[32];
    EXEC SQL END DECLARE SECTION;

    STRCPY_TO_ORA(sql_old_path, old_path);
    STRCPY_TO_ORA(sql_new_path, new_path);

    /* Declare a cursor for the FETCH statement */
    EXEC SQL DECLARE books_cursor CURSOR FOR
        SELECT BOOK_ID
        FROM BOOK_INFO
        WHERE FOLDER_PATH = :sql_old_path;

    EXEC SQL OPEN books_cursor;

    if (sqlca.sqlcode != 0)
    {
        fprintf(stdout, "Open cursor failed\n");
    }

    books_found = 0;
    while (sqlca.sqlcode == 0)
    {
        /* Fetching data */
        EXEC SQL FETCH books_cursor
        INTO :sql_book_id;

        if (sqlca.sqlcode != 0)
        {
            break;
        }

        STRCPY_FROM_ORA(book_id_string, sql_book_id);
            fprintf(stdout, "BOOK_ID = %s\n", book_id_string);

        /* Updating the path */
        EXEC SQL UPDATE BOOK_INFO
            SET FOLDER_PATH = :sql_new_path
            WHERE BOOK_ID = :sql_book_id;

        if (sqlca.sqlcode != 0)
        {
            break;
        }

        /* Track how many books we found, though we only really care later that
         * this is non-zero */
        books_found++;

        path_update_success_function(book_id_string, new_path);
    }

    EXEC SQL CLOSE books_cursor;

    /* Check for and display error, but ignore 1403 as this just indicates the
     * end of the result set */
    if ((sqlca.sqlcode != 0) && (sqlca.sqlcode != 1403))
    {
        fprintf(stdout, "Oracle error %s\n", sqlca.sqlerrm.sqlerrmc);
        return 1;
    }

    if (books_found == 0)
    {
        fprintf(stdout, "No book found for this folder %s\n", old_path);
        book_not_found_function(old_path);
        return 0;
    }

    other_function();

    return 0;
}

int main(int argc, char **argv)
{
    int rc;

    rc = db_connection("evariste", "123456");

    /* Only do the first path if we didn't get an error connecting */
    if (rc == 0)
    {
        rc == books_path_updating("/home/user1/unix_programming_books",
            "/home/user1/UNIX_PROGRAMMING_BOOKS");
    }

    /* Only do the next path if we didn't get an error from the previous one */
    if (rc == 0)
    {
        rc = books_path_updating("/non_existing_path",
            "/non_existing_path");
    }

    /* Decide whether to rollback or commit; this assumes you don't want to
     * keep any changes if there are any errors */
    if (rc != 0)
    {
        EXEC SQL ROLLBACK WORK RELEASE;
        return 1;
    }

    EXEC SQL COMMIT WORK RELEASE;
    return 0;
}
于 2012-06-16T11:53:49.533 に答える