預設情況下,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_name
can'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);