Julius Kavay · Apr 11, 2022 go to post

Sergei Shutov's answer is correct. The question was, how to remove a specific character (in this case: double quotes) from a string. Your answer is also correct but he told nothing about quoted strings.

The problem is, we have a question but no explanatory examples. Something like xxxx is the string I have, and
 yyyyy  is the string, I want to get.

Julius Kavay · Apr 11, 2022 go to post

To help you, help us to help you. This means, show us what you have you already done. So we can you point in the right direction, maybe explain, why your solution dosn't work, etc. It's nothing bad to ask for help. At some point in the time we all were new to Studio and ObjecScript.

Just asking for a solution is like going home from the school and letting the parents make the homework...

So what have you tryed?

Julius Kavay · Apr 5, 2022 go to post

For us all, the common denominator is Cache/IRIS and we have, as you know, Cache/IRIS for Win, Linux, AIX and MAC platforms. It's nice to know about existing external tools, but for some of us the COS solutions remains as the last resort, especially if those (external) tools do not exists for the OS, one works on (Just My2Cents).

Julius Kavay · Apr 4, 2022 go to post

First, as you alread wrote, changing the collation of an already existing installation is dengerious,
second, as far as I know, the database creation page (of ManagementPortal) offers you "Cache/IRIS-standard" and "Cache/IRIS-standard string" only. Nevertheless, changing to "standard string" only affects the collation and not the display, i.e. string subscripts will be displayed quoted but numeric subscripts are not quoted.

Julius Kavay · Mar 30, 2022 go to post

However, those legacy systems are already in operation, therefore they neither need python nor 3DES, at most, an upgrade to an current system. Hence, I don't understand your argumentation.

Julius Kavay · Mar 17, 2022 go to post

I'm quite shure, the above code won't work as expected, or with the words of Joseph Weizenbaum: “A computer will do what you tell it to do, but that may be much different from what you had in mind.”

The content of your myf variable is always 0 (the result of comparing nullstring with a filename), the size of tmpFile stream is also 0 (you never write into the stream).

Sometimes it's faster to write a "oneliner" to solve a simple problem then searching and downloading a solution from openexchange or from whereever... That's the beauty of the ObjectScript.

And if you think, the oneliner is worth to be reused, then make it to a method, add some small adjustments for a general usability...

The oneliner

s str="",tmp=##class(%File).TempFilename("txt") o tmp:"NWRU":0 i $t { u tmp zw ^||fruit s s=$zpos r:'$zseek(0) str#s c tmp:"D" }

The more general version

ClassMethod ToString(ref,max=32000)
{
    s tmp=##class(%File).TempFilename("txt") o tmp:"NWRU":0 q:'$t ""
    u tmp zw @ref s siz=$zpos r:'$zseek(0) str#$s(siz>max:max,1:siz) c tmp:"D" q str
}

Use it as

write ##(your.class).ToString($na(^||fruit))


Julius Kavay · Feb 8, 2022 go to post

Nice and easy...

That's like having an anteroom into bedroom and living room. There is always just one door open. If you want to go into bedroom, you have to brick the door of the living room and make a break through into the bedroom. The way back into living room is the same, just vice versa...

Julius Kavay · Feb 1, 2022 go to post

If you ask me, it should be the responsibility of the class compiler to check table names against reserved words and to quote them, if neccessary.
I think, you have closer connection to the development - what about an enhancement request?
Maybe a new property, say SqlTableNameQuoted.

Julius Kavay · Jan 31, 2022 go to post

First, disable the start of %ZSTART:

ManagementPortal-->SystemAdmin-->Configuration-->AdditionalSettings-->Startup:

here, set SystemStart to false.

Now, you can (Re)Start the system and check the %ZSTART routine.  <DIRECTORY> means, trying to access a nonexistent database directory.

After solving the problem, set SystemStart to true.

Julius Kavay · Jan 31, 2022 go to post

The simplest way is to create a classmethod, which returns the desired name:

Class DC.Evgenys.Data Extends %Persistent
{
/// which: 0=Fullname, 1=Schemaname, 2=Tablename
ClassMethod TableName(which = 0) [ CodeMode = objectgenerator ]
{
    set sch=%compiledclass.SqlSchemaName, tab=%compiledclass.SqlTableName
    do %code.WriteLine($c(9)_"quit $p("""_sch_"."_tab_","_sch_","_tab_""","","",which+1)")
    quit $$$OK
}
}

So you can do something like this:

for i=0:1:2 write ##class(DC.Evgenys.Data).TableName(i),!
DC_Evgenys.Data
DC_Evgenys
Data
Julius Kavay · Jan 28, 2022 go to post

You forgot to take into account the $system.SQL.* variants . They make much more fun, especially because you get time for a coffee break... devil

Julius Kavay · Jan 28, 2022 go to post
Class My.Class 
{
Property MyProperty As %String [ReadOnly];

Method %OnNew(init As %String) As %Status [ Private, ServerOnly = 1 ]
{
    set i%MyProperty = init
}
} 

And use it as

set obj = ##class(My.Class).%New("Some initial value")
write obj.MyProperty --> Some initial value
set obj.MyProperty --> <CANNOT SET THIS PROPERTY>
Julius Kavay · Jan 28, 2022 go to post

A possible work-around could be the class below. In short, you work with your json property as intended, merely before saving the object, you save the json-property into a stream and after opening an instance, you restore the json-property from the the stream - that's all. The drawback, no SQL over the json property...

Class DC.Dyn Extends %Persistent
{
Property json As %DynamicObject [ Transient ];
Property jstr As %GlobalCharacterStream [ Internal, Private ];

ClassMethod MyTest(kill = 0)
{
   if kill do ..%KillExtent(1,1)

   set obj=..%New()
   set obj.json.short="A short test text"
   set obj.json.maxstr=$tr($j("",$$$MaxStringLength)," ","X")
   do obj.json.%Set("hugedata",..stream(obj),"stream")

   write "Status : ",obj.%Save(),!
   set id=obj.%Id()
   write "ID : ",id,!
   kill (id)

   set obj=..%OpenId(id)
   write "short : ",obj.json.short,!
   write "maxstr : ",$e(obj.json.maxstr,1,20),"... Size: ",$length(obj.json.maxstr),!
   set stream=obj.json.%Get("hugedata",,"stream")
   write "hugedata: ",stream.Read(20),"... Size: ",stream.Size,!
}

ClassMethod stream(obj)
{
   set stream=##class(%Stream.TmpCharacter).%New()
   do stream.Write(obj.json.short)
   do stream.Write(obj.json.maxstr)
   do stream.Write(obj.json.maxstr)
   quit stream
}

Method %OnOpen() As %Status [ Private, ServerOnly = 1 ]
{
   if ..jstr {
      do ..jstr.Rewind()
      set ..json=##class(%DynamicAbstractObject).%FromJSON(..jstr)
   }
   Quit $$$OK
}

Method %OnAddToSaveSet(depth As %Integer = 3, insert As %Integer = 0, callcount As %Integer = 0) As %Status [ Private, ServerOnly = 1 ]
{
   do ..jstr.Clear(), ..json.%ToJSON(..jstr)
   Quit $$$OK
}
}

Some testing...

IDEV:USER>d ##class(DC.Dyn).MyTest(1)
Status  : 1
ID      : 1
short   : A short test text
maxstr  : XXXXXXXXXXXXXXXXXXXX... Size: 3641144
hugedata: A short test textXXX... Size: 7282305

If your code uses obj.%Reload() then %OnReload() and %OnOpen() should contain the same code.

Julius Kavay · Jan 27, 2022 go to post

Your solution is just perfect. And fast.

But yes, you can avoid string manipulations... This one, for example, uses math only, merely it's neither short nor looks elegant:

 set dt=$h write $zd(dt,8)*100+($p(dt,",",2)\3600)*100+($p(dt,",",2)#3600\60)*100+($p(dt,",",2)#60)

but gives the same result as your short and nice solution...

 set dt=$h write $zd(dt,8)*100+($p(dt,",",2)\3600)*100+($p(dt,",",2)#3600\60)*100+($p(dt,",",2)#60),!,$tr($zdt(dt,8)," :")

On the other hand, you can install new brakes on your car, as suggested by others... ;-))

Just compare those codes with yours:

set h=$h, t=$zh for i=1:1:1E6 { set x=$tr($system.SQL.TOCHAR($h,"YYYY^MM^DD^HH24^MI^SS"),"^") } write $zh-t,!

set h=$h, t=$zh for i=1:1:1E6 { set x=$tr($zdt(h,8)," :") } write $zh-t,!

The choice is yours...

Julius Kavay · Dec 20, 2021 go to post

A simple

write ##class(%SYS.Namespace).GetPackageDest(yourNsp, yourPackage)

should do the trick

The same goes for globals and routines

write ##class(%SYS.Namespace).GetGlobalDest(yourNsp, yourPackage)

write ##class(%SYS.Namespace).GetRoutineDest(yourNsp, yourPackage)

if yourNsp is not provided, the current Nsp will be used

Julius Kavay · Dec 14, 2021 go to post

Excuse me for my sassy answer, but I'm pretty sure, you' are asking the wrong question. Data can't be stored "case sensitive" (they are stored as they are) but stored data can be processed case sensitive or ignoring the cases, according to ones demand.

So it depends on how your Crystal Reports sees the data.

Julius Kavay · Dec 4, 2021 go to post

Just to put things in right perspektive, those "one letter commands" and "a lot of them in the same line" were neither tempting nor addictive, they were simply necessity!

At the time of the birth of MUMPS (the core of Cache/IRIS/etc.), more then 50 years ago in the second half of 1960es,  memory (which was a real core memory at the time) was rare and expensive and was measured in units of kilobytes! Just to contrast, today's server have the same amount of RAM, but in gigabytes, that's a factor of one million!

As a consequence of memory shortage and because MUMPS of that time was interpreted (i.e. you loaded the sourcecode into memory), one had to utilize each and every possibility to save memory. One of those possibilities were the ability of the language to short each command to one letter and to put as many commads as possible into one line (thereby saving line-ending bytes).

The tools (to save memory) of that (ancient) time were argumentless IFs and ELSES, short (variable-, global- and routine) names, commands with postcondition and sophisticated programming.

Last but not least, if one aims to "modernize" thos old applications, should be keept in mind, especially, if one is not so familiar with the old fashioned style and methods, there will be many unexpected pitfalls.

Sample1: on old printers, the line with "Total..." will be printed "bold-alike"

 write "last item",?15,$j($fn(val,",",2),10),!
 write ?15,"----------",! do  do  do
 . write $c(13),"Total",?15,$j($fn(sum,",",2),10)
 write !!!,"Due date for payment ....",!

Sample2: converting from:

 ; normal flow
 do
 . ; nested
 . ; commands
 ; normal flow

into:

 ; normal flow
 if 1 {
   ; nestd
   ; commands
 }
 ; normal flow

will be in most cases OK, except, if the nested part uses the current value of $STACK:
this is now one less then in case of argumentless DO!

Julius Kavay · Nov 30, 2021 go to post

If you look for those informations from Cache/IRIS then a good starting point is:

do $system.CPU.Dump()

Advantage: you get the same (output) format on Linux and Windows

Julius Kavay · Nov 17, 2021 go to post

According to the above task, "...a string of comma-separated integers ...", inputs like

"3, 5, 7, 8, 10, 12, 14, 16" and / or
"3, 5, 7, 7, 7, 7, -8, -6, -4, -21,-21,-21, 77,77,77,77"

are also valid? Those are all integers too.

Julius Kavay · Nov 13, 2021 go to post

The reason is, the database encryption is not activated - see the last line in your screenshot.

Go to MangementPortal, SystemAdministration --> Encryption. There you can create the encryption keys and activate the encryption.

Julius Kavay · Nov 8, 2021 go to post

I know exactly nothing about HealthShare... so I can just suggest two ways to remove the unwanted characters from a string:

use $zstrip()

set inpData="some wild sequence of characters"
set cleanData = $zstrip(inpData, "*C") // this removes all control characters (0x00-0x1f, 0x7f-0x9f)

the other way is to define a set of valid characters and remove all others

set inpData="some wild sequence of characters"
set validChars = "012...89ABC..Zabc..z..."
set badChars = $translate(inpData, validChars) // remove from input all valid chars, leftover are bad chars
set cleanData = $translate(inpData, badChars) // remove all the bad chars

or just the short version

set cleanData = $translate(inpData, $translate(inpData, validChars))