There are many cases where stored procedures require complex arguments using data shapes well known to higher level languages or that come from the schema. There is already some affordance for this sort of thing in the form of this kind of pattern:
(I'll continue to use this simple example as I discuss the generalization below)
Then maybe something like this
The above expands into:
And I think we can all agree the sugared version is a lot easier to reason about and much less prone to errors as well.
Those features have been in the language for a long time and that's all fine and well
but it isn't general enough to handle the usual mix of situations. For instance what
if you need a procedure that works with two people? A hypothetical
procedure cannot be written with the old form. This is where argument bundles come in.
The idea here is to name the bundle which provides useful reference. To wit:
So what's going on here? Well, there are lots of reasons to keep the API to procedures simple and adding general purpose structured types would be at odds with that. It would require lots of knowledge about C structure layout and whatnot. And trying to call from java would require very complex JNI for any such procedure. So we avoid all that. We keep simple arguments. The above expands into:
Or course the types don't have to be the same, you can create and name shapes of your choice. The language allow
you to use an argument bundle in all the places that a cursor was previously a valid source. That includes
update cursor, and procedure calls. You can refer to the arguments by their expanded name
p1.address means the same thing.
Here's another example showing a silly but illustrative thing you could do:
The above shows that you can use a bundle as the source of a shape elsewhere, and you can
use a bundle as a source of data to load a cursor. After which you can do all the usual value cursor things
out statements and so forth.
In order to call procedures with argument bundles more readily from other languages, the JSON output now includes additional information about where procedure arguments originated; The field with this information is creatively called "argOrigin:" and it has 3 forms.
- "arg_name" -> the argument is not an expansion of anything
- "T arg_name" -> the argument came from
- there will be one arg for each member of T
- the formal argument name for this arg will be argname
- if T is procedure arguments
like p1 argumentsthen you'll get "p1[arguments] arg_name"
- "name T arg_name" -> the argument came from
name like T(a named bundle)
- there will be one arg for each member of T
- the formal argument name for this arg will be T_arg_name
- T could be procedure arguments as above
- If the source of an argument was a cursor or argument bundle name you get instead that thing's shape source name
- this is always better because cursor names and bundle names are not globally unique.
- If the cursor had an anonymous source (e.g.
like select 1 x) then you get the useless shape name "select"
- this is an indicator that you should make some ad hoc struct for this procedure because there is no useful name for the arg bundle's type
None of this matters unless you're trying to make wrappers for a CQL procedure for some other language and you'd like to have your wrapper deal with structs rather than all loose arguments. the JSON basically tells you the structs.
Interestingly, argument bundles resulted in a significant reduction of code in the compiler. The argument bundle
name has to be usable in the contexts where a cursor was previously usable. It is another source of shaped data.
Getting that to work proved to be super simple as the two forms look almost identical to the compiler -- no coincidence there.
So very little code was required to make
from [cursor_name] work with
from [any_shape_name] in the half dozen or so places
that this construct is allowed (e.g. procedure call arguments, insert statements, etc.). However, there was as
much code associated with
from arguments as there was
from cursor_name. And the code was nearly identical..
When argument bundles were introduced the natural thing to do was to create an artifical bundle called "arguments" which
represents the bundle that is ALL the arguments. With that done, all the code for
from arguments could be deleted
arguments itself was a valid shape name. Hence
insert into T from arguments "just works". And so half
the rewrites were deleted. The only cost was that the form
from arguments like shape became the cursor form
from arguments(like shape) which only adds mandatory parens to a form that was largely unused anyway (there were two
cases in our entire codebase). The cursor form is more general as you can do
from C(like A, like B) to get the
fields that match
A then those that match
B. Arguments get this for free as well (well, at the cost of parens).
So overall, this feature was added, and the compiler got smaller and cleaner. Only the test suite had to grow.
Stay safe out there.