Преглед изворни кода

Merge pull request #11326 from paulozulato/fix-oracle-table-check

fix(oracle): fix return error checking on table validation
Paulo Zulato пре 2 година
родитељ
комит
2c153c11e7

+ 42 - 3
apps/emqx_bridge_oracle/test/emqx_bridge_oracle_SUITE.erl

@@ -165,6 +165,9 @@ sql_insert_template_for_bridge() ->
 sql_insert_template_with_nested_token_for_bridge() ->
     "INSERT INTO mqtt_test(topic, msgid, payload, retain) VALUES (${topic}, ${id}, ${payload.msg}, ${retain})".
 
+sql_insert_template_with_inconsistent_datatype() ->
+    "INSERT INTO mqtt_test(topic, msgid, payload, retain) VALUES (${topic}, ${id}, ${payload}, ${flags})".
+
 sql_create_table() ->
     "CREATE TABLE mqtt_test (topic VARCHAR2(255), msgid VARCHAR2(64), payload NCLOB, retain NUMBER(1))".
 
@@ -333,10 +336,11 @@ update_bridge_api(Config, Overrides) ->
 probe_bridge_api(Config) ->
     probe_bridge_api(Config, _Overrides = #{}).
 
-probe_bridge_api(Config, _Overrides) ->
+probe_bridge_api(Config, Overrides) ->
     TypeBin = ?BRIDGE_TYPE_BIN,
     Name = ?config(oracle_name, Config),
-    OracleConfig = ?config(oracle_config, Config),
+    OracleConfig0 = ?config(oracle_config, Config),
+    OracleConfig = emqx_utils_maps:deep_merge(OracleConfig0, Overrides),
     Params = OracleConfig#{<<"type">> => TypeBin, <<"name">> => Name},
     Path = emqx_mgmt_api_test_util:api_path(["bridges_probe"]),
     AuthHeader = emqx_mgmt_api_test_util:auth_header_(),
@@ -539,6 +543,14 @@ t_start_stop(Config) ->
     ok.
 
 t_probe_with_nested_tokens(Config) ->
+    ProbeRes0 = probe_bridge_api(
+        Config,
+        #{<<"sql">> => sql_insert_template_with_nested_token_for_bridge()}
+    ),
+    ?assertMatch({ok, {{_, 204, _}, _Headers, _Body}}, ProbeRes0).
+
+t_message_with_nested_tokens(Config) ->
+    BridgeId = bridge_id(Config),
     ResourceId = resource_id(Config),
     reset_table(Config),
     ?assertMatch(
@@ -553,7 +565,34 @@ t_probe_with_nested_tokens(Config) ->
         _Sleep = 1_000,
         _Attempts = 20,
         ?assertEqual({ok, connected}, emqx_resource_manager:health_check(ResourceId))
-    ).
+    ),
+    MsgId = erlang:unique_integer(),
+    Data = binary_to_list(?config(oracle_name, Config)),
+    Params = #{
+        topic => ?config(mqtt_topic, Config),
+        id => MsgId,
+        payload => emqx_utils_json:encode(#{<<"msg">> => Data}),
+        retain => false
+    },
+    emqx_bridge:send_message(BridgeId, Params),
+    ?retry(
+        _Sleep = 1_000,
+        _Attempts = 20,
+        ?assertMatch(
+            {ok, [{result_set, [<<"PAYLOAD">>], _, [[Data]]}]},
+            emqx_resource:simple_sync_query(
+                ResourceId, {query, "SELECT payload FROM mqtt_test"}
+            )
+        )
+    ),
+    ok.
+
+t_probe_with_inconsistent_datatype(Config) ->
+    ProbeRes0 = probe_bridge_api(
+        Config,
+        #{<<"sql">> => sql_insert_template_with_inconsistent_datatype()}
+    ),
+    ?assertMatch({ok, {{_, 204, _}, _Headers, _Body}}, ProbeRes0).
 
 t_on_get_status(Config) ->
     ProxyPort = ?config(proxy_port, Config),

+ 24 - 1
apps/emqx_oracle/src/emqx_oracle.erl

@@ -433,9 +433,32 @@ check_if_table_exists(Conn, SQL, Tokens0) ->
     case jamdb_oracle:sql_query(Conn, {SqlQuery, Params}) of
         {ok, [{proc_result, 0, _Description}]} ->
             ok;
-        {ok, [{proc_result, 6550, _Description}]} ->
+        {ok, [{proc_result, 942, _Description}]} ->
             %% Target table is not created
             {error, undefined_table};
+        {ok, [{proc_result, _, Description}]} ->
+            % only the last result is returned, so we need to check on description if it
+            % contains the "Table doesn't exist" error as it can not be the last one.
+            % (for instance, the ORA-06550 can be the result value when table does not exist)
+            ErrorCodes =
+                case re:run(Description, <<"(ORA-[0-9]+)">>, [global, {capture, first, binary}]) of
+                    {match, OraCodes} -> OraCodes;
+                    _ -> []
+                end,
+            OraMap = maps:from_keys([ErrorCode || [ErrorCode] <- ErrorCodes], true),
+            case OraMap of
+                _ when is_map_key(<<"ORA-00942">>, OraMap) ->
+                    % ORA-00942: table or view does not exist
+                    {error, undefined_table};
+                _ when is_map_key(<<"ORA-00932">>, OraMap) ->
+                    % ORA-00932: inconsistent datatypes
+                    % There is a some type inconsistency with table definition but
+                    % table does exist. Probably this inconsistency was caused by
+                    % token discarding in this test query.
+                    ok;
+                _ ->
+                    {error, Description}
+            end;
         Reason ->
             {error, Reason}
     end.

+ 1 - 0
changes/ee/fix-11326.en.md

@@ -0,0 +1 @@
+Fixed return error checking on table validation in the Oracle bridge.