go to post Laura Cavanaugh · Jul 18, 2017 No, it's just how I'm copying code into here... Here is what I am using:^llctemp("query")="SELECT * FROM MyTable WHERE ((DateTime >= '2017-07-11 00:00:00') AND (DateTime <= '2017-07-18 23:59:59')) AND (Claim->Status->Name IN ('Paid')) AND (Claim->ClaimNumber = ANY (Select Claim->ClaimNumber from MyTable where Claim->ClaimNumber %INLIST ? SIZE ((10)) )) " "returnParams")=1^llctemp("returnParams",1)=$lb("2902700","2869840","2870820","") That's my test data. Then I say: Set status = tRS.Execute(filterParams...) // < -- look, I need the ... !! Turns out I LITERALLY need the ... ( ! )Now I'm not getting the <LIST> but I'm also not getting data! Sigh. I'll get it. I am rushing a little, so that's messing me up. I think with all this, I can get it to work at some point. Thanks!!
go to post Laura Cavanaugh · Jul 18, 2017 No, I am using %INLIST -- it's all the other where clauses that are using IN, with concatenation. I had read that %INLIST would use the same cached query, or something, so decided %INLIST was better, then ran into this problem where I now have to pass in an Execute parameter, whereas all of the other params are basically hard-coded. Here's a copy of my query that was built:SELECT * FROM MyTable WHERE ((DateTime >= '2017-07-11 00:00:00') AND (DateTime <= '2017-07-18 23:59:59')) AND (Claim->Status->Name IN ('Paid'))AND (Claim->ClaimNumber = ANY (Select Claim->ClaimNumber from MyTable where Claim->ClaimNumber %INLIST ? SIZE ((10)) )) The last line is mine. Shoot. It was working when I passed in a $lb like this: set filter = $listfromstring(filterClaims) //build my $lb() for the Execute parameterset returnParams = $lb(filter) //$lb($lb(1,2,3), hypothetical param2, ... ,paramN)set param1 = $lg(returnParams,1) //param1 = $lb(1,2,3)// ... set paramN = $lg(filterParams,n) ...Set status = tRS.Execute(param1) but now, with the returnParams as an arity (that's cool, btw), I'm getting a <LIST>. If necessary, I'll go back to the forced "param1" thing, because this is an urgent fix. I can play around with it later.
go to post Laura Cavanaugh · Jul 18, 2017 Yes, exactly. We are building the sql statement line by line; the where clauses are built based on user input, and the whole mess is concatenated with actual values. hmm. But essentially, it looks like the params array is what I needed. Except that I'm getting a <LIST> error, so I have to go back and look at that. I'm on 2014.1.3. Thanks!
go to post Laura Cavanaugh · Jul 18, 2017 Oh no, good to know about concatening values instead of using ? Execute params. I should go rewrite the entire query! It has so many optional parameters though, so I'll go look at the Rubens/Timothy solution. Thanks. So this is not a good way to build the where clause:" Set where(16)=InstancePrefix_"PayerName IN ("_valuelist_")"" ?
go to post Laura Cavanaugh · Jul 18, 2017 I think it's a bit safer anyway to know exactly how many parameters to expect (avoid a sql injection attack?); I can see how long the one statement with a known number of parameters takes compared to other statements. So far I have just the one unknown parameter, and all the rest are built into the sql. Thanks.Oh -- the parameter is a $lb(); the sql is using %INLIST, which, in the example in the documentation, seems to require a parameter passed in the %Execute() rather than built into a value in the sql statement. The user might or might not search on this field. It's more like:select * from person where ID %INLIST ?I was thinking that since I need to pass this in to the Execute, I might as well set up a structure in case we add more parameters to the statement in the future; but perhaps it's better to just pass in a known number.Thanks.
go to post Laura Cavanaugh · Jun 15, 2017 Yes, I needed the SqlComputeOnChange = property; now it's getting updated for every insert/update when the {property} changes, which is great. The only problem is, my object is not limited to one row. It's an object with dynamic properties, where one object is several rows, and one row is the Category and Value of one property. This is fine when I insert or update ALL the rows for one object, but not when I update just one row. I can't think of a good way to force update on %READERLIST for other rows, based on a WHERE clause, maybe.ROWLEVELSECURITY = 1;///Updated for each row when the property 'Value' changes Property %READERLIST As %String [ SqlComputeCode = {set {*} = ##class(Users).%SecurityPolicy()}, SqlComputed, SqlComputeOnChange = Value ];Here's an example of my data:ID %READERLIST Category Value Username1 DEV Color Blue Laura2 DEV Number 555 Laura3 QA Color Pink Jane4 QA Number 87 Jane I'll be mulling this over for a while, but would love any other ideas.Thanks,Laura
go to post Laura Cavanaugh · Jun 15, 2017 I can say first hand that John is very patient and thorough. Good move!
go to post Laura Cavanaugh · Jun 13, 2017 Huh. I have been unable to have my class update %READERLIST and the %RLI index when I update a row. It's set when I create/save an object, but it's not updated when I update the object. Can I show you some simple test classes?My %READERLIST is based on a role name. From OVERRIDEing the Parameter ROWLEVELSECURITY:"/// ROWLEVELSECURITY = 1 | <property> means that row level security is active and the list/// of users/roles for a given instance/row is contained in a generated property. If/// the value of this parameter is a valid property name then that property will be/// used as the reader list and only generated if not already defined.ROWLEVELSECURITY = 1;"?
go to post Laura Cavanaugh · Jun 13, 2017 Is is possible to change the %RLI index when a row is updated? Or, change the %READERLIST value for the row?
go to post Laura Cavanaugh · May 23, 2017 That's it! Thank you! You might have been thinking "it's so obvious", but I wasn't thinking of adding the attributes via html, just for that cell. I was only thinking of "write", or using the column object to set its cellTitle property, which is not feasible since I can't get the column obejct. But substituting html works great. Thanks!I was able to change the style just for cells whose columns are greater than pSeed (nice touch there), and I removed the showValueInToolTip for the rest of the cells. I'm sure that would have been noticed at some point.Laura
go to post Laura Cavanaugh · May 12, 2017 And by the way I like the <pre> tag - nice touch. Can we call ..EscapeHTML or does that require a license/connection?
go to post Laura Cavanaugh · May 12, 2017 I could try that... but this is for the user-friendly page, and I don't want that info on it. I was hoping to log the info in the error trap.I just tested the error trap, and found that you can, actually, load the details of an object, while still in the error traap ^%ER. I had no idea:Error: 7 7. <UNDEFINED> --routine name -- *undef : CSP Error at 9:41 am. $I=|TCP|1972|16772 ($X=327 $Y=14056) $J=16772 $ZA=24576 $ZB=$c(0) $ZS=262144 ($S=267019816) set x=undef //LLC testing Variable: %request (copying data ... done)(base stack level = 20) %request = <OBJECT REFERENCE>[1@%CSP.Request]Show object details? yes+----------------- general information ---------------| oref value: 1| class name: %CSP.Request| reference count: 6... etcSo, as long as the error trap has that info available, I'm pretty good. Does that change in 2016? Why is the %CSP.ErrorLog page in 2016 so careful to save off the request, session, and response objects inthe error log?Thanks,Laura
go to post Laura Cavanaugh · Mar 21, 2017 Can this be used in the System/Security Management/System-side Security Paramters "password pattern" at all? I'm trying to find a way to match a user's password to something much more restrictive than "8 to 32 alpha, upper, lower, numeric, OR punctuation". I'd like to require at least one of a few kinds of characters (1 upper, 1 punctuation). I have a nice regex for this, but I'm not sure if I can use a regex, or this cool datatype, in the above mentioned System setting. Any recommendations?
go to post Laura Cavanaugh · Mar 17, 2017 John, thanks for the response. I might ask this explicitly in the DC later, but I'll have to look at my notes before I do, as I'm sure I'll get some flak. Just for informational purposes: we were instructed to restrict our users to a single tab in our web application. I know this is not how a web application is supposed to work (according to many users on google groups writing about this sort of thing), but the directive came from above. I wrote simple logic to check if a user has a session already, and if so, he can't open a second tab. Sometimes, due to a bug, or timeouts on queries, the logic thinks the user has a second session when he does not. At that point the user can't even log into the application. It's at this point that he'll have to call IT, who will have to call a developer, who can then kill his sessions manually from the management portal. I was trying to give the users a way to "reset" or "clear" their own sessions (logging in first to a separate page perhaps) so that they can use the application again. When I first began to look at this, I realized that most of this has to be done in the %SYS namespace; hence the problem, and its relavance to this question about changing their own password. However, it hasn't been an issue (yet), so it's on my back burner. When it becomes an issue I'm sure I'll be back asing about it. As always, thanks for the help.Laura
go to post Laura Cavanaugh · Mar 17, 2017 Since we're on the subject, do you have a magic way of letting users kill their own sessions (in case the application is not letting them log in) in the CSP Sessions global? I'd love to give them a "Log out of all sessions" button.Thanks,Laura
go to post Laura Cavanaugh · Mar 16, 2017 Oh, hello John! I was not aware of it, AND it seems to work for an average user without requiring access to the %SYS namespace. That is great! Thanks so much. That was easy!Laura
go to post Laura Cavanaugh · Feb 15, 2017 Well, that helps. Thanks. I can't forsee any reason to make it more complicated, unless there is some huge benefit that I'm overlooking? Ah, I was thinking of changing the emails to a list of users, and getting their emails from the user table, so maybe that's a future benefit.I extended the %Net.MailMessage for one object, and had such a pain of a time stuffing the To prooperty and retrieving it again (it's a list of %String). This time I was thinking a simple %String would be nice, as long as I can use it with SQL, and stuff.Thanks,Laura
go to post Laura Cavanaugh · Feb 9, 2017 Hi All, Thanks for the help. I learned a lot, and looked at our actual instances with a more critical eye. I'll be recommending some changes on them. I had installed the unlicensed version of 2016 on my computer just for fun, so there were no license issues (but that's something to keep in mind for our other instances). I had installed 2016 with minimal security, then tried to increase the security to match our development instance. That was actually successful; it was the disabling of all the other users that messed it up.Thanks,Laura
go to post Laura Cavanaugh · Feb 8, 2017 Ah, thank you. While playing around with ^SECURITY, I had enabled all users EXCEPT UnknownUser (of course), and after checking out the auditing area of ^SECURITY (thanks for that tip), I saw that it was indeed UnknownUser that is trying to log into the management portal. I did not know about that step, that the CSP gateway has to log in first to serve up a page. What user is normally used for this? Thanks,Laura