Robert Cemper · Mar 1, 2018 go to post

you need an oref in ref 
and also in Myproperty1, ... 
So you have to check both . see answer

Robert Cemper · Mar 1, 2018 go to post
ClassMethod myfuct( id) As %String
{
  set ref=##class(myClass).%OpenId(id)
  If '$isobject(ref) quit "no object 1, no return"
  if '$isrobject(ref.
Myproperty1) quit "no object 2, no return"
  set str="my return: "_ref.Myproperty1.OtherClass1Property
  quit str
}
Robert Cemper · Mar 1, 2018 go to post

you do 

set ref=##class(myClass).%OpenId(id)

but you don't check if you really got an object.  the id might be invalid
continue with 

if '$isobject(ref) quit ""

Robert Cemper · Mar 1, 2018 go to post

the code causing the problem in MyClass.2.int looks most likely like this:

Set oid=$select(i%Myproperty="":"",1:$listbuild(i%Myproperty_""))

you are inside an ObjectMethod   and miss the actual Object  reference.
This happens when you try to access a property inside a Classmethod.
 classic mistake:

ClassMethod MyMethod(1,2,3) as %Status {
 set x=..Myproperty
}

correct use: 

ClassMethod MyMethod(oref,1,2,3) as %Status {
 set x=oref.Myproperty
}
Robert Cemper · Mar 1, 2018 go to post

Whether external backup or backup from a mirror (also asynchronous) or Caché backup you always have to identify
the point in time when your DB is logically consistent. What I think of is no open transactions, no open dependencies.

If you know that point in time you could separate your async mirror or shadow and run any backup from there.
Or just shut down your async server instance and run snapshots.
But there might also be a time gap between master and async server.
Once completed your async server can join again and catch up whatever time that may take.   
The critical point is to know when the async server has reached consistency.
But that depends on the application.
 

Robert Cemper · Feb 28, 2018 go to post

there is a method CopyFromStream that really moves the content to a new Stream
So your PDF moves from physical file to a Global stream that you work up and down as a "private" copy.
Without touching the original anymore. This might be a useful option.
 

Robert Cemper · Feb 28, 2018 go to post

for a file stream it's a physical file, for a global stream it's a global or part of it.
if you clear it you either delete the file or the global (or its part )that holds the stream.
stream in Caché describes a sequence of persistent bytes on disk that you work on with dedicated common methods.
this must not be mixed up with a stream of characters on a network connection. if you miss a character there it's gone. 

Robert Cemper · Feb 28, 2018 go to post

Clear() removes all content. The easiest way to CLEAR a file is to remove it. in any file system.

Robert Cemper · Feb 28, 2018 go to post

"lightweight" is the theoretical approach for object purists that want to have just 1 object covering the world and don't care about practical use. They often were moaning "oh only 1.n relationship".  
 As you noted "heavy" allows real relation management. And could be faster in some cases.

Robert Cemper · Feb 28, 2018 go to post

Hi Alexey,
You hit the point: "lightweight"  just documents the relation.  Full stop. No further service.
You have to service (ie. Delete) it at both ends.
If you use a serial object with OREF + Status)  you still have to service both ends.

The "heavy" variant does it centralized at one place.
Though from storage point of view you move out the additional subscript level from array.

Robert Cemper · Feb 27, 2018 go to post

Hi, Evegeny!
for both variants you work along the array by GetNext() method
for each employee you have an array with the OREFs of the company. So you have the full object at hands.
similar the opposite direction from company to employee and employee->nae in SQL or employee.name

And as we always have a Collection type Array indexing is simple either by (KEY) or (ELEMENT). whether you  need the ID or the OREF
http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GSQLOPT_indices#GSQLOPT_indices_collections

The only tricky action is DELETE: there you have to have a method to "DisRelate" before delete.
But real commercial systems never delete anything. Just set a flag "isDeleted". Which is much easier for any "undo" action. 

Robert Cemper · Feb 27, 2018 go to post

It's a value returned from OS:
So this might be platform dependent.
the call is  $zu(140,5,$select($$$isVMS&&(%file'[";"):%file_";*",1:%file))
the part for VMS deletes all versions of the file if the name is not terminated by " ;"

Robert Cemper · Feb 27, 2018 go to post

First I would expect Soap.InboundAdapter writes to stream and has no limit.

But if longstrings are enabled the MAXsize of a %String is ~3.6 MB.   Your description sounds to fit this.
You may look at your Adapter where the input goes.
But it might be also later processing of a stream to cause the problem.

Robert Cemper · Feb 27, 2018 go to post

doc say:

classmethod Delete(filename As %String, Output return As %Integer) as %Integer
Deletes the file filename. Returns true if it succeeds and false otherwise. Pass return by reference to obtain the low level return value in case of errors

so try:

set success = file.Delete(File, .return)

to see the reason for failing

Robert Cemper · Feb 26, 2018 go to post

You look for INSERT from Query
doc is here http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=RSQL_insert#RSQL_insertselect

As far as I see it should work the way you have written
(assuming data types between target and source match) 

To estimate runtime you may try the select count(*) from  VwSrcTable  first to get a feeling
how many records that will be. 

Then during load running Select count(*) from DestTable from a 2nd session may let you see your progress.
 

Robert Cemper · Feb 22, 2018 go to post

SQLCODE -99 Privilege violation

You have 3 different sets of access rights in this scenario

  • your  development user    
  • the application user
  • the user your Caché / ENS server installation is running on

Check if also  your server has the required access rights at OS level.
under *IX it's quite likely that you don't run as root.
(though this happens also on other OS)
 

Robert Cemper · Feb 21, 2018 go to post

An interesting observation!
IT WORKS !

I just retyped it a little bit extended for fast retry:

set minage = 80
set myquery = 3
set tStatement = ##class(%SQL.Statement).%New()
set myquery(1) = "SELECT top 10 %ID AS id, Age , Name, %ODBCOUT(DOB) DOB, Home_State"
set myquery(2) = "FROM Sample.Person WHERE Age > :minage"
set myquery(3) = "ORDER BY 2"
set qStatus = tStatement.%Prepare(.myquery)
set tResult = tStatement.%Execute()
do tResult.%Display()
in SAMPLES:
id      Age     Name                    DOB     Home_State
16      82      Schaefer,Alvin S.       1935-05-05      HI
108     82      Adams,Brian Q.  1936-02-21      IL
199     82      Yeats,Ashley K. 1935-10-28      NC
74      83      Ravazzolo,Molly I.      1934-12-31      WV
63      84      Cheng,Filomena J.       1933-12-27      NM
69      84      Yeats,Patrick U.        1933-04-19      KY
92      85      Lepon,Liza M.   1932-06-03      MN
94      87      Browne,Patricia I.      1930-04-05      AL
111     87      Orlin,Edward J. 1930-04-10      OR
197     87      Rogers,Barbara M.       1930-12-06      WI

It also works using traditional %ResultSet

Though I didn't interpret nor use it that way it is documented here:

Dynamic SQL versus Embedded SQL    (4th point)

Dynamic SQL can accept a literal value input to a query in two ways:
input parameters specified using the 
“?” character,
and input host variables (for example, :var).
Embedded SQL uses input and output host variables (for example, :var).
Robert Cemper · Feb 21, 2018 go to post

reason #1) 40 yrs. backward compatibility  
#2) in $LB not everything is a string but has its hidden data types 
while a string is sequence of bytes an integer get#s a binary representation ( ~ 19 digits ==> 8 byte (int64))
try:

set x=$lb(64444,"64444")  zzdump x
04 04 BC FB 07 01 36 34 34 34 34


it's really byte saving

Robert Cemper · Feb 20, 2018 go to post

In general I would agree:
Though in order to use the class query you have the change  to namespace "%SYS" and  back.
As the query is predefined you finally build your own lookup list which is a copy of the original global.
Anyhow this would provide the required result:

     kill roles
    set roles=""
    new $namespace
    zn "%SYS"
    set rs=##class(%ResultSet).%New("Security.Roles:ListAll1")
    set tSC=rs.Execute()
    if tSC
       {
        while rs.Next() {
            set role=rs.Get("Name")
            write ">",role,! ;; just for display
            set roles($zcvt(role,"L"))=""
       }
     set rs=""                       ;; for save return from "%SYS"
     zw roles                        ;; for demo
     set list2=$lfs(input,"CN=")
     for i=2:1:$LL(list2) {
        set CN=$p($li(list2,i),",") ;; get 1st piece
        set CN=$zcvt(CN,"L") ;; lower case required..v
        set exists=''$d(roles(CN))
        write !,i," ",exists," ",CN ;; for debugging and demo
        if exists write " role found"
        }
     quit                            ;; get back to original namespace
Robert Cemper · Feb 19, 2018 go to post
for i=2:1:$LL(list2) {
  set CN=$p($li(list2,i),",") ;get 1st piece 
  set CN=$zcvt(CN,"L")        ;lower case required..v 
  set 
exists=''$d(^|"%SYS"|SYS("Security","RolesD",CN))
  write !,i,"  ",exists," ",CN
  if exists write " role found"
}  
Robert Cemper · Feb 19, 2018 go to post

so with a little change you get the content of CN= as starting string 

set list2=$lfs(input,"CN=")
; ignore trailer
for i=2:1:$LL(list2) write !,i,?5,$p($li(list2,i),",")
 
2    Access.Ensemble.Developer.User
3    [CPD Admin]
4    [MUSE_Access]
5    [IT eMaterials]