預設情況下,mysql_real_query() 和 mysql_query() 將其語句字串參數解譯為要執行的單一語句,並且您會根據語句是否產生結果集(一組列,如 SELECT)或受影響的列計數(如 INSERT、UPDATE 等等)來處理結果。
MySQL 也支援執行包含多個以分號 (;) 字元分隔的語句的字串。此功能透過在您使用 mysql_real_connect() 連接到伺服器時,或在連線後呼叫 mysql_set_server_option() 時指定的特殊選項來啟用。
執行多語句字串可能會產生多個結果集或列計數指示器。處理這些結果的方法與單一語句的情況不同:在處理第一個語句的結果後,必須檢查是否有更多結果存在,如果有,則依序處理它們。為了支援多結果處理,C API 包含 mysql_more_results() 和 mysql_next_result() 函數。這些函數在迴圈的結尾使用,只要有更多結果可用,迴圈就會持續迭代。 未能以這種方式處理結果可能會導致與伺服器的連線中斷。
如果您執行 CALL 儲存程序語句,也需要進行多結果處理。儲存程序的結果具有以下特徵
-
程序中的語句可能會產生結果集(例如,如果它執行
SELECT語句)。這些結果集會按照它們在程序執行時產生的順序返回。一般而言,呼叫者無法知道程序會返回多少個結果集。程序執行可能取決於迴圈或條件語句,這些語句會導致執行路徑在每次呼叫時有所不同。因此,您必須準備好檢索多個結果。
程序的最終結果是一個狀態結果,其中不包含結果集。該狀態指示程序是否成功或發生錯誤。
多語句和結果功能只能與 mysql_real_query() 或 mysql_query() 一起使用。它們不能與預先準備語句介面一起使用。預先準備語句處理程式定義為僅適用於包含單一語句的字串。請參閱 第 6 章,C API 預先準備語句介面。
要啟用多語句執行和結果處理,可以使用以下選項
-
mysql_real_connect()函數有一個flags引數,其中兩個選項值是相關的CLIENT_MULTI_RESULTS使用戶端程式能夠處理多個結果。如果您執行產生結果集的儲存程序的CALL語句,必須 啟用此選項。否則,此類程序會導致錯誤Error 1312 (0A000): PROCEDURE。proc_namecan't return a result set in the given contextCLIENT_MULTI_RESULTS預設為啟用。CLIENT_MULTI_STATEMENTS使mysql_real_query()和mysql_query()能夠執行包含多個以分號分隔的語句的語句字串。此選項也會隱式啟用CLIENT_MULTI_RESULTS,因此傳遞CLIENT_MULTI_STATEMENTS的flags引數給mysql_real_connect(),等同於傳遞CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS的引數。也就是說,CLIENT_MULTI_STATEMENTS足以啟用多語句執行和所有多結果處理。
連線到伺服器後,您可以使用
mysql_set_server_option()函數,並傳遞MYSQL_OPTION_MULTI_STATEMENTS_ON或MYSQL_OPTION_MULTI_STATEMENTS_OFF的引數來啟用或停用多語句執行。使用此函數啟用多語句執行也會啟用多語句字串的 「簡單」 結果處理,其中每個語句產生單一結果,但不足以允許處理產生結果集的儲存程序。
以下程序概述了處理多語句的建議策略
將
CLIENT_MULTI_STATEMENTS傳遞給mysql_real_connect(),以完全啟用多語句執行和多結果處理。在呼叫
mysql_real_query()或mysql_query()並驗證其成功後,進入一個迴圈,您可以在其中處理語句結果。在迴圈的每次迭代中,處理目前的語句結果,檢索結果集或受影響的列計數。如果發生錯誤,則退出迴圈。
在迴圈的結尾,呼叫
mysql_next_result()以檢查是否存在其他結果,如果存在,則啟動對其的檢索。如果沒有更多結果可用,則退出迴圈。
以下顯示了上述策略的一種可能的實作方式。迴圈的最後一部分可以簡化為對 mysql_next_result() 是否返回非零值的簡單測試。編寫的程式碼區分了沒有更多結果和錯誤,這使得可以為後者發印訊息。
/* connect to server with the CLIENT_MULTI_STATEMENTS option */
if (mysql_real_connect (mysql, host_name, user_name, password,
db_name, port_num, socket_name, CLIENT_MULTI_STATEMENTS) == NULL)
{
printf("mysql_real_connect() failed\n");
mysql_close(mysql);
exit(1);
}
/* execute multiple statements */
status = mysql_query(mysql,
"DROP TABLE IF EXISTS test_table;\
CREATE TABLE test_table(id INT);\
INSERT INTO test_table VALUES(10);\
UPDATE test_table SET id=20 WHERE id=10;\
SELECT * FROM test_table;\
DROP TABLE test_table");
if (status)
{
printf("Could not execute statement(s)");
mysql_close(mysql);
exit(0);
}
/* process each statement result */
do {
/* did current statement return data? */
result = mysql_store_result(mysql);
if (result)
{
/* yes; process rows and free the result set */
process_result_set(mysql, result);
mysql_free_result(result);
}
else /* no result set or error */
{
if (mysql_field_count(mysql) == 0)
{
printf("%lld rows affected\n",
mysql_affected_rows(mysql));
}
else /* some error occurred */
{
printf("Could not retrieve result set\n");
break;
}
}
/* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
if ((status = mysql_next_result(mysql)) > 0)
printf("Could not execute statement\n");
} while (status == 0);
mysql_close(mysql);