こんにちは、
かなり複雑な JMP スクリプトがあるのですが、奇妙な方法で失敗しています。その理由を理解したいと思います。説明に入る前に、ここでの複雑さをお詫びします。
私は、名前空間「sql_lib」を定義する sql_lib.jsl というライブラリを作成しました。その名前空間内に、「sql_lib:QueryBatchService」という名前のクラス clsQueryBatch を定義しました。このクラスの目的は、複数の SQL クエリを簡単にバッチ処理して、バックグラウンドで同時に実行できるようにすることです。アイデアは、sql_lib:QueryBatchService 型のオブジェクトをインスタンス化するときに、オブジェクトにクエリを追加し、クラス メソッド run_queries() を呼び出してすべてのクエリを起動し、最後にクラス メソッド get_results() を使用してすべてのクエリの結果を取得するというものです。このクラスの完全な実装は実際には重要ではありませんが、私の方法論は次のとおりです。クラスの _ init _() メソッドは、渡されたパラメーターから、使用するデータベース セッションや結果テーブルの必要な可視性レベルなど、いくつかのメンバー変数を設定します。また、重要な点として、匿名の名前空間 this:m_ns も作成します。この名前空間には、完了したクエリやエラーが発生したクエリの数とともに、クエリの結果を保存および取得します。 _ init _ メソッドは次のようになります (注: また、sql_lib:DBSession というデータベース接続のラッパー クラスも作成しました。このクラスの目的は、各データベース接続に名前を付けて、同じ接続を複数のクエリで簡単に追跡および再利用し、エラーが発生したときに再接続できるようにすることです)。
_init_ = Method({
db_session,
visibility = 1
},
If(! (db_session<<GETNAME></GETNAME>
Once the object is instantiated, I add queries to the queue with add_query():
<CODE class=" language-jsl">add_query = Method({query_str,query_name},
If(!IsString(query_str),
Write("clsQueryBatch:add_query requires an SQL query string as a parameter.\!N");
Throw();
);
query = NewSQLQuery(Connection(m_dbc), CustomSQL(query_str));
query << Query Name(query_name);
m_queries[query_name]=query;
m_ns:total++;
);
And I can then launch all queued queries with run_queries(). This is where the weirdness happens. You’ll notice that I’ve created an Associative Array variable in the anonymous m_ns namespace called results. This should be available as m_ns:results, and I take advantage of this by wrapping the code that runs the queries in Eval(EvalExpr()) and injecting the m_ns_name member variable as an expression into the OnRunComplete method of the RunBackground message sent to each query. I recently changed m_ns:results from a List to an Associative Array because I needed to be able to ensure that I could track down multiple differently named result tables. When I was using a list to track the results, this code worked fine, but when I try to assign a value into the Associative Array, I get the error “Not subscriptable value in access or evaluation of 'Assign' , ns:results[key] = /*###*/queryResult/*###*/“. Preamble completed, here’s the code for run_queries():
<CODE class=" language-jsl">run_queries = Method({},
If(m_visibility==1,
ForEach({{query_name,query},idx}, m_queries,
Eval(
EvalExpr(
query << RunBackground(
OnRunComplete(
Write("Query complete.\!N");
ns = Namespace(Expr(m_ns_name));
key = Eval(Expr(query_name));
Show(ns:results,Type(ns:results),key,queryResult);
ns:results[key] = queryResult;
ns:complete++;
),
OnRunCanceled(
Write("Query cancelled.\!N");
ns = Namespace(Expr(m_ns_name));
ns:error++;
),
OnError(
Write("Query failed!\!N");
ns = Namespace(Expr(m_ns_name));
ns:error++;
)
)
)
)
)
, //else
ForEach({{query_name,query},idx}, m_queries,
Eval(
EvalExpr(
query << RunBackground(
OnRunComplete(
ns = Namespace(Expr(m_ns_name));
key = Eval(Expr(query_name));
Show(ns:results,Type(ns:results),key,queryResult);
ns:results[key] = queryResult;
ns:complete++;
),
Invisible,
OnRunCanceled(
Write("Query cancelled.\!N");
ns = Namespace(Expr(m_ns_name));
ns:error++;
),
OnError(
ns = Namespace(Expr(m_ns_name));
Write("Query failed!\!N");
ns:error++;
)
)
)
)
)
)
);
As you can see, I’ve put a few Show() statements in here to try to understand what’s happening. The results of those are what prompts my question. Please also note that the query runs and generates a data table as expected, the problem arises when I try to store a reference to that data table for later use.
<CODE class=" language-jsl">Show(ns:results,Type(ns:results),key,queryResult);
puts this in the log:
<CODE class=" language-jsl">ns:results = [=>];
Type(ns:results) = "Associative Array";
key = "subid_temp_table_data";
queryResult = DataTable("subid_temp_table_data");so clearly the namespace is resolving correctly, and the type of ns:results is Associative array, and key is a string, queryResult is a datatable, but for some reason I am unable to create a new key=>value pair in the ns:results AA. Remember, this worked when ns:results was a list and I used Insert Into(ns:results, queryResult). Is there a difference in the memory context for lists and associative arrays that I’m violating in some way here? Usually in the past when calling RunBackground and using the OnRunComplete context, I’ve used a global variable to hold the results of the query, is this an issue with my nested namespace:class:namespace structure? Any insight you can provide would be greatly appreciated.
JMP サポートの Jasean のおかげで、結果の連想配列を初期化したときに AssociativeArray() 関数を使用したためにこのエラーが発生していたことが判明しました。代わりに [=>] 表記を使用するように変更すると、問題は解決しました。