Hallo,
Ich habe also ein ziemlich komplexes Stück JMP-Skript, das auf eine seltsame Weise fehlschlägt, und ich würde gerne wissen, warum. Ich entschuldige mich gleich zu Beginn für die Komplexität, bevor ich näher darauf eingehe.
Ich habe eine Bibliothek geschrieben, die wir sql_lib.jsl nennen und die einen Namespace „sql_lib“ definiert. Innerhalb dieses Namespace habe ich eine Klasse clsQueryBatch mit dem Namen „sql_lib:QueryBatchService“ definiert. Der Zweck der Klasse besteht darin, eine einfache Stapelverarbeitung mehrerer SQL-Abfragen zu ermöglichen, die gleichzeitig im Hintergrund ausgeführt werden. Die Idee ist, dass man, wenn man ein Objekt vom Typ sql_lib:QueryBatchService instanziiert, Abfragen zum Objekt hinzufügen und dann die Klassenmethode run_queries() aufrufen kann, um sie alle zu starten und schließlich die Ergebnisse aller Abfragen mit der Klassenmethode get_results abzurufen (). Die vollständige Implementierung dieser Klasse ist nicht wirklich relevant, aber meine Methodik ist wie folgt: Die Methode _ init _() der Klasse richtet aus den übergebenen Parametern einige Mitgliedsvariablen ein, wie die zu verwendende Datenbanksitzung und die gewünschte Sichtbarkeit Ebene der Ergebnistabellen, und was noch wichtiger ist, es erstellt auch einen anonymen Namespace this:m_ns, in dem ich die Ergebnisse der Abfragen zusammen mit der Anzahl der abgeschlossenen/fehlerhaften Abfragen speichere und abrufe. Die _init_ -Methode sieht so aus (Hinweis: Ich habe auch eine Wrapper-Klasse für die Datenbankverbindung namens sql_lib:DBSession erstellt, deren Zweck darin besteht, jeder Datenbankverbindung einen Namen zu geben, damit ich dieselbe Verbindung problemlos für mehrere Abfragen verfolgen und wiederverwenden kann , erneute Verbindung, wenn ein Fehler auftritt):
_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.
Dank Jasean vom JMP-Support stellte sich heraus, dass dieser Fehler auftrat, weil ich beim Initialisieren des assoziativen Arrays mit den Ergebnissen die Funktion AssociativeArray() verwendete. Indem ich dies änderte, um stattdessen die Notation [=>] zu verwenden, löste ich mein Problem.