CAN-DO

Hi Everyone, Hope you all are doing well.

I found some scenarios where CAN-DO function doesn't work the same way as it supposed to be(with special symbols). Somewhere i saw that CAN-DO is too old in progress programming and it is designed as a Security Function so instead of using CAN-DO we should use LOOKUP and INDEX. I have few concern regarding this:

1. Why CAN-DO function is security function.I did search regarding security functionality of CAN-DO function but didn't find anything related.
2. Should we still use CAN-DO function, if yes then what are the scenarios for that.

Please suggest.

Thanks & Regards!
Rajat.
 

GregTomkins

Active Member
The reason nobody else has answered this yet is because while CAN-DO can function as a shorthand for "OR" with a comma-delimited list, doing so is so reviled, most ProgressTalkers can't bring themselves to respond. Some might say that it's worse than USE-INDEX, or being on Version 9, or creating tables lacking a primary unique index.

Myself, I use it here and there, and I don't see a big problem. But that's probably why I am slaving away for peanuts in Northern Canada, while most PT'ers are raking in the big dollars in the sunshine.

As far as I know, there is nothing security-specific about CAN-DO, it's just how Progress originally imagined it being used. Other than some edge cases around special symbols, which I never use, there is nothing you CAN DO with CAN-DO that your CANT DO with LOOKUP.
 

TheMadDBA

Active Member
CAN-DO is not 100% a security function... but CAN-DO was originally made to handle the security functions for _File back in the olden days. That is why the * and ! characters have special meaning. Also why the default for the comparison string is the current USERID.

IF you can 100% guarantee that your values will never include * or ! then you can use CAN-DO. Plenty of existing code does.

But in most cases doing anything new with comma delimited lists is a bad idea.
 

TomBascom

Curmudgeon
Of course it is a security function. The name itself makes that obvious as does the documentation.

Along the other points that have been raised - if your userid is "root" it always returns true because root can do anything.
 

TomBascom

Curmudgeon
Just because plenty of existing code does something awful is not a good reason to continue the practice.

Especially when better alternatives exist.

CAN-DO() was pressed in to service 25 years ago because there were no string functions. No INDEX(), no LOOKUP(), no SUBSTRING() etc.
 

TomBascom

Curmudgeon
One more thing :)

CAN-DO() is always evaluated on the client. It cannot be evaluated on the server for query resolution.
 
Hi Tom, thanks for replying.

1. I don't understand the meaning of security function, is it related to any progress terminology or what.

2. As you said that CAN-DO is evaluated at client side then:
2.1 Is it good or bad because as per my understanding if server load is less then performance will be more?
2.2 How to check that CAN-DO is evaluated at client side OR can we check its performance in comparison with LOOKUP?

Please suggest.

Thanks & Regards!
Rajat.
 

TomBascom

Curmudgeon
A little quality time with the documentation is an excellent way to gain additional insight. I strongly recommend it. If you are running windows the ? icon in the OpenEdge program group has a great little index that makes looking up any keyword fast and painless. I sometimes spend hours just going from one to another bathing in the glorious prose of the documentation team. (I try not to read the sample code though -- that is known to cause brain damage in the unwary.)

A long time ago, in systems written before some people reading this forum were born, security was somewhat less intrusive and much more of an after thought than it is today. In those days of old the application enforced what little security there was by way of of occasional checks of the userid versus some criteria to determine if the user CAN-DO() the desired action. Thus you might code something like:

Code:
if CAN-DO( "tom" ) then
  for each customer:
    delete customer.
  end.

In this example only a user logged in as "tom" (or "root") will be allowed to run the bit of code which will delete all of the customers.

As I said, back in the day security was a bit of an after-thought.

Anyhow -- notice how the comparison of the provided argument to the current userid is *implied* by the call to CAN-DO()? This is why it must be run in the context of the client session.

This sort of thing is precisely what CAN-DO() was created for.

But programmers are clever -- and back in the 80s when the very first serious Progress 4GL applications were being created someone noticed that primitive string comparisons could also be done with CAN-DO(). Thus started the long and sordid history of CAN-DO() being abused as a string comparison function. What could possibly go wrong? (See above...) Sadly this was either invented by, or quickly adopted by, several very successful early applications and now many generations of otherwise innocent 4gl programmers have had their minds poisoned by this garbage.

Is it *better* for performance to run on the client? Certainly not. That means that each record will have to be shipped to the client for selection purposes. Many records will be discarded. Which means that all of that network traffic and the associated latency and bandwidth is wasted. It is *much* better from a performance perspective to have the server do as much selection and sorting as possible. This will actually reduce server load because the server will no longer have to waste energy looking at and manipulating records that are not needed.

As for "proving it" -- as always feel free to put together some test cases and run some benchmarks if you do not want to take my word for it. If you find a contrary result that would be exciting but I'll warn you that benchmarking is tricky and that extraordinary results require extraordinary proof -- so your benchmark code will need to be shared and carefully considered if it appears to show something different.
 

TomBascom

Curmudgeon
Since I'm on a roll... ;)

IF you can 100% guarantee that your values will never include * or ! then you can use CAN-DO.

Actually... those are not the only special characters that CAN-DO() recognizes:

http://www.peg.com/forums/peg/200405/msg00232.html
...
Sent: Sunday, May 09, 2004 07:08
Subject: Re: CAN-DO Issues with #

> > Had a weird problem show up. Customer used # in their text (e.g. #1 AUTO
> > MECHANICS) and when I entered "#*" to be used in the CAN-DO, the data did
> > not appear.
>
> http://www.peg.com/lists/peg/history/200102/msg00054.html
> <Tony Lavinio>
> The CAN-DO function knows about six special characters, AFAIK:
>
> . to match a single character
> * to match multiple characters
> ! to negate a match,
> , to separate matches in a list
> ~ to escape a character (don't forget to double it!)
> # which is used by the SQL89 code to handle GRANTable vs
> non-GRANTable permissions.
>

And hardly any code which abuses CAN-DO() makes any effort at all to ensure that special characters are not embedded in the arguments.

Yes, lots of code uses CAN-DO(). That does not make it a good practice. Or safe. Or efficient.

Lots of code does lots of bad things. We can do better.
 

TheMadDBA

Active Member
Hmm... Somehow I have managed to use Progress since V4 and apparently have never run into # or . in a CAN-DO list. We also seem to have found something that Tom is more passionate about than RAID levels and NAS/SAN :p

Like I said before I tend not to use delimited lists if I can avoid it, but you know what it is like to maintain code from certain vendors or homegrown code based on those vendor "standards".
 

TomBascom

Curmudgeon
I'm easy to wind-up... you could, for instance, open a thread and try to defend Hungarian Notation if you'd like -- but please wait a couple of weeks. I'm a bit busy right now and I'd rather focus on other things for a while.
 

TheMadDBA

Active Member
I will think of something soon to get you going.... You would think that PSC could have updated the documentation to state something like that in the last 20 years or so.... I checked the V10 help and it still had this for the CAN-DO function...

CAN-DO function
Checks a string value against two types of comma‑separated lists:
An ID list of one or more user permission strings that indicate what users have access to the current procedure. The function returns TRUE if the specified user ID has access according to the list. Thus, you can implement run‑time authorization for any procedure in your application.
An arbitrary list of string values. The function returns TRUE if the specified string value is contained in the list.
 

Rob Fitzpatrick

ProgressTalk.com Sponsor
I'm easy to wind-up... you could, for instance, open a thread and try to defend Hungarian Notation if you'd like -- but please wait a couple of weeks. I'm a bit busy right now and I'd rather focus on other things for a while.

Or FIND FIRST... or FOR FIRST... ;)
 

Cecil

19+ years progress programming and still learning.
I'm easy to wind-up... you could, for instance, open a thread and try to defend Hungarian Notation if you'd like -- but please wait a couple of weeks. I'm a bit busy right now and I'd rather focus on other things for a while.

I'm going explicitly use USE-INDEX for all my FIND statements because it will make my code run faster.:D
 

TheMadDBA

Active Member
At the risk of riling you up again.... We can't seem to get can-do as root to behave differently than any other user. Are you talking specifically about a Progress _User named root or just OS level root?
 
Top