So far in this chapter, we have seen how to build well formed expressions
for server-side execution. We've reached the point where we can build such
an expression, and we can hold it in an exprn_mapper
variable. But before we can execute it, we need to place it in some other
context, e.g. a query, and that requires something else: compatibility
with the context.
Type compatibility is one necessary aspect (e.g. you can't use points->x + 3.14f in a context that requires a predicate or an abstract_mapper<std::string>), but type compatibility is not sufficient.
For consider this: points->x + 3.14f is
allowed here:
const query<float> x_plus_3_14 = points.select(points->x + 3.14f);
but not here:
const query<float> nonsense = oscars.select(points->x + 3.14f); // wrong
To clarify what's at issue, let me introduce the term visible, used in this way: a mapper is visible to an expression.
In points.select(points->x + 3.14f), the
value mapper for the points
table (aka *points)
is visible to the expression points->x + 3.14f.
That's due to a general rule that, for any query q
and server-side expression e, q.select(e) makes q's value
mapper visible to e. Still more generally, all
of the quince constructs that enclose server-side expressions within non-expression
contexts make some mappers visible to the expressions they enclose. The
specific rules are documented along with the constructs: watch for the
phrase “will be visible to” in the chapters that follow.
The rest of what you need to know about visibility is:
exists(...), in(...), collective
comparisons, and scalar(...)), then whatever is visible
to the expression is visible to all the expressions inside the subquery.
optional_mapper
is visible, so is its content mapper.
tuple_mapper
is visible, so are all its member mappers.
class_mapper
is visible, so are all its member mappers and base mappers.
So that's visibility defined. Now how does it affect which expressions may be evaluated?
A necessary condition for exprn to be evaluated
is that it be visibility-correct. It is visibility
correct if and only if at least one of the following hold:
exprn is not a mapper: it's a value, like
3.14f.
exprn is a mapper (possibly an exprn_mapper), and it is visible
to itself.
exprn is an exprn_mapper,
and all of its subexpressions are visibility-correct.
Currently quince does not check visibility correctness. That is left to
the DBMS at run-time, so your application will see any violation in the
form of a dbms_exception.
const query<float> x_plus_3_14 = points.select(points->x + 3.14f);
points.select(...)
makes *points
(that's points's value
mapper) visible to points->x
+ 3.14f.
points->x is visible to points->x
+ 3.14f,
because points->x a member of *points.
points->x is visible to points->x
and to 3.14f, because they
are subexpressions of points->x
+ 3.14f.
points->x is visibility-correct because it's
visible to itself.
3.14f is visibility-correct
because it's not a mapper.
points->x
+ 3.14f
is visibility-correct because both of its subexpressions are visibility-correct.
const query<float> xs = points.select(points->x); const query<float> x_plus_3_14 = xs.select(points->x + 3.14f);
On the last line:
xs.select(...) makes points->x
(that's xs's value
mapper) visible to points->x
+ 3.14f.
points->x is visible to points->x
and to 3.14f, because they
are subexpressions of points.
points->x is visibility-correct because it's
visible to itself.
3.14f is visibility-correct
because it's not a mapper.
points->x
+ 314f
is visibility-correct because both of its subexpressions are visibility-correct.
const query<float> x_plus_3_14 = points.select(points->x).select(points->x + 3.14f);
Okay because it's the same as example 2.
const exprn_mapper<float> additionA = points->x + 3.14f; const exprn_mapper<float> additionB = points->x + 3.14f; const query<float> x_plus_3_14 = points.select(additionA); const query<float> attempted_reselect = x_plus_3_14.select(additionB); // wrong
On the last line:
x_plus_3_14.select(...) makes additionA
(that's x_plus_3_14's
value mapper) visible to additionB.
additionB is not visible
here, since additionB
is not the same mapper as additionA.
additionB has subexpressions
points->x and 3.14f.
points->x is not visible here.
points->x is not visibility-correct.
points->x
+ 3.14f
are visibility-correct.
additionB
is not visibility-correct.
const query<float> attempted_reselect = points.select(points->x + 3.14f).select(points->x + 3.14f); // wrong
Wrong because it's the same as example 4.
const exprn_mapper<float> addition = points->x + 3.14f; const query<float> x_plus_3_14 = points.select(addition); const query<float> reselect = x_plus_3_14.select(addition);
On the last line:
x_plus_3_14.select(...)
makes addition (that's
x_plus_3_14's value
mapper) visible to addition.
addition is
visibility-correct because it's visible to itself.
const exprn_mapper<float> addition = points->x + 3.14f; const query<float> reselect = points.select(addition).select(addition);
Okay because it's the same as example 6.