안녕,
그래서, 저는 이상하게 보이는 방식으로 실패하는 상당히 복잡한 JMP 스크립트가 있는데, 그 이유를 이해하고 싶습니다. 시작하기 전에 여기서 복잡성에 대해 사과드립니다.
저는 sql_lib.jsl이라고 부르는 라이브러리를 작성했는데, 여기에는 "sql_lib"라는 네임스페이스가 정의되어 있습니다. 해당 네임스페이스 내에서 "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() 함수를 사용했기 때문이라는 것이 밝혀졌습니다. 대신 [=>] 표기법을 사용하도록 변경하여 문제가 해결되었습니다.
AssociativeArray()를 호출하면 생성자 객체를 반환하는 듯합니다. 그래서 제가 새 객체를 인스턴스화할 때마다 연관 배열이 덮어씌워졌습니다. 멤버 변수를 [=>] 객체로 정적으로 할당하면 덮어씌워지지 않습니다. 적어도 @제시안 의 이메일에서 제가 얻은 결론은 그렇습니다. 그가 더 자세히 설명해 줄 수 있을지도 모릅니다.