1 namespace == 1 project.
- Log in to post comments
1 namespace == 1 project.
Yes for custom storage you'll need to check the storage for hints.
In the case of %Dictionary package check %LoadData method.
To get method description call:
set desc = $$$defMemberKeyGet(CLASS,$$$cCLASSmethod,METHOD,$$$cMETHdescription)Can you please elaborate on your question?
Do you want to start using git? If so check this series of articles.
Do you want to do some advanced git flow control? If so please describe what do you want in more detail.
SQL is a declarative language (same as HTML for example). It does not DO anything. All it is is a description of what do you want to achieve.
In the case of InterSystems IRIS (and any other dbms for that matter) we take SQL statement, parse it into AST and generate code in other imperative language from AST. Now this generated code gets executed.
In case of InterSystems IRIS we generate the code in ObjectScript language. For DROP statement it would include this line:
kill ^globalD
If you want to you actually can see generated OjectScript code. To do that
Open SMP > System Administration > Configuration > SQL and Object Settings > General SQL Settings.
Enable "Cached Query - Save Source" — This specifies whether to save the routine and INT code that Caché generates when you execute any Caché SQL except for embedded SQL.
After that purge query from portal if it already exists and execute the query again in SMP.
You'll see something like this:
Cached query %sqlcq.<NAMESPACE>.cls<NUMBER>
Go to studio and open %sqlcq.<NAMESPACE>.cls<NUMBER> class - it would contain generated ObjectScript code that executes for your SQL query.
C:\TempC:\InterSystems\Ensemble2018\mgr\Temp\b.xlsx
Replace with: C:\InterSystems\Ensemble2018\mgr\Temp\b.xlsx
Set ^%SYS("zenreport","excelserverport")=5005
Great points, Sean.
However there are, I think, areas where macros are needed:
But I definitely agree that overabundance of custom macros makes code unreadable.
Let's say you created class Point:
Class try.Point Extends %Persistent [DDLAllowed]
{
Property X;
Property Y;
}You can also create it via DDL:
CREATE Table try.Point ...It would create the same class.
After compilation our new class would have autogenerated Storage structure which is a mapping of global to data to columns and properties:
Storage Default
{
<Data name="PointDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>X</Value>
</Value>
<Value name="3">
<Value>Y</Value>
</Value>
</Data>
<DataLocation>^try.PointD</DataLocation>
<DefaultData>PointDefaultData</DefaultData>
<IdLocation>^try.PointD</IdLocation>
<IndexLocation>^try.PointI</IndexLocation>
<StreamLocation>^try.PointS</StreamLocation>
<Type>%Library.CacheStorage</Type>
}What is going on here?
From the bottom and up (bolded are important, ignore the rest):
Now our default data is PointDefaultData so let's see it. Essentially it says that global node has this structure:
So we might expect our global to look like this:
^try.PointD(id) = %%CLASSNAME, X, YBut if we output our global it would be empty because we didn't add any data:
zw ^try.PointDLet's add one object:
set p = ##class(try.Point).%New()
set p.X = 1
set p.Y = 2
write p.%Save()And here's our global
zw ^try.PointD
^try.PointD=1
^try.PointD(1)=$lb("",1,2)As you see our expected structure %%CLASSNAME, X, Y is set with $lb("",1,2) which corresponds to X and Y properties of our object (%%CLASSNAME is system property, ignore it).
We can also add a row via SQL:
INSERT INTO try.Point (X, Y) VALUES (3,4)Now our global looks like this:
zw ^try.PointD
^try.PointD=2
^try.PointD(1)=$lb("",1,2)
^try.PointD(2)=$lb("",3,4)So the data we add via objects or sql is stored in globals according to storage definitions (you can modify manually storage definition by replacing X and Y in PointDefaultData - check what happens to new data!)
Now, what happens when we want to execute SQL query?
SELECT * FROM try.PointIt is translated into ObjectScript code that iterates over ^try.PointD global and populates columns based on storage definition - PointDefaultData part of it precisely.
Now for modifications. Let's delete all the data from the table
DELETE FROM try.PointAnd let's see our global after it:
zw ^try.PointD
^try.PointD=2Note that only ID counter is left, so new object/row would have an ID=3. Also our class and table continue to exist.
But what happens on:
DROP TABLE try.PointIt would destroy the table, class and delete the global.
zw ^try.PointDClasses and tables are mappings that are read "on the fly". That's exactly it.
Stores data on disk? Meaning, that if we create these persistent classes, the data is stored twice? Once in the global node and in some other format as defined (or not defined by the class)?
The data is stored in globals and only globals. Globals themselves are physically written on disk.
But just to reiterate, how does the DDL interpret a read definition into a write definition? The data stored in the global node and the definition do line up exactly (in our case, almost not at all).
Please expand your question. Do you mean how does SELECT or DROP or whatever SQL statement against table interacts with globals?
Preface macro with /// to enable autocomplete:
///
#define $$$In...Globals store data. That's the only way data can be stored inside Intersystems products.
Tables and classes are projections of this data. In your created classes (at the end) there's a Storage element.
It contains mappings of class properties (and table columns) to global nodes.
So if you delete this representation it does not delete the underlying global data, because class is essentially just a description of how to read and write into global.
You can delete the class. It would also delete the table.
Why do you want to do that?
Can you describe what do you want to achieve?
It should be started automatically, but you can configure one explicitly at: SMP - System Administration - Configuration - Zen Reports - Excel Servers.
Set log file and try to start it from the same page. I think it would show the root problem.
looks like a Java-based server did not start.
Have you checked that Java is in or not in path for cache service account?
Please post:
Added a dummy BS to production with OnInit:
Class test.InitService Extends Ens.BusinessService
{
Parameter ADAPTER = "Ens.InboundAdapter";
Property Adapter As Ens.InboundAdapter;
Method OnProcessInput(pInput As %RegisteredObject, Output pOutput As %RegisteredObject) As %Status [ CodeMode = expression ]
{
$$$OK
}
/// This user callback method is called via initConfig() from %OnNew() or in the case of SOAP Services from OnPreSOAP()
Method OnInit() As %Status
{
$$$TRACE("INIT")
set sc = ..SendRequestAsync(...)
quit sc
}What's the use case? I think it's better to keep independent tasks separate.
Anyway:
1. Create your own task class by extending %SYS.Task.Definition.
2. Program your task
3. Create a new task, choosing your task class (by TaskName).
1. Execute this query:
SELECT ID FROM %SYS.ProcessQuery WHERE LastGlobalReference [ '1119102928'2. Iterate over result set. ID is process ID.
3. Kill process by id:
do $system.Process.Terminate(processId)Continued from this discussion.
It's better to not create lists, especially lists which you need to filter later.
Write a SQL query, iterate over it results and do stuff you need to do right there.
SQL Query can be a separate class element for readability purposes.
1. I'd like to add to @Nicole.Aaronanswer, that moving code is done in two separate steps:
Interesting questions.
That's definitely not a recommended practice.
Thank you, ended up extracting this method:
ClassMethod GetPrivateProp(oref, propName) As %String
{
Set value = ""
Set cd=$system.CLS.DumpContext(oref,0)
Set inst=$piece(cd,"^",8)
For j=1:1:inst {
Set pd=$system.CLS.Property(j,oref,0)
Set ivar=$piece(pd,"^")
CONTINUE:ivar'=propName
Set slot=$piece(pd,"^",2)
Set value = $zobjval(oref,slot,0,3,slot)
Quit
}
Quit value
}UPD: Simplified code, thanks to @Dmitry Maslennikov suggestion:
ClassMethod GetPrivateProp(oref, propName) As %String
{
Set pd=$system.CLS.Property(propName,oref,0)
Set slot=$piece(pd,"^",2)
Set value = $zobjval(oref,slot,0,3,slot)
Quit value
}1. I definitely recommend using CLS and not XML for general readability and also sane blame/diff output.
2. There should not be any differences to usual Git development (as described in the series of articles you mention). One of our customers is using TFS for Ensemble development. Are you using Studio or Atelier? VSCode? If Studio, you'll need a source control hook, Atelier works as is and you'll need a plugin for VS Code.
3.Check this article for info on CI/CD on TFS.