Laura Cavanaugh · Oct 17, 2019 go to post

I use ByRef a lot, but mostly to indicate that an array or object will be changed in the method. 

In fact, until now, I thought it was necessary to use ByRef in order to "continue the changes to the object back to the calling code".  However, after playing around with some code, including your example, I see that it's not necessary at all, which makes me think that it's useful as an "annotation", so that the programmer knows that the object WILL BE changed. 

Now, I feel that the real "pass by reference" is the dot in front of the variable, and the ByRef is merely an indicator that this variable could be changed when returned.

Is this true?  I'm not really sure what "passing a reference by reference" would produce. I came upon this article because I want several methods in a row to update a log file, which I sometimes add to the method signature as ByRef, and sometimes I don't, and I wanted to know why it still worked (i.e. my log file is created, and is updated in the calling method).

Here is your original example, but without the ByRef:

ClassMethod Test(UseByRef As %Boolean = {$$$YES})
{
    Set Obj = {}
    Set Obj.Property = 1
    Write "At the begining ",Obj.Property,!
    Do ..RefMethod(Obj)
    Write "After Value pass ",Obj.Property,!
    Do ..RefMethod(.Obj)  // pass by reference because I want the object to change
    Write "After ByRef pass ",Obj.Property,!
}

/// notice there's no ByRef in the method signature

ClassMethod RefMethod(Obj)
{
    Set Obj = {}
    Set Obj.Property = 500
}

USER>Do ##class(Utils.ObjByRef).Test()


At the begining 1
After Value pass 1
After ByRef pass 500

Laura Cavanaugh · Sep 5, 2019 go to post

Michael,

Thanks for this tip.  I'm using this utility to programatically export part of a very large global to a file, for archiving data.  I've decided that using the %Global.Export() method is the best way to go, since I have to do this in code without user input from a terminal. I considered ^%GOGEN and $system.OBJ.ExportToStream as well (comments on this?)

Previously I was merging the global part to a temp global in another namespace (the namespace would then be deleted), and then deleting the subscript from the main global.  Obviously this could temporarily greatly increase the amount of space this global uses; hence the switch to something better.

The global I'm archiving is very large, so I'd like to ensure that this utility doesn't copy the global to a temp global, a PPG, or any kind of format that would take up disk space (aside form the space the file is using).  

Do you know if this utility works directly from the global to the file, or does it use any temp globals along the way?

Thanks,

Laura

Laura Cavanaugh · Jul 19, 2019 go to post

Thank you.  Does this count toward the $storage value? or is the $storage affected only by variables (and not PPGs)?

Laura Cavanaugh · May 29, 2019 go to post

This is one of my favorite posts - and my favorite code snippet that will log an error and return a status:

set ok=$$$OK
try {
}
catch (ex) {
    do ex.Log()
    set ok=ex.AsStatus()
}
quit ok
 

Laura Cavanaugh · Apr 4, 2019 go to post

Understood.  I've gone through this configuration before, and set up username/password, and other security.  I don't know why this appears to have been reset for this instance.  But the SM_FORMS setting worked - thanks.

Laura Cavanaugh · Apr 4, 2019 go to post

Wow.  That very well could be the cause - SM_FORMS is enabled on another server (a few other differences, but none that seem pertinent).  Is this something I can change on a production server without disrupting users?  They should be going through the IIS ... 

Laura Cavanaugh · Feb 8, 2019 go to post

Thank you all, for the comments.  It sounds like there's not too much of a problem keeping the INT code.  The space needed would indeed be smal compared to the space for the datasets.  It doesn't increase privacy or security.  Rather, it sounds more like the INT code is provided for our benefit, for debugging purposes, and is normally not saved on live systems almost out of tradition (and because who is debugging on live, eh? Well, I am, at times).

Thanks,

Laura

Laura Cavanaugh · Oct 9, 2018 go to post

I think the frozen plans from our fairly recent upgrade was indeed the problem, especially taking into account what Wolf said about adding new properties to a table.  I had done that recently, which makes the "SELECT-list and INTO-list mismatch" error more plausible. We upgraded to 2017.2.2.

I coudln't really test unfreezing the plan (which was in a Frozen/Upgrade status) because I had already changed the code to use a new object, %SQL.Statement.  And, this also makes sense, since using a new object probably created a new plan ... ?

We are not that sophisticated -- we don't have a DBA -- I'd prefer to let InterSystems code optimize the queries. We never optimize and freeze plans.  We just add Indexes to make queries faster.  I'll probably leave the queries frozen until we come across this problem again.  Unless I hear that it's OK to simply unfreeze them all.  What's the downside to that?

Thanks for the help,

Laura

Laura Cavanaugh · Oct 3, 2018 go to post

Update: using the %SQL.Statement class did help, and I had to change only a few lines of code (the Execute, Next, and Data methods).

Still curious as to why this was happening on our DEV server but not other servers, where the other servers still have the original code using %ResultSet class.  And why now -- we've been using this code for years, and upgraded to 2017 in July.

Thanks,

Laura

Laura Cavanaugh · Jul 12, 2018 go to post

I have been killing index globals and rebuilding indices (a lot), because I was also changing how I added the Tag.  

 /// Add Tag,Tag.Tag as Key, to claim array of Tags
Method AddTag(tag As Data.Tag) As %Status
{
set ok=$$$OK
try {
..TagsArray.SetAt(tag,tag.Tag)
do ..Tags.Insert(tag)
}
catch (ex) {
set ok=ex.AsStatus() 
}
quit ok
}

I had some version of code yesterday where my last query worked, and used the index.  I imagine that we'll be looking for tags based on the "Tag" property (i.e. 'LLC' or 'TWO') rather than the ID, but we could just use the ID.

Laura Cavanaugh · May 24, 2018 go to post

I can do that.  For future queries, I'm getting these 4 errors in the Audit Database for each error:

Description: Attempt to access a protected resource
Reoutine: EMSUpdatePassword+2^%SYS.SECURITY |"^^c:\intersystems\ensembledev\mgr\"|
Namespace: {namespace}
Event Data: <PROTECT>EMSUpdatePassword+2^%SYS.SECURITY *c:\intersystems\ensembledev\mgr\

Description: Attempt to access a protected database
Routine: Store+5^%ETN |"^^c:\intersystems\ensembledev\mgr\cachelib\"|
Namespace: {namespace}
Event Data: <PROTECT>Store+5^%ETN

Description: Attempt to access a protected database
Routine: Value^%STACK |"^^c:\intersystems\ensembledev\mgr\cachelib\"|
Namespace: {namespace}
Event Data: <PROTECT>Value^%STACK

Description: Attempt to access a protected resource
Routine: ^%SYS.SECURITY |"^^c:\intersystems\ensembledev\mgr\"|
Namespace: {namespace}
Event Data: <PROTECT>^%SYS.SECURITY *$TEXT(EMSUpdatePassword+2^%SYS.SECURITY)

I'll ask IS.

Thanks,

Laura

Laura Cavanaugh · May 23, 2018 go to post

We've been using the $SYSTEM.Security.ChangePassword since 3/2017, apparently, and only recently have I noticed that it's logging a <PROTECT> error, and yet still changes the user's password (only recently have users been required to change passwords):

<PROTECT>EMSUpdatePassword+2^%SYS.SECURITY *c:\intersystems\ensembledev\mgr\"  at  8:27 am.   $I=|TNT|192.168.32.100:62074|11696   ($X=0  $Y=26)
     $J=11696  $ZA=0   $ZB=$c(13)   $ZS=262144 ($S=268247904)
     source   code not available

I'm using this line of code: 

set bChanged = $system.Security.ChangePassword($username,newPass,oldPass,.ok)

bChanged is not in the error trap; ok =1; the user's password is generally changed, as far as I can tell, because we don't get users asking why they cannot log in.  I can recreate this from the terminal using a username without much acess (no %SYS access).

I'm sure there's a security thing going on here.  Why would this error get logged?  It makes me nervous, as we're adding more users who will need to change their passwords often.

Any ideas?

I can't compile or step through the code - it's hidden.

Thanks,

Laura

Laura Cavanaugh · Mar 21, 2018 go to post

A task, of course... I'll have to go through the list of users and check their LastLoginTime/CreateTime, Enabled, etc.  For future users who are looking for this, I'll use the SQL procedure Security.Users_Detail().

I did not know about the Security.Scan, but I'll take a look, and see what else I should tack on to it.  Good idea to run our custom security task after the SecurityScan.

Thanks! Getting there.  And perhaps InterSystems will add this concept in the 2017 (2018?) release.

Laura

Laura Cavanaugh · Feb 23, 2018 go to post

Ha!  That was it.  Thanks.  Wish we had entered all our usernames in one case, but alas.  

Thanks for the help - I appreciate all the answers.  Now, to go through our security and update all the appropriate roles.... 

Laura Cavanaugh · Feb 23, 2018 go to post

I am not sure.  I'll check now.

Edited to: I wish I could paste an image, but this may be the problem.  I granted my laura_test_dev user

1. direct permission to execute

2. the %Library.File_FileSet SQL Procedure,

3. in the PMG namespace.   

Logged out of the terminal, logged back in as that user, and got this:

 Instance: ENSEMBLEDEV
 
Username: laura_test_DEV
Password: *********
PMG>w $system.SQL.CheckPriv("laura_test_dev","9,%Library.File_FileSet","e","PMG")
0
 

I agree; this seems like it should work, and for some reason that I haven't yet figured out, it is not working.  At this point, the folder structure and who created the folders has no bearing.  We're on version 2016.2.2.

MISSED A CRITICAL STEP.  I then ran the query from the terminal, after having given that user the direct permission, and the query worked.  Now I'm confused as to why I got a 0 on the priv check, but the query worked.  But, it worked.  So maybe I won't mess with it.

Laura Cavanaugh · Feb 23, 2018 go to post

We do have auditing turned on, for all kinds of events.  I was looking at that, and didn't see much that I could use.   Scratch that -- we happen to have %System/%DirectMode/DirectMode events turned on, and I could only see the fact that user Laura_test_DEV ran that command line in the terminal, but the Details page doesn't show failure or any more info.

Didn't think to debug the %PRepare method.  I can probably see what line of code is actually failing.  The other "low-level" (as I think of it) call to FileSetFunc works at the terminal prompt, but I'm not sure if it's working from the application.  I can only hope it has something to do with the test folders.

Thanks for the help.  I'll update with my final solution.

Laura Cavanaugh · Feb 23, 2018 go to post

From the terminal prompt, logged in as my application user, the ##class(%File).FileSetFunc(directory) appears to be working.  Oddly, giving the user execute permissions like John suggested didn't work.  I wish it had because my code is all set up for the class query.

I had seen the FileSestFunc in other posts... I don't know why this works differently.  Can I use a FileMask, however?  

set rs=##class(%File).FileSetFunc("c:\","*.pdf;*.csv")

Oh, and we're on Windows, and the instance is running as a domain user with lots of privileges, but if the application user copies and deletes a file, who is actually doing it?  The instance's user, or the application user?

Too early for me.

Also, I did try the call with a FileMask, and it does work.  Is it the same as the FileSet query?  I can't find it in the code... must be a lower-level call to that query or something.  

Laura Cavanaugh · Nov 14, 2017 go to post

John, thanks for the info.  It was indeed a windows security problem, related to the new Cache_Instance_instancename group.  I had created 3 namespaces before we ran the cinstall (windows-level caché command to set up the windows security needed), and then because they were located outside of the cache tree, lost access to them.

Note: this was a very special case where I installed the new instance to run as the local system, and then needed to run the cinstall command to change it to use another windows domain user.  We also ran into a few windows security issues after the upgrade that we're still working out.

 

We rectified it by added the appropriate security to the e:\ drive where the dataset are located.

 

Also note: I created a test namespace AFTER we ran the command to set up the windows security (i.e. today, I created it), and the caché service user DOES automatically get access to the folder with the new dataset.

 

Thanks for all the speedy help!

Laura

Laura Cavanaugh · Nov 14, 2017 go to post

Great idea! Yes indeed! this is what it says:

 DKMOUNT: Mounted SFN 5 DB 'e:\datasets\demo\' as Read Only DB. File or filesystem allows read-only access. 

Looks like it's related to our new windows security setup, which, by the way, was implemented as part of the 2016 upgrade.  The 2016 version wants a windows group called Cache_Instance_instancename and the username that runs the instance is moved to this group.  We had to run something to change this windows security after we installed this instance as 2016.  Origainlly, the instance was installed to run as SYSTEM.

I wonder - should I uninstall the instance and reinstall so that it's run as the user?  It's still early enough in the game that I could do that.  Would that automatically give my user access to the e:\datasets\ folder since I'm creating namespaces in the Installer manifest?  not sure.

Anyway, after I've figured out the windows security for this folder, I'll let you know if that helps.

Thanks! 

Laura Cavanaugh · Nov 14, 2017 go to post

Hi Danny,

That seemed promising, but when I stop Caché, the cache.lck file is removed, and appears again when I restart the instance. 

Yes, the root database name is not the same as my caché system.  Caché is installed in the typical c:\intersystems\instance while these namespaces' databases are on another drive - e:\datasets.  Also, we changed the underlying Windows security recently for our 2016 upgrade, so I'll have to make sure the instance's service user has access to the e:\ drive.

This is what appears in the cache.lck file:

c:\intersystems\rhs01p\mgr\

SERVER01

where rhs01p is the instance name, and SERVER01 is the server name.

I'll check the Windows security and let you know.

Thanks,

Laura

Laura Cavanaugh · Nov 7, 2017 go to post

Hello John,

I'm trying to get more information about a similar $ZF issue, and running the caché instance as a Windows user rather than Local SYSTEM.  I have this link from IS to help me out: 

http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCRNA_C157184

 

But I was hoping to get a little bit more info from the link you sent out; unfortunately the link gives me a "missing" error.  Do you think you can find that link again?

 

This is my issue: after we upgraded from 2014 to 2016, the ability to use call out (such as w $zf(-1,"dir *.*") ) is gone.  IS recommended using the cinstall command, as noted above, but it's not working.  I'm asking IS about it now... We run our instances under a particular user, not as local system.

I can update this thread with the solution.

Thanks,

Laura Cavanaugh

Laura Cavanaugh · Oct 12, 2017 go to post

Hi Eduard,

Interesting hack, and a good point.  There's enough going back and forth between namespaces, importing new code, and running new methods in the newly created namespace already, so I'd prefer to keep my manifest simple.  If I find that it needs to be done in, say, 5 places, I'll just say it needs to be the one value ("ABC") and I can create a copy of the installer if it needs to be a new value ("XYZ").  If it needs to be a new value, then we're probably moving toward replacing the old value anyway.

 

Thanks.

Laura Cavanaugh · Sep 8, 2017 go to post

Yan, yes, this looks like it's working.  The OnCreateResultSet method is called, but not the OnExecuteResultSet.  Thanks!

Laura

Laura Cavanaugh · Aug 17, 2017 go to post

Hi Timothy,

Yes, indeed, thanks.  I already have a SessionEvents class set up for all my web applications involved, so I stuck in this method:

ClassMethod OnLogin() As %Status
{
if ^ZPMGSYSTEM("%DOWNFLAG")=1 quit $$$ERROR($$$GeneralError,"Logins are currently disabled")
quit 1
}
 

This caused an actual login that got around our flag (via special testing, in this case) to get a response of 

Not Found

The requested URL /Works/PMG.Works.Home.cls was not found on this server.

Is that the expected behavior?

So, I would say this works.  Unfortunately, it also removes my backdoor -- it keeps out everyone!  I guess I could add a little backdoor into this method as well; a screen door, if you will, on my back door.

Laura Cavanaugh · Aug 11, 2017 go to post

I did not know that - but I tried taking it out, but my test global is still populated with method calls to OnCreateResultSet and OnExecuteResultSet methods.  The table itself if hidden at first.  In fact, there are multiple tablesPanes, and they are all getting called upon page load, even though the tablePane group is hidden.  

I'm going to play around with pInfo.QueryExecuted; and there's a runflag set up, which I can see why it was set up now.

THanks.

Laura Cavanaugh · Aug 2, 2017 go to post

I often forget to mention that we are on 2014.  Thanks - at least I can tell him we can't do it but maybe in a future release we can change the IS logo.

Thanks,

Laura

Laura Cavanaugh · Aug 2, 2017 go to post

I can't believe how much I look forward to these discussions.  Unfortunately, there is no EnsembleLogo* anywhere in the InterSystems directory.  

It almost looks like it's simple text, made to look like a logo using CSS. This is from the page source:

 

<div class="portalLogoBox">
  <div class="portalLogo" title="Powered by Zen">Ensemble</div>
  <div class="portalLogoSub">by InterSystems</div>

 

The class portalLogoBox must do all that CSS/html stuff to make it look cool.  I was wondering if I can change the text from Ensemble to something else.

 If the user is in the DeepSee Analyzer, it will say DeepSee by InterSystems instead, but with similar CSS modifications.

I figured out why  he wants to do this; we have a few "portal" users who have accss to all of the clients' namespaces.  For a demo, they will go into the DeepSee UserPortal, then exit to the management portal to switch namespaces, then go back in to the DeepSee user portal.  THe DeepSee user portal has settings where you can change the logo that is displayed (what are those classes?  I need to be able to change them programmatically rather than manually 50 times!) but when the portal users go back to the management portal, our company logo is lost; instead the lovely Ensemble by InterSystems (Powered by Zen) is there.  I personally think IS should get the credit, but my boss is wondering if we can change it for the purposes of these demos.

 

If not, that's OK; but now I'm simply curious.

 

Thanks!

Laura

Laura Cavanaugh · Jul 20, 2017 go to post

Wow, that works in 2014 too!  So, there must be something with my $lb parameter, you're right.  

Note what happens here, without the ... .  What is that?  Can't find it in the documentation.  Nevermind, I found it: http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY…

quit $classmethod($this, "Sum", .args)

ClassMethod Sum(n... As %Integer)

zw n
n=1
n(1)=3
n(1,1)=10
n(1,2)=20
n(1,3)=30

But... does it work for a SQL query?  It's fine in COS, but what about a %ResultSet.Execute() call?  Should I change it to %SQL.Statement?