From: Alexei Gradinari Date: Mon, 4 Jul 2016 21:38:57 +0000 (-0400) Subject: res_sorcery_realtime: fix bug when successful UPDATE is treated as failed X-Git-Tag: 13.11.0-rc1~42^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b4a9fa2c9e2c7c5bae5b6bbb4a6fb7f021a1f2f6;p=thirdparty%2Fasterisk.git res_sorcery_realtime: fix bug when successful UPDATE is treated as failed If the SQL UPDATE statement changes nothing then SQLRowCount returns 0. This value should be treated as success. But the function sorcery_realtime_update treats it as failed. This bug was found using stress tests on PJSIP. If there are 2 consecutive SIP REGISTER requests with the same contact data during 1 second then res_pjsip_registrar adds contact location on 1st request and tries to update contact location on 2nd. The update fails and res_pjsip_registrar even removes correct contact location. The test "object_update_uncreated" was removed from test_sorcery_realtime.c because it's now a valid situation. This patch also adds missing debug of extra SQL parameter. ASTERISK-26172 #close Change-Id: I05a7f3051455336c9dda29efc229decf86071303 --- diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c index 2888d35973..2d991a586d 100644 --- a/res/res_config_odbc.c +++ b/res/res_config_odbc.c @@ -137,6 +137,7 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data) if (!ast_strlen_zero(cps->extra)) { const char *newval = cps->extra; + ast_debug(1, "Parameter %d = '%s'\n", x, newval); if (strchr(newval, ';') || strchr(newval, '^')) { ENCODE_CHUNK(encodebuf, newval); ast_string_field_set(cps, encoding[x], encodebuf); diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c index 2c533ea0b6..138d6ea95e 100644 --- a/res/res_sorcery_realtime.c +++ b/res/res_sorcery_realtime.c @@ -271,7 +271,7 @@ static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data return -1; } - return (ast_update_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) <= 0) ? -1 : 0; + return (ast_update_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) < 0) ? -1 : 0; } static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object) diff --git a/tests/test_sorcery_realtime.c b/tests/test_sorcery_realtime.c index 3ed14623ef..64475fb8b3 100644 --- a/tests/test_sorcery_realtime.c +++ b/tests/test_sorcery_realtime.c @@ -711,41 +711,6 @@ AST_TEST_DEFINE(object_update) return AST_TEST_PASS; } -AST_TEST_DEFINE(object_update_uncreated) -{ - RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery); - RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup); - - switch (cmd) { - case TEST_INIT: - info->name = "object_update_uncreated"; - info->category = "/res/sorcery_realtime/"; - info->summary = "sorcery object update unit test"; - info->description = - "Test updating of an uncreated object in sorcery using realtime wizard"; - return AST_TEST_NOT_RUN; - case TEST_EXECUTE: - break; - } - - if (!(sorcery = alloc_and_initialize_sorcery("sorcery_realtime_test"))) { - ast_test_status_update(test, "Failed to open sorcery structure\n"); - return AST_TEST_FAIL; - } - - if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) { - ast_test_status_update(test, "Failed to allocate a known object type\n"); - return AST_TEST_FAIL; - } - - if (!ast_sorcery_update(sorcery, obj)) { - ast_test_status_update(test, "Successfully updated an object which has not been created yet\n"); - return AST_TEST_FAIL; - } - - return AST_TEST_PASS; -} - AST_TEST_DEFINE(object_delete) { RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery); @@ -942,7 +907,6 @@ static int unload_module(void) AST_TEST_UNREGISTER(object_retrieve_regex); AST_TEST_UNREGISTER(object_retrieve_regex_nofetch); AST_TEST_UNREGISTER(object_update); - AST_TEST_UNREGISTER(object_update_uncreated); AST_TEST_UNREGISTER(object_delete); AST_TEST_UNREGISTER(object_delete_uncreated); AST_TEST_UNREGISTER(object_allocate_on_retrieval); @@ -964,7 +928,6 @@ static int load_module(void) AST_TEST_REGISTER(object_retrieve_regex); AST_TEST_REGISTER(object_retrieve_regex_nofetch); AST_TEST_REGISTER(object_update); - AST_TEST_REGISTER(object_update_uncreated); AST_TEST_REGISTER(object_delete); AST_TEST_REGISTER(object_delete_uncreated); AST_TEST_REGISTER(object_allocate_on_retrieval);