go to post Rubens Silva · Jul 20, 2017 Can you post the code that's generating this error?I noticed that the error is coming from a method called File inside your class User.zKQRest.
go to post Rubens Silva · Jul 20, 2017 Yes, you must use ... to inform the method that you're are using the format compatible with variable arity.When using . instead, the compiler assumes it should index from the subscript that you provided. It's not a bug, but a unexpected behavior caused by your input as the compiler modifies the way it treats the parameter if you put ... on the declaration.So yep, you should always use ... for passing and receiving parameters with variable arity, unless you know exactly which parameters and their passing index, you can express it using a more "literal" format: as you have noticed, right from start I defined a param variable to hold all my values, this is really useful for populating the arity from a loop.But what if already know what to pass? You could also call the method as: $classmethod($this, "Sum", 1,2,3,4,5,6) // up to 255 parameters.Also, yes, it works for %ResultSet.Execute, by the way here is the method signature: Method Execute(args...) As %Status [ PublicList = (qHandle, args) ]
go to post Rubens Silva · Jul 20, 2017 Are you sure? ClassMethod TestAritySum(){ set args = 3 set args(1) = 10 set args(2) = 20 set args(3) = 30 quit $classmethod($this, "Sum", args...)}ClassMethod Sum(n... As %Integer){ set sum = 0 for i=1:1:n { set sum = sum + n(i) } quit sum}
go to post Rubens Silva · Jul 19, 2017 Not exactly, this following syntax is weird, but works:try typing instance."my_property", you can even create properties and methods with "".Extremely useful if you are working with snake_case.Here's the proof:USER>zn "samples" SAMPLES>set r = ##class(%SQL.Statement).%ExecDirect(,"SELECT TOP 1 ID AS ""my_id"" FROM SAMPLE.PERSON") SAMPLES>w r.%Next()1SAMPLES>w r."my_id"1
go to post Rubens Silva · Jul 18, 2017 Now I can assume that you merged your "returnParams" subscript into a variable called filterParams. Doesn't look wrong for me, just wondering about that SIZE. Try removing it and see if it affects your results.Also check if you modified the display mode. Along with that status variable to see if some error happened.P.S.: It's becoming hard to type here :x
go to post Rubens Silva · Jul 18, 2017 Uhmm... what could be causing this issue is that embedded list. Your %INLIST reads one list, but the result is another list.Or maybe I'm still missing some piece of code to understand better.Anyway according to the documentation: SET states=$LISTBUILD("VT","NH","ME") SET myquery = "SELECT Name,Home_State FROM Sample.Person WHERE Home_State %INLIST ?" SET tStatement = ##class(%SQL.Statement).%New() SET qStatus = tStatement.%Prepare(myquery) IF qStatus'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT} SET rset = tStatement.%Execute(states) I assume it should be:set params=N set params(1)=$lb(1,2,3) set params(2)=hypothetical param2 ... set params(N)=paramNI can see that your returnParams is a list instead of the format that allows variable arity. But like I said, I might be missing some piece of code to understand better.However, since my suggestion is not a surefire tip and you're in a hurry I think you should opt-in for the fatest working solution and investigate the error cause when you have some time, just like you said.
go to post Rubens Silva · Jul 18, 2017 Ahh, that's because you're using IN instead of %INLIST. IN doesn't expect a list, so throws an exception.
go to post Rubens Silva · Jul 18, 2017 I'll assume that your 'where' variable is already your SQL query. set params=1set params(1)=$lb(,1,2,3,4,5,6,7)"Set where(16)=InstancePrefix_"PayerName IN (?)"" do statement.%Prepare(.where)set rows = s.%Execute(params...) Remember that you still can concatenate SQL parts, because they aren't editable by the end-user, I just don't recommend concatenating values.
go to post Rubens Silva · Jul 18, 2017 If you can't release memory by ajusting your own source code, then what you need is to do is expand it's size by using $zstorage or the configuration.Also, is that a recursive call?
go to post Rubens Silva · Jul 18, 2017 Makes sense, I think it's because OUTER JOIN lifts equivalence constraints when joining.
go to post Rubens Silva · Jul 18, 2017 If you mean testing using the SSL configuration in the Portal, when you click Test, it asks you for your server name and port. This follows the same pattern as %Net.HttpRequest, which means: don't provide the protocol http:// or https://, only your address: fantasyfootballnerd.comFor a use case, we have service hosted on AWS using HTTPS and it connects succesfully, but only if I strip the protocol from the address. Here's a feedback from our service when using the Test button (it's portuguese though ...)Conexão SSL bem sucedida <- Indicates success on connecting.Protocolo: TLSv1/SSLv3Ciphersuite:ECDHE-RSA-AES128-GCM-SHA256Peer: <- No peer certification defined, so it's empty...Requisição: GET / HTTP/1.0 <- Request done using HTTP 1.0 protocol Resposta: <- Response is an empty body.
go to post Rubens Silva · Jul 18, 2017 HTTP Status 301 means Moved Permanently, which happens when you request a resource and the server redirects you to another (usually equivalent), since you said it's asking to use HTTPS, I suppose you haven't configured a SSL configuration on the Caché side.Create a new SSL Configuration mark Enabled, select Type to Client, Peer certificate verification level to None, and Protocols to TLS.Or simply fill the Name and Description, anything else is default... click Test to see if it works and Save it.Now after instantiating the %Net.HttpRequest, you pass your instance.SSLConfiguration = "Your SSL Configuration Name" and instance.Https = 1.This is the minimal you usually need to do to have a working SSL aware client.
go to post Rubens Silva · Jul 18, 2017 %Execute and Execute as well support a variable arity of arguments. This can be reproduced as:set args=2set args(1)="first_value"set args(2)="second_value" do statement.%Execute(args...)Notice that the variable itself contains the total of arguments while each subscript is sequential, this defines their position as arguments.Methods that support a variable arity imply on using three rules:1 - Argument variable must contain the arity size.2 - Argument index starts from 1.3 - Index must be sequential.Method with a variable arity can also pass through their arguments to the next method like this:ClassMethod First(params... As %String){ do ..Second(params...)}
go to post Rubens Silva · Jul 18, 2017 I didn't know that Caché allowed to use JOINs without specifying FROM. That's really useful to know indeed.
go to post Rubens Silva · Jul 18, 2017 Actually, the amount of placeholders inside the SQL is what dictates how many parameters should be read. SQL engines or ORMs that support queries with placeholders usually escape the input value already to prevent attacks like SQL injection. And that is why you should never use _concatenation_ with SQL strings. Because the engine cannot sanitize what is not an explicit value.As you said the parameter is a %List instead of a multidimensional you don't need to do anything regarding the input, just pass it and read it using %INLIST.And surely, if you can provide a fixed number of parameters, this should always be your first option.
go to post Rubens Silva · Jul 18, 2017 The main downside of using "?" instead of :param is that if you have multiple ocurrences from the same column you have to repeat the parameter. That's why I would discard using dynamic queries if the SQL already covers all conditions to display the results and create it as class query (possibly your first example).
go to post Rubens Silva · Jul 17, 2017 You can use $query as Fabian suggested along with indirection this will allow you to traverse the global without the need of creating a recursive call.You can use $qlength along with $query to discover how deep (how many subscripts) you are in the global.You can use $qsubscript along with an index to fetch it's name.There's a sample within the $query documentation.Also, $order uses the lastest subscript you provided to find the next one. So, no, you don't need to know how many subscripts you have. But you need to know when to stop.I suggest you to check [@Sergey Kamenev]'s articles for a deep understanding about globals.