Mark Hanson · Jan 5, 2017 go to post

As you know these escape sequences are valid HTML escaping of unicode characters. The general principal is always that you store the text in the database  as characters i.e. not escaped at all and you apply any escaping needed when serving this content to a client. So it appears you need to convert these escaped characters into something you can store in your 8bit database.

Now in general I would suggest using unicode in which case you can just make sure the data being sent to you is correctly converted into unicode characters and then you just store the characters in the database. This would then work with any characters and not just the few you are having problems with. However it sounds like you do not want to move from 8bit to unicode. If that is the case anything you do will be something of a hack, but you can just use $replace on the data coming in to convert say "%u2019" to "'" before you store it in the database to 'normalize' the input. This solution will only cover a few characters where you can find a suitable replacement but it may be enough to get by for the short term while you investigate moving to unicode as a permanent solution.

Mark Hanson · Jan 3, 2017 go to post

You can also view the line at the command prompt with:

ZZPRINT "main+45^LBZNSJHCACUPLB"

Or to view 5 lines before this line and 2 lines after:

ZZPRINT "main+45^LBZNSJHCACUPLB":5:2

Mark Hanson · Dec 19, 2016 go to post

Note that any time you build a query as a string if you allow users to insert parameter values or control the string you are building in any way into you need to be aware of SQL injection attacks. This is not a problem with '?' query argument substitution as it is designed to avoid injection attacks, but if you have say:

Set sql="select Name from MyTable where Age > "_userage

And the user supplies 'userage' then they could provide "100; drop table MyTable;" or worse.

Mark Hanson · Nov 29, 2016 go to post

In Cache 2017.1 we have light weight SQL profiling enabled by default which will keep track of the number of times each SQL query is called and how long these queries take.  So you can quickly answer the question as to which SQL queries matter to your application and then investigate these important queries in more detail.

This information will show up in the system management portal in the SQL explorer section under the sql queries in this namespace section.

Mark Hanson · Nov 23, 2016 go to post

Note that NIST has come up with new recommendations about password security, here is a good overview:

https://nakedsecurity.sophos.com/2016/08/18/nists-new-password-rules-wh…

Specifically see this section:

No composition rules. What this means is, no more rules that force you to use particular characters or combinations, like those daunting conditions on some password reset pages that say, “Your password must contain one lowercase letter, one uppercase letter, one number, four symbols but not &%#@_, and the surname of at least one astronaut.”

So it recommends against complex patterns such as the one you are asking about. Also of interest is this one:

No more expiration without reason. This is my favourite piece of advice: If we want users to comply and choose long, hard-to-guess passwords, we shouldn’t make them change those passwords unnecessarily.

The only time passwords should be reset is when they are forgotten, if they have been phished, or if you think (or know) that your password database has been stolen and could therefore be subjected to an offline brute-force attack.

Mark Hanson · Nov 14, 2016 go to post

Also this should be fast too:

Set id=1

&sql(select Name into :name from Test.Person where %ID=:id)

Write name,!

Mark Hanson · Oct 17, 2016 go to post

Some tools do not like the fact that the RSS feed is badly formatted as there are no title fields, this was reported a long time ago but is still not fixed for example the start of 'https://community.intersystems.com/group/8046/feed':

<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xml:base="https://community.intersystems.com/group/8046" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:og="http://ogp.me/ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:sioc="http://rdfs.org/sioc/ns#" xmlns:sioct="http://rdfs.org/sioc/types#" xmlns:skos="http://www.w3.org/2004/02/skos/core#" xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
  <channel>
    <title></title>
    <link>https://community.intersystems.com/group/8046</link>
    <description></description>
    <language>en</language>
Mark Hanson · Sep 29, 2016 go to post

This is then identical to the 'For' loop example except you have a redundant 'If 1' test each time around the loop, so why not just use the 'For' structure in the original post?

Mark Hanson · Sep 23, 2016 go to post

The 'Do While' is in fact identical to the 'For' block structure except it adds a redundant while condition at the end which is never false as it will have already exited this block from the 'Quit:Sub1=""' condition earlier, so you should probably remove this as it just takes the 'For' structure and adds this extra test which will slow the loop down.

A disadvantage of the 'While' structure is first you need to repeat the iteration construct, e.g. 'Set Sub1=$O(^Trans(Sub1))' before entering the loop and at the end. Also if you need to skip an item with say the 'For' structure you can just issue a 'Continue' but with the 'While' structure you have to advance the current subscript value manually before issuing a 'Continue'

In the 'Method Levels' the lines like 'Goto Level1' are not needed as the previous line says 'Set Sub2="" Goto Level2' so it will always be evaluating this 'Goto Level2' and so will never get to the next line. Rather than having this you can simplify to just 'Set Sub2=""' and remove both 'Goto' statements so it will just drop down into Level2 automatically.

Mark Hanson · Sep 9, 2016 go to post

Why do you want the connection id to change? In CSP we route multiple requests to a few server processes to be able to handle massive numbers of client efficiently. However the process that handles the request does not hold any information about the session at all, all this information such as the license we hold is in the %session object so as long as you have a new %session object this is a brand new connection.

Mark Hanson · Sep 7, 2016 go to post

I think we may need some more context of what the code looks like and exactly what error message you are getting. We do support $$$CacheError in 2016.1, for example:

Set status=$$$ERROR($$$CacheError,$zerror)

If you are trying to lookup the macro value then use $$$ERRORCODE($$$CacheError), then you can write logic like:

If errorcode=$$$ERRORCODE($$$CacheError) Write "It was a Cache error",!
Mark Hanson · Jul 23, 2016 go to post

You do not need to override the propGet method here as this will be generated automatically to call the sqlcomputecode if that is defined.

Mark Hanson · Jul 7, 2016 go to post

Try:

<script language="Cache" method="OnPreHTTP" arguments="" returntype="%Boolean"
     Set %response.ContentType "text/xml"
    Quit 1</script><?xml version="1.0" encoding="UTF-8" ?>

As the cr/lf after the </script> will end up in the output we generate as this is part of the HTML output rather than inside the script itself.

Mark Hanson · Jun 23, 2016 go to post

You are right, I had missed this was creating a %Status and thought they just needed the error code. To create a %Status value I would always use the $$$ERROR macro as you suggest.

Mark Hanson · Jun 23, 2016 go to post

The correct way to do this is:

set RunStatus=$System.Status.Error($$$ERRORCODE($$$GeneralError),"DXL Testing Run Error")

So use $$$ERRORCODE which can convert the error code to the number correctly.

Mark Hanson · May 20, 2016 go to post

Thank you for this really useful article, there is some great information here.

Mark Hanson · May 16, 2016 go to post

FYI: I get consistently slower performance with the 'for' loop variation here (around 10% slower) so at least in my simple test the while loop both looks nicer and runs faster.

Mark Hanson · May 13, 2016 go to post

Much better, the main page request is down to 1.0s and total load time is 1.7s which while still slow is no where near as bad as >6s, thanks.

Mark Hanson · May 13, 2016 go to post

The MAK4540 fix was approved for porting to 2016.1.1 and all later releases.

Mark Hanson · May 12, 2016 go to post

I fully agree with hoisting constants out of a loop and have recently spent a while optimizing code to use $listnext in SQL and so agree it is a much faster way to iterate over $listbuild structures.

However in your first case of a 'For' loop the end condition is evaluated when entering the loop the first time and is not re-evaluated at all, for example run this:

CACHE20164:USER>set a=2 for i=1:1:a { set a=10 write i,! }
1
2

As you can see it always stops at '2' rather than going on to '10'.

Also there is overhead in converting from a delimited string into a $list format in order to use the more efficient $listnext, you can avoid the O(n^2) overhead with the regular $piece(string,",",i) code in a loop using $find with a starting position and then $extract the item you need. This should perform better than $listnext version of the loop at least for mid sized strings as it avoids the conversion overhead.

Mark Hanson · May 12, 2016 go to post

The use of ZZW was a mistake and we removed this in the next release after it was introduced.

I did not see any documentation that said that 'ZZ' was reserved for any particular use and the examples in the documentation show functions that do not use 'ZZ' as part of their name so I was trying to avoid user extensions in naming the item 'ZZPRINT' by assuming we can use 'ZZ' and customers will use 'Z<something else>'. I apologize if this caused a problem for you, that was the opposite of my intension.

Mark Hanson · May 11, 2016 go to post

I would generally advise against using %File class for reading files as this is a very low level wrapper around the COS file commands. For example if you want to apply a translate table you need to know about the 'K' flag on the open command. I much prefer using the %Stream.FileBinary or %Stream.FileCharacter classes as these provide a much more consistent interface to the file.

Mark Hanson · Apr 16, 2016 go to post

I often do this too, I think this sort of pattern is a good way to make the error handling simple and consistent.

Mark Hanson · Apr 14, 2016 go to post

The problem with this is I believe they do not want the object saved into the database at all. It seams like a worthwhile enhancement that export to XML could optionally call %ValidateObject on the objects as it walks the tree.

Mark Hanson · Apr 14, 2016 go to post

I fully agree that using the line by line monitor is the way to go, take a look at  %Monitor.System.LineByLine.cls which provides an API to turn this on/off and get information out of the line by line monitoring.

Also for mapping INT lines back to source lines you can look at the API in %Studio.Debugger.cls in method  SourceLine. This class does say it is internal but I think this particular method should be fine to use.

Mark Hanson · Apr 10, 2016 go to post

This is not possible, as you suggest you should put the methods you wish to call at generator time in another class and make sure you create a dependency with this other class using the 'DependsOn' keyword to make sure we fully compile this other class first.