diff --git a/scripts/api_coverage_manifest.py b/scripts/api_coverage_manifest.py index 46044a3..292df71 100755 --- a/scripts/api_coverage_manifest.py +++ b/scripts/api_coverage_manifest.py @@ -47,6 +47,7 @@ PUBLIC_APIS = [ ("cli_arg", True, "public"), ("unit_compile", True, "public"), ("cleanup_sqlite_connections", False, "internal"), ("cleanup_mysql_connections", False, "internal"), ("mysql_connect", True, "integration"), ("mysql_query", True, "integration"), + ("mysql_affected_rows", True, "integration"), ] REMOVED_APIS = ["unit_load", "concat"] diff --git a/site/doc/areas/mysql.txt b/site/doc/areas/mysql.txt index d24ec91..8d90ca2 100644 --- a/site/doc/areas/mysql.txt +++ b/site/doc/areas/mysql.txt @@ -5,4 +5,5 @@ mysql_disconnect mysql_error mysql_escape mysql_insert_id +mysql_affected_rows mysql_query diff --git a/site/doc/pages/mysql_affected_rows.txt b/site/doc/pages/mysql_affected_rows.txt new file mode 100644 index 0000000..e0429c7 --- /dev/null +++ b/site/doc/pages/mysql_affected_rows.txt @@ -0,0 +1,24 @@ +:sig +u32 mysql_affected_rows(MySQL* m) + +:params +m : pointer to an active MySQL connection +return value : number of rows changed by the most recent statement + +:see +>mysql +mysql_query +mysql_insert_id + +:content +Returns the number of rows changed by the most recent insert, update, or delete on the connection. A successful statement that returns rows, a rejected query, or a null connection returns `0` rather than retaining an earlier statement's count. + +:example +MySQL* db = mysql_connect(); +if(db != 0) +{ + mysql_query(db, "update users set active=1 where active=0"); + print("rows updated: ", mysql_affected_rows(db), "\n"); + mysql_disconnect(db); +} +else print("(requires a reachable MySQL server)\n"); diff --git a/site/doc/pages/mysql_query.txt b/site/doc/pages/mysql_query.txt index 0e46a57..27d86ae 100644 --- a/site/doc/pages/mysql_query.txt +++ b/site/doc/pages/mysql_query.txt @@ -9,6 +9,7 @@ return value : a list of rows returned from executing the query :see >mysql +mysql_affected_rows :content Executes a MySQL query and returns the resulting data, if any. @@ -17,6 +18,8 @@ Executes a MySQL query and returns the resulting data, if any. The result is returned as a `DValue`, which makes it easy to iterate through rows and read fields with the usual `DValue` accessors. +After an insert, update, or delete, use `mysql_affected_rows()` to inspect how many rows changed. + :example MySQL* db = mysql_connect(); if(db != 0) diff --git a/site/tests/services.uce b/site/tests/services.uce index 5e0ff3b..a3332db 100644 --- a/site/tests/services.uce +++ b/site/tests/services.uce @@ -131,8 +131,21 @@ RENDER(Request& context) (dbs.find("information_schema") != String::npos || dbs.find("mysql") != String::npos) ? "pass" : "fail", dbs.substr(0, dbs.length() > 220 ? 220 : dbs.length()) ); + mysql.query("USE mysql"); + mysql.query("CREATE TEMPORARY TABLE uce_affected_rows_test (id INT PRIMARY KEY, value INT NOT NULL)"); + mysql.query("INSERT INTO uce_affected_rows_test VALUES (1,10),(2,20)"); + u32 inserted = mysql_affected_rows(&mysql); + mysql.query("UPDATE uce_affected_rows_test SET value=value+1 WHERE id=1"); + u32 updated = mysql_affected_rows(&mysql); + mysql.query("SELECT * FROM uce_affected_rows_test"); + u32 selected = mysql_affected_rows(&mysql); + mark( + "mysql_affected_rows()", + inserted == 2 && updated == 1 && selected == 0 ? "pass" : "fail", + "inserted=" + std::to_string((u64)inserted) + " updated=" + std::to_string((u64)updated) + " selected=" + std::to_string((u64)selected) + ); } site_tests_summary(passed, failed, skipped, "Memcache or MySQL checks are allowed to skip cleanly when the corresponding service is not available on the development host."); site_tests_page_end(); -} \ No newline at end of file +} diff --git a/src/lib/mysql-connector.cpp b/src/lib/mysql-connector.cpp index 4427dd0..8a427f6 100644 --- a/src/lib/mysql-connector.cpp +++ b/src/lib/mysql-connector.cpp @@ -202,6 +202,7 @@ static bool mysql_has_unquoted_positional_placeholder(String query); DValue MySQL::query(String q) { + affected_rows = 0; if(mysql_has_unquoted_positional_placeholder(q)) { _preload_next_error_code = CR_UNKNOWN_ERROR; diff --git a/src/lib/mysql-connector.h b/src/lib/mysql-connector.h index 391f5dc..68ea445 100644 --- a/src/lib/mysql-connector.h +++ b/src/lib/mysql-connector.h @@ -104,3 +104,8 @@ inline u64 mysql_insert_id(MySQL* m) { return(m->insert_id); } + +inline u32 mysql_affected_rows(MySQL* m) +{ + return(m ? m->affected_rows : 0); +} diff --git a/src/wasm/core.cpp b/src/wasm/core.cpp index c682605..3135d32 100644 --- a/src/wasm/core.cpp +++ b/src/wasm/core.cpp @@ -280,6 +280,7 @@ static bool wasm_mysql_has_unquoted_positional_placeholder(String query) DValue MySQL::query(String q) { + affected_rows = 0; if(wasm_mysql_has_unquoted_positional_placeholder(q)) { _preload_next_error_code = 2000;