As we saw in Chapter 2, one of the things we have to do when we define a type is specify the values that make up that type. Here's an example: 1 TYPE QTY 2 POSSREP QPR 3 { Q INTEGER 4 CONSTRAINT Q 0 AND Q 5000 } ; Explanation:
Here's a slightly more complicated example: TYPE POINT POSSREP CARTESIAN { X NUMERIC, Y NUMERIC CONSTRAINT SQRT ( X ** 2 + Y ** 2 ) 100.0 } ; Type POINT denotes points in two-dimensional space; it has a possrep CARTESIAN with two numeric components called X and Y (corresponding, presumably, to cartesian coordinates), and there's a type constraint that says, in effect, that the only points we're interested in are those that lie on or inside a circle with center the origin and radius 100. Selectors and THE_ OperatorsBefore I continue with my discussion of type constraints as such, I'd like to digress for a few moments; the QTY and POINT examples raise a number of issues that I need to address somewhere, and here's as good a place as any. Recall from Chapter 2 that user-defined types like QTY and POINT have associated selector and THE_ operators. Well, those operators are intimately related to the possrep notion; in fact, selector operators correspond one-to-one to possreps, and THE_ operators correspond one-to-one to possrep components. Here are some examples:
Now let's redefine type POINT to make its possrep have the same name as the type (for simplicity, let's also drop the type constraint, at least for the time being): TYPE POINT POSSREP { X NUMERIC, Y NUMERIC } ; To continue with the examples:
By the way, POINT is a good example of a type for which we might want to define more than one possrep for example: TYPE POINT POSSREP CARTESIAN { X NUMERIC, Y NUMERIC } POSSREP POLAR { R NUMERIC, THETA NUMERIC } ; The two possreps here reflect the fact that points in two-dimensional space can indeed "possibly be represented" by either cartesian or polar coordinates. Each possrep has two components, both of type NUMERIC and both user-visible. Continuing with the examples:
Type Constraints ContinuedNow let's get back to type constraints as such. Suppose I had defined type QTY as follows, with no explicit constraint: TYPE QTY POSSREP { Q INTEGER } ; This definition is defined to be shorthand for this one: TYPE QTY POSSREP { Q INTEGER CONSTRAINT TRUE } ; With either of these definitions, anything that can possibly be represented by an integer would be a legitimate QTY value (and so type QTY would still be subject to a certain constraint, albeit a fairly weak one). In other words, the specified possrep imposes a kind of a priori type constraint, and the CONSTRAINT specification if present imposes an additional constraint, over and above that a priori one. Informally, however, we usually take the term "type constraint" to refer to what's stated in the CONSTRAINT specification. One important issue I've ducked so far is the question of when type constraints are checked. In fact, they're checked whenever some selector is invoked. Assume again that values of type QTY are subject to the constraint that they must be possibly representable as integers in the range 0 to 5000. Then the expression QTY(250) is an invocation of the QTY selector, and that invocation succeeds. By contrast, the expression QTY(6000) is also such an invocation, but it fails. In general, in fact, we can never tolerate an expression that's supposed to denote a value of some type T but in fact doesn't; indeed, "a value of type T" that's not a value of type T is a contradiction in terms. As a consequence, no variable in particular, no relvar can ever be assigned a value that's not of the right type. A note on SQL: You will have noticed that all of my examples in this section have been expressed in Tutorial D, not SQL. That's because, believe it or not, SQL doesn't support type constraints at all -except for the rather trivial a priori ones, of course.[*] In other words, although SQL would let you define type QTY (for example) and specify that quantities must be representable as integers, it would not let you say those integers must lie in a certain range. For such reasons among others, I don't want to consider SQL user-defined types in detail in this book. However, I will at least show SQL counterparts to the Tutorial D QTY and POINT definitions that we've already seen:
CREATE TYPE QTY AS INTEGER FINAL ; CREATE TYPE POINT AS ( X NUMERIC, Y NUMERIC ) NOT FINAL ; One last point to close this section: defining anything to be of some particular type imposes a constraint on that thing, of course. In particular, defining attribute QTY of relvar SP (for example) to be of type QTY imposes the constraint that no tuple in relvar SP will ever contain a value in the QTY position that fails to satisfy the QTY type constraint. (This is an example of what's sometimes called anattribute constraint.) |