2012-06-09 27 views
0

我有這樣的一個表:甲骨文PRO *用光標C更新表故障

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!爲什麼這個?

感謝您的幫助。

回答

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? 

您已經獲取過去的結果集的結尾。這次兩行匹配遊標,所以前兩次抓取成功;第三個沒有獲取數據。這是預期的,你不應該把它當作一個錯誤 - 只是打破循環,這也會導致調用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似乎仍然可以從先前設置取,所以這是一種誤導。

據我記得,你通常會在文件中聲明一次光標,而不是每次調用該函數;不確定Pro * C是否忽略了重新定義。您可以查看生成的文件以瞭解它如何處理它。你也不會從這裏得到一個運行時錯誤,如果它錯了,它不會(預)編譯。

該表未更新,並且函數 path_update_success_function和other_function永遠不會執行! 這是爲什麼?

path_update_success被稱爲前兩個讀取,但不適合其中發生故障,而不是用於所述第二路徑,因爲該函數返回第三由於表觀declare cursor它得到接近它之前。不會調用other_function,因爲對於您從該函數返回的兩個調用,都可以達到它。同樣,該表似乎不會更新,因爲您在提交之前返回。與SQL * Plus不同,Pro * C在退出時不會自動提交,因此存在隱式回滾。另請注意,如果您確實遇到commitrelease會斷開與您的連接,所以您第二次得到未連接到Oracle的錯誤。你應該決定提交/回滾一次,可能是在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; 
} 
+0

感謝您的答案,但我看不出如何解決這個問題。 – iPadDevloperJr

+0

@iPadDevloperJr - 我已經添加了修改過的代碼,但我有點生疏,所以可能不太對;但希望能給你這個想法。 –

+0

感謝您的好主意,好像這個工作:) – iPadDevloperJr

0

似乎DECLARE CURSOR不設置的sqlca.sqlcode。 當您完成抓取時,您得到的錯誤是前一錯誤。

所以你不應該在DECLARE CURSOR之後,而是在OPEN CURSOR之後測試錯誤。