It somewhat defeats the purpose of $zf(-100).
Parametrized commands are generally better.
- Log in to post comments
It somewhat defeats the purpose of $zf(-100).
Parametrized commands are generally better.
set cmd = "ps"
set arg = 4
set arg(1) = "-Af"
set arg(2) = "|"
set arg(3) = "grep"
set arg(4) = "username"
set sc = $zf(-100, "/SHELL", cmd, .arg)SQL is rather static and wants to be resolved at compile time.
What do you want to achieve?
You can have a classmethod that returns resultset(s). Check Sample.Person for example.
Try
select name from A where id = '5983658923646'By the way, what do you want to do with that info?
I'm using Cache-Tort-Git UDL fork and really recommend it. It's a great source control hook!
Some thoughts.
1. Do not use Hungarian notation.
2. Do not use ByRef params/dynamic objects/$lists/args... as an arguments. There are two exceptions: you don't know the number of arguments or there's more than 10 arguments.
3. Method should not parse arguments, only validate arguments. If caller passed invalid input it's caller problem. Fail fast.
4. Mandatory arguments go first.
5. If several methods have similar signatures, the order of arguments should be the same.
6. Same logical arguments in different methods should have the same names.
7. Arguments should be consistent. If you pass primitives, pass primitives everywhere. If you pass dynamic objects, pass them everywhere.
8. Return types should also be consistent.
9. If it's object methods and you pass the same optional arguments in several methods extract these arguments as a property.
Thank you, @Steven Hobbs ! I'll try to fix my code on LE platforms at the very least.
There are some unusual rules that must be followed if you want to get the same results as the $LISTxxx functions get in IRIS/Caché.
Is there any place I can familiarize myself with these rules?
You can do it with a special property class. Here's how it works:
Class Testing.PropertyClass
{
Parameter myPropName;
}
Class Testing.MyPersistentClass Extends %RegisteredObject [ PropertyClass = Testing.PropertyClass]
{
Property p1 As %String(MAXLEN = 5, myPropName = "myPropValue");
}But I recommend you to check RESTForms project (part1, part2), which sounds like what you're doing -automatic REST interface for persistent classes.
It also defines property class for similar purposes.
Why do you want to achieve that?
You need custom datatype for that, defining your parameters:
Class Testing.String Extends %String
{
Parameter myPropName;
}
And use that as a property type:
Class Testing.PropertyParameters Extends %RegisteredObject
{
Property p1 As Testing.String(MAXLEN = 5, myPropName = "myPropValue");
}
Still, please tell us your use case.
You can store/access list properties same as array properties(via third table):
Property MyListProp As list Of Some.Class(SQLPROJECTION = "table/column", STORAGEDEFAULT = "list");Note that you need first to delete class storage if any exists and either recreate or move the data to comply with the new storage.
You can also write a stored procedure which accepts id and returns the field you need.
Here's an example:
ClassMethod ListProp(id, prop, listprop) As %String [ SqlProc ]
{
set ids = $classmethod(, prop _ "GetStored", id)
quit:'$lv(ids) ""
set ptr = 0
set result = ""
if listprop="id" {
while $listnext(ids, ptr, value) {
set result = result _ value
}
} else {
set propClass = $$$defMemberKeyGet($classname(),$$$cCLASSproperty,prop,$$$cPROPtype)
while $listnext(ids, ptr, value) {
set result = result _ $lb($classmethod(propClass, listprop _ "GetStored", $lg(value)))
}
}
quit $lts(result)
}Arguments:
Check out our webinar today! It would be about Python Gateway/ML. Also, there's ML Toolkit user group - a private GitHub repository set up as part of InterSystems corporate GitHub organization. It is addressed to the external users that are installing, learning or are already using ML Toolkit components. To join ML Toolkit user group, please send a short e-mail at the following address: MLToolkit@intersystems.com and indicate in your e-mail the following details (needed for the group members to get to know and identify you during discussions):
Congratulations!
Pease consider using code formatting button
to format large (multiline) code listings.
Add this line:
ENV PIP_DEFAULT_TIMEOUT 600to the beginning of Dockerfile (after FROM of course) and try to build again.
You can store list properties same as array properties:
Property Collection As list Of ICT.Experiments.B(SQLPROJECTION = "table/column", STORAGEDEFAULT = "list");Note that you need first to delete class storage if any exists and either recreate or move the data to comply with the new storage.
Working code:
int GetGlobalOrder(char *global, int start, int end, CACHE_EXSTRP result)
{
if (isInitialized == false) {
Initialize(NULL);
}
// narg Number of subscript expressions pushed onto the argument stack.
int narg = 1;
// Direction for the $Order is 1 for forward, -1 for reverse.
int dir = 1;
// Indicates whether the data value, if there is one, should be returned.
int valueflag = 1;
// Has argument flag
int flag = 0;
// key - current subscript
int key = start - 1;
// row count
int c=0;
while (key<end) {
CACHEPUSHGLOBAL(strlen(global), global);
CACHEPUSHINT(key);
CACHEGLOBALORDER(narg, dir, valueflag);
CACHEPOPINT(&flag);
if (flag) {
//use CACHETYPE() to get the value type, then the appropriate CACHEPOP for the subscript
CACHEEXSTRKILL(result);
CACHEPOPEXSTR(result);
// do stuff with result
}
//use CACHETYPE() to get the subscript type, then the appropriate CACHEPOP for the subscript
int type = CACHETYPE();
CACHEPOPINT(&key);
if (key==NULL) {
break;
}
c++;
}
return ZF_SUCCESS;
}Thanks to @Chuck Sorenson for help!
What does this code print?
set ^dbg = $lb(pRequest.FileStatus, pRequest.Path, pRequest.InterchangeOID)
zw ^dbgHere's a sample C code to iterate over $lb structure.
#include <math.h>
/// Convert unsigned integer bytes to integer
int64_t makeint(const char *buff, size_t offset, size_t offsetinint, size_t len)
{
union
{
int64_t i64;
uint8_t u8[8];
}d64;
offsetinint = offsetinint & 7;
memset(&d64, 0, sizeof(d64));
memcpy(&d64.u8[offsetinint], buff + offset, len > (8 - offsetinint) ? (8 - offsetinint) : len);
return d64.i64;
}
/// get next power of 2 greater than v
int64_t next2(int64_t v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v |= v >> 32;
v++;
return v;
}
/// List types. NONE and NONE2 are placeholders
/// See %CACHE_HOME%\dev\Cache\callout\demo\czf.pdf (Section "Lists")
enum ListTypes {NONE, STRING, USTRING, NONE2, INTP, INTN, DOUBLEP, DOUBLEN, FLOAT};
/// This function iterates over all elements in a list
void ListToTuple(CACHE_EXSTRP result)
{
// $lb structure
char* list = result->str.ch;
int listLength = result->len;
// current element
int num = 0;
// current byte position
int i=0;
// length of current element
int l = 0;
// datatype
int type = 0;
while (i<listLength) {
// Calculate length of current element - START
if (0 == (l = (list[i]&255))) {
// First BYTE is 0, length is in following 2 BYTEs
size_t t_n = ((list[i+1]&255)|((list[i+2]&255)<<8));
if (t_n != 0) {
l = t_n + 3;
} else {
// 4 Byte length
l = ((list[i+3]&255) | ((list[i+4]&255) << 8) | ((list[i+5]&255) << 16) | ((list[i+6]&255) << 24)) + 7;
}
}
// Calculate length of current element - END
// Calculate data position - START
int dataStart = 0;
int dataLength = 0;
if (l < 255) {
type = list[i+1];
dataStart = i + 2;
dataLength = l - 2;
} else if (l < 65536) {
type = list[i+3];
dataStart = i + 4;
dataLength = l - 4;
} else {
type = list[i+7];
dataStart = i + 8;
dataLength = l - 8;
}
// Calculate data position - END
if (type==STRING) {
char* value;
memcpy(value, list+dataStart, dataLength);
} else if (type==USTRING) {
char* value;
memcpy(value, list+dataStart, dataLength/2);
} else if (type == INTP) {
int64_t value = makeint(list, dataStart, 0, dataLength);
} else if (type==INTN) {
int64_t value = 0;
if (l==2) {
value = -1;
} else {
memcpy(&value, list+dataStart, dataLength);
if (value == 0) {
value = - (1 << (dataLength * 8));
} else {
int64_t pow2 = next2(value);
value = value - pow2;
}
}
} else if (type==DOUBLEP) {
int64_t temp = makeint(list, dataStart+1, 0, dataLength-1);
signed char exp = list[dataStart];
double value = temp*pow(10, exp);
} else if (type==DOUBLEN) {
int64_t temp = 0;
memcpy(&temp, list+dataStart+1, dataLength-1);
if (temp == 0) {
temp = - (1 << (dataLength * 8));
} else {
int64_t pow2 = next2(temp);
temp = temp - pow2;
}
signed char exp = list[dataStart];
double value = temp*pow(10, exp);
} else if (type==FLOAT) {
double value;
memcpy(&value, list+dataStart, 8);
}
i += l;
num++;
}
}
You need to map both data global and class package.
You have ASYNC calls to MS SQL operation in your Business process, right?
Add sync elements immediately after them.
Serenji connects you directly to the code in your namespaces, resulting in an experience more familiar to existing Studio users. No need to export and import classes and routines.
Nice!
Sure, there's a prebuilt docker container for that:
docker run -d -p 52773:52773 --name irispy intersystemscommunity/irispy-community:latest
Callin is stack-based. You push function arguments to a stack, call function, read result from stack.
These two functions are used to push and pop $lb to stack, not to get individual $lb elements.
Thank you Robert!
To be honest I'm hoping someone has C code to share.