CIAO,
Quindi, ho un pezzo abbastanza complesso di script JMP che fallisce in un modo che sembra strano e mi piacerebbe capire perché. Mi scuso per la complessità qui presente prima di entrare nel merito.
Ho scritto una libreria che chiameremo sql_lib.jsl che definisce uno spazio dei nomi "sql_lib". All'interno di tale spazio dei nomi ho definito una classe clsQueryBatch con il nome “sql_lib:QueryBatchService”. Lo scopo della classe è consentire un facile raggruppamento di più query SQL da eseguire simultaneamente in background. L'idea è che quando si istanzia un oggetto di tipo sql_lib:QueryBatchService, si possono poi aggiungere query all'oggetto e poi chiamare il metodo della classe run_queries() per lanciarle tutte, acquisendo infine i risultati di tutte le query con il metodo della classe get_results (). L'implementazione completa di questa classe non è realmente rilevante, ma la mia metodologia è la seguente: il metodo _ init _() della classe imposta alcune variabili membro dai parametri passati, come la sessione del database da utilizzare e la visibilità desiderata livello delle tabelle dei risultati e, cosa importante, crea anche uno spazio dei nomi anonimo this:m_ns che è dove memorizzo e recupero i risultati delle query insieme al numero di query completate/errate. Il metodo _ init _ si presenta così (nota che ho anche creato una classe wrapper per la connessione al database chiamata sql_lib:DBSession, il cui scopo è quello di assegnare un nome a ciascuna connessione al database in modo da poter monitorare e riutilizzare facilmente la stessa connessione per più query , riconnettendosi quando si verifica un errore):
_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.
Grazie a Jasean del supporto JMP, si scopre che questo errore si verificava perché quando ho inizializzato i risultati Associative Array, ho utilizzato la funzione AssociativeArray(). Modificarlo per utilizzare la notazione [=>] ha invece risolto il mio problema.