Hello all,
Okay, based on the information that Kent sent, I've done all kinds of
tests and here are my conclusions:
As we know, there are 3 ways that a calculation will use a plug-in on
the server as opposed to the client. Each of the 3 ways is listed below
along with my findings for each:
1. During the execution of server-side ScriptMaker scripts.
-- This should be obvious. FileMaker Server allows you to create a
Schedule that can call any ScriptMaker script in any file on the server.
That script can make any calls to server side plug-ins. This,
however, is only controlled server side. There is no way a client can
tell the server to run a schedule (without external help anyway).
2. During schema updates a stored calculation containing an external
function to be reevaluated.
-- The key word here is "reevaluated", which basically boils down to
only schema changes to the actual stored calculation in question will
cause it to be reevaluated on the server. Adding or removing fields or
changing any of the schema not related to this stored calculation will
not cause it to reevaluate on the server. Only changing the actual
stored calculation in a significant way (ie, you can't just add a
comment) will cause it to reevaluate on the server.
-- If you make the stored calculation a global, it only appears to
evaluate on the server the very first time (ie, right after you create
it). I was not able to get it to reevaluate on the server ever again no
matter how I changed the calculation. Note though that closing and
reopening the file will appear to make it evaluate on the server, but
it's simply giving you the original value it calculated; it doesn't
actually reevaluate it. If you think about how global fields work with
served databases, this should make sense.
-- If the stored calc relies on a secondary field (meaning if you
update that secondary field, the stored calc will reevaluate) and you
have a client-side plug-in use the ExecuteSQL API function to set that
secondary field, the stored calc will reevaluate on the client, not the
server. It seems this should be obvious, but I've included it for
completeness sake because it is one of the things I tested.
3. During a find request on an unstored calculation field that depends
on an external function.
-- If you create an unstored calculation field in your database and
then go into Find Mode and type something to find in that unstored
calculation field, it will indeed evaluate this calculation on the
server if it can. It determines if it can evaluate the calculation on
the server based on the kMayEvaluateOnServer flag of an external
function. Note that this flag must be defined on both the client-side
and server-side plug-in for all the external functions used in the
calculation. Otherwise, you will get inconsistent results and it may
even cause the server or the admin to crash (I was having some really
weird crashes testing this stuff .. see the P.S.).
-- Since a manual find works, this "feature" can be scripted with a
Perform Find script step. It can also be triggered from a button using
the Perform Find button step.
-- Doing a "find" from a client-side plug-in using the ExecuteSQL API
function (ie, a "select") does not cause the calculation to evaluate on
the server. The client appears to handle all queries done through the
ExecuteSQL API function. This is unfortunate.
-- There's an interesting side-effect of doing this: If your unstored
calculation uses a plug-in function that returns different results
depending on if it's evaluated on the client or the server, then the
found records returned to you may not appear to match what you were
searching for. To put this in example form, I was testing with the
Version function of my plug-in. On the client side, the version
function returns something like "Plugin Name v.1.0". On the server
side, the version function returns something like "Plugin Name SE
v.1.0". So, if I do a find for "SE" in this unstored calc, the server
evaluates the Version function on the server, sees the "SE" in the
result, and matches the record. But, after performing the find, the
client side shows me the resulting records and reevaluates the unstored
calc on the client resulting in a value that does not contain "SE". So,
it appears to have found records that don't match what I searched for.
I'm still pondering this in my head if it can be exploited in some
interesting way.
So, of the 3 ways mentioned above, the last method of performing a
find in an unstored calculation is actually a useful and exploitable way
of forcing a calculation to evaluate on the server and thus interact
with a server-side plug-in from a client. I'll leave it up to the
reader to figure out how to get information from the server-side plug-in
to be returned to the client. :)
Thanks for the kick-off in the right direction, Kent. And I hope
everyone else finds this information useful.
Jake
P.S. Here's some interesting things I found out while I was testing this:
- It appears that if you make a stored calculation that evaluates
FieldNames(Get(FileName);Get(LayoutName)), the server will go bye-bye.
Fun, eh? Perhaps I should report this. :)
- If the client-side plug-in does not define kMayEvaluateOnServer for
an external function, but the server-side plug-in does, it seems to
randomly pick which plug-in to ask about whether or not the function can
evaluate on the server or not. It seemed inconsistent anyway; perhaps
there was some obscure pattern I wasn't seeing. Also, when I was
testing all this and realizing that I didn't have the
kMayEvaluateOnServer flag set, the server admin java app kept crashing!
Not the database server itself, but the admin. It appeared that maybe
the database server was misbehaving though in that the names and
descriptions of the plug-ins in the admin would sometimes disappear or
have random characters in them. Perhaps the admin was having some
buffer overflow issues based on bad data from the server? I dunno.
--
Jake Traynham
Owner, CNS Plug-ins
http://www.cnsplug-ins.com/