Robert Cemper · Nov 26, 2017 go to post

A few recommendations:
#2) save you original Global as you do otherwise.  [Just to be Save]
#1)  In Studio Copy class has a checkbox to copy Storage Definition (=Globals) . Set it.
  In the new class add ClassParameter MANAGEDEXTENT=0 ;

/// The <var>MANAGEDEXTENT</var> parameter can be set to 0 (zero) to cause the Extent Manager
/// to ignore this class. If set to 1 then the Extent Manager will register globals used by
/// the class and detect collisions. Unmanaged extents (MANAGEDEXTENT = 0) are not checked.
/// Currently, only classes using default storage (%Library.CacheStorage) can be managed.
Parameter MANAGEDEXTENT As INTEGER [ Constraint = "0,1", Flags = ENUM ] = 1;

 

So the old and the new class use the same Globals.
Now go on with #3  to #6
If you miss something in refactoring the damage should be limited as you just change names not the Storage in Globals.
Assuming the change of ClassName is all you do.

Robert Cemper · Nov 24, 2017 go to post

I see. It's hard generated
IndexNext distracted me

But you may call it individually. With your sequence then.

Robert Cemper · Nov 24, 2017 go to post

For %BuildIndices you may provide a list  or use default. it doesn't affect sequence

example from Sample.Person.1.Int

%BuildIndices(pIndexList="",pAutoPurge=1,pLockFlag=0,pJournalFlag=1,pStartID="",pEndID="",pIgnoreIndexList="") public {
if ($listlength(pIndexList)=1)&&($listget(pIndexList,1)="") return 1 }
Set class=$classname(),tBuildFlags=1,tBuildFlags(class)=$c(0,0,0,0,0,0)
Set tPtr=0,tStatus=1,pJournalFlag=''pJournalFlag
While $listnext(pIndexList,tPtr,tIndex) {
continue:tIndex=""
If '$d(^oddCOM(class,"i",tIndex)) {
Set tStatus=$select(+tStatus:$$Error^%apiOBJ(5066,class_"::"_tIndex),1:$$AppendStatus^%occSystem(tStatus,$$Error^%apiOBJ(5066,class_"::"_tIndex)))
}
}
If ('tStatus) RETURN tStatus
if $listfind(pIndexList,"$Person") set $Extract(tBuildFlags(class),1)=$c(1) }
if ((pIndexList="")||($listfind(pIndexList,"FCOL"))),'$listfind(pIgnoreIndexList,"FCOL") set $Extract(tBuildFlags(class),2)=$c(1) }
if ((pIndexList="")||($listfind(pIndexList,"NameIDX"))),'$listfind(pIgnoreIndexList,"NameIDX") set $Extract(tBuildFlags(class),3)=$c(1) }
if ((pIndexList="")||($listfind(pIndexList,"SSNKey"))),'$listfind(pIgnoreIndexList,"SSNKey") set $Extract(tBuildFlags(class),4)=$c(1) }
if ((pIndexList="")||($listfind(pIndexList,"ZipCode"))),'$listfind(pIgnoreIndexList,"ZipCode") set $Extract(tBuildFlags(class),5)=$c(1) }
if ((pIndexList="")||($listfind(pIndexList,"dobx"))),'$listfind(pIgnoreIndexList,"dobx") set $Extract(tBuildFlags(class),6)=$c(1) }
If ((pIndexList="")||($Ascii(tBuildFlags(class),5))) && '$listfind(pIgnoreIndexList,"$Person") set $extract(tBuildFlags(class),1)=$c($select((pStartID'="")||(pEndID'=""):1,1:2)) }
Quit ..%BuildIndexInternal(.pLockFlag,.pAutoPurge,.pStartID,.pEndID,.pIndexList,.tBuildFlags,"^Sample.PersonD",1,.pJournalFlag,0) }
 
 

%Save does it straight by ASSCII sorting of index names (lower after Upper case)

See %SaveData(id)  in the generated .int 

Robert Cemper · Nov 24, 2017 go to post

ok.
You followed the direction: that you mark the "unavailable" value by a UNIQUE value.
So for SQL it's NOT NULL.
I agree with you that NullString (COS) => String of length 0 and NULL(SQL) is confusing 
[since invention of SQL in the late 60ties]

Robert Cemper · Nov 24, 2017 go to post

Take a closer look to %Library.Date, %Library.TimeStamp, %Library.Integer
and you will see the various methods for LogicalTo.....
The switch you select applies to the final presentation only. Not to internal calculations.

Robert Cemper · Nov 23, 2017 go to post

I think there is a basic misunderstanding of what NULL means in SQL.

NULL in SQL means unknown / undefined value / any value
Which is to my understanding a clear contradiction to uniqueness.

If you assign yourself something indicating NO VALUE ( e.g '') then it works but it isn't NULL anymore in the sense of SQL.
 

Robert Cemper · Nov 23, 2017 go to post

as documented in
http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

DATEPART delivers a %Integer value.
Differently to %Date which has different display, logical and ODBC presentation %Integer does not follow any specific presentation but is just Integer and nothing else.
And your input to DATEPART function is in any example the same: the logical value of TimeCreated.

To  cover your expectations you would need to adapt your input yourself. eg by %ODBCOUT() function.
or the related LogicalToDisplay function.

Your expectation that a data type %Integer does a revers research how it was calculated is just un-realistic.

Robert Cemper · Nov 19, 2017 go to post

A Total different idea.
if Transaction.Account is defined as Account object (could also be calculated)
     [ Property Account as Account ;   ]

then you may use implicit join for your query. 
it looks like this:

select Account.Name, Account.State, Transaction.Amt, Transaction.Date, Transaction.Service
from Transaction 
left join Account 
    on Account.Id = Transaction.Account  
where Transaction.Account in ( 
    Select Account.Id
     from Account

     where Transaction.Account ->Type is not null
     and Transaction.Account->Id>123456789        
     and Transaction.Account->Id <=323456789     
  )   
and Transaction.Date >= ?
and Transaction.Date <= ?
 
Robert Cemper · Nov 19, 2017 go to post

OK, that looks better smiley

now go to Mgmt Portal /SQL and verify for both tables that you see values in column Selectivity (marked)

IF THERE IS NO SELECTIVITY ANY QUERY PLAN IS JUST GUESSWORK.

if this is empty Query Generator just can guess and do a lot of unnecessary extra work.

so got Tune Table click it

and this you get there information that the Query Generator allows to make useful optimizations (marked)

Next enter your specific  query and click to "Show Plan"
that marked information tells you what is happening and Relative Cost qualifies the expected performance. 

This query plan tells you what is really happening.

Robert Cemper · Nov 19, 2017 go to post

At  first sight I'd say the Query Generator is right as your Sub Select Just adds some more WHERE conditions.
Your range on Transction.Date  with related index might be much more limiting than your range on Account.Id.
A index on Account.Type might also speed up your query.
 

where Account.Id in (
    Select Account.Name
     from Account

?? Is Account.Name the same as Account.Id  ???  
IN ( ) expects EXACT VALUES !

Suggestion if no done yet: Run tune Table for both tables

Next: publish the generated Query plan.
 

Robert Cemper · Nov 17, 2017 go to post

much faster and straight forward string conversion then $ZD* stuff doing unnecessary conversions .
yesyes

Robert Cemper · Nov 17, 2017 go to post

24 hrs is fine. but which time zone? UTC,EST, ...?
Rollig it along the globe will  extend it to be 48 hrs.

Robert Cemper · Nov 16, 2017 go to post

I assume you know where you get your email address from.
The rest is straight COS and your code my look like this


set myEmail=.......      ;wherever you get it from your PID-13-4
set msg=..CreateTextMessage(myEmail)   
ClassMethod CreateTextMessage(toMail) As %Net.MailMessage
{
 Set msg = ##class(%Net.MailMessage).%New()
 Set msg.From = "test@test.com"
 Do msg.To.Insert(toMail)
 Do msg.Cc.Insert("yyy@yyy.com")
 Do msg.Bcc.Insert("zzz@zzz.com")
 Set msg.Subject="subject line here"
 Set msg.IsBinary=0
 Set msg.IsHTML=0
 Do msg.TextData.Write("This is the message.") 
 Quit msg
}
Robert Cemper · Nov 15, 2017 go to post

A dirty hack:

- make a new class extending %SerialObject with  VALIDIFNULL  set.
- export your serial classes (to XML)
- replace %SerialObject by your MySerialObject
- reload the changed classes.

Not so nice but I had the same issue with some 100 Serial Objects.

The more sophisticated way would be do it programatically over %Dictionary.DefinedProperty  ..... 
Very interesting and very time consuming  

Robert Cemper · Nov 15, 2017 go to post

You have to set $ZTRAP again at the begin:
Or start with do infile^myroutine ....
at the 1. run it is set i line 3
you my also pass the filename as parameter 

Robert Cemper · Nov 15, 2017 go to post

Welcome back!
infile  ; simple file read
  set filename="C\mydir\myfile.txt"
  set $ZTRAP="end"
  open filename:("R"):0 else  Write "file error"
  for line=1:1 use filename read text use 0 write text,! 
end
 close filename
  set $ZTRAP=""
  use 0 write "Done",
  quit

it's not so sophisticated and I used the end-of-file error to exit

This is also available in class %Library.File with lot more comfort 
http://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?…

HTH
 

Robert Cemper · Nov 15, 2017 go to post

Taskmanager is a part of Caché System Management and you should read the Docs.
JOB is a COS command also used in Taskmanager but not only. Any routine may use it.

So your Request / Question is just not clear
 

Robert Cemper · Nov 15, 2017 go to post

If you don't want / need the content as object and just want to convert XML2JSON
why wasting time and energy to re-invent the wheel an not just using any of the many downloadable tools
and call them over $ZF(-2)  and consume the result ?
Google gave my some thousand hits of tested solutions e.g. https://github.com/sinelaw/xml-to-json

I mean it's doable with Caché but file_in => file_out is not more than a nice exercise for training.
 

Robert Cemper · Nov 15, 2017 go to post

SQL Code and it's style and methodology was there long before Objects in actual style where introduced. (feeling mid 90ties)
It was mainly kept for backward compatibility.
In Caché 5 (2002) they were a real parallel universe  Object - SQL.
Later Computed + SQLcomputed Properties were for long time the only  place for common code.

Robert Cemper · Nov 14, 2017 go to post

Make it a serial class with 2 numeric  properties and a calculated for the difference

Robert Cemper · Nov 13, 2017 go to post

Positive! Confirmed!
If you highjack your previous workspace (as I did by accident) there's nothing to move anymore.
Especially all conections are there already.

Robert Cemper · Nov 13, 2017 go to post

Suggested solution:

#1 create a ROLE with resources DOCBOOK (Readonly) + the required Nmaspaces

#2 remove required resources %Development from web application  /csp/documatic

 #3 next create a user with  the new defined role (here: "docread")

I decided not to give %Development as it could allow access to terminal prompt.

Robert Cemper · Nov 13, 2017 go to post

Thanks, I missed that leaving before yes

And I've seen the new generated code added to  %Save()
It confirmed my feelings about %* ....  smiley

Robert Cemper · Nov 13, 2017 go to post

Thank You Alex!
I knew it's a can of worms and spread over documentation like feeding pigeons.
And honestly I was pretty sure not catch them all and hesitated quite some time to touch it..   
yes  Great contribution.