Type Constraints


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:

  • Line 1 just says we're defining a type called QTY ("quantities").

  • Line 2 says that quantities have a possible representation called QPR. Now, physical representations are always hidden from the user, as we know from Chapter 2. However, Tutorial D requires every TYPE statement to include at least one POSSREP specification,[*] indicating that values of the type in question can "possibly be represented" in some specific way; and unlike physical representations, possible representations which we usually abbreviate to just possreps are definitely visible to the user (in the example, users definitely know that quantities have a possrep called QPR). Note very carefully, however, that there's absolutely no suggestion that the specified possible representation is the same as the physical representation, whatever that happens to be; it might be or it might not, but either way it makes no difference to the user.

    [*] There are some minor exceptions to this rule that need not concern us here.

  • Line 3 says the possrep QPR has a single component, called Q, which is of type INTEGER; in other words, values of type QTY can "possibly be represented" by integers (and users are aware of this fact).

  • Finally, line 4 specifies that those integers must lie in the range 0 to 5000 inclusive and it's that fact that constitutes the type constraint for type QTY; in other words, valid quantities are precisely those that can possibly be represented by integers in the specified range.

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_ Operators

Before 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:


QPR ( 250 )

This expression is a selector invocation for type QTY. The selector has the same name, QPR, as the sole possrep for that type; it takes an argument that corresponds to, and is of the same type as, the sole component of that possrep, and it returns a quantity (that is, a value of type QTY). Note: In practice, possreps often have the same name as the associated type I used different names in the QTY example to make it clear there's a logical difference between the possrep and the type, but it would be much more usual not to. In fact, there's a syntax rule that says we can omit the possrep name from the TYPE statement entirely if we want to, in which case it defaults to the associated type name. So let's change the QTY type definition accordingly:

   TYPE QTY POSSREP { Q INTEGER CONSTRAINT Q  0 AND Q  5000 } ; 

Now the possrep and the corresponding selector are both called QTY, and the selector invocation shown earlier becomes just QTY(250) which is the style I've been using for selectors throughout this book prior to this point. I'll assume this revised definition for type QTY for the rest of this chapter.


QTY ( A + B )

The argument to a QTY selector invocation can be specified as an arbitrarily complex expression (just so long as it's of type INTEGER, of course). If that expression is a literal, as it was in the previous example, the selector invocation is a literal in turn; in other words, a literal is a special case of a selector invocation, as we already know from Chapter 3.


THE_Q ( QZ )

This expression is a THE_ operator invocation for type QTY. The operator is named THE_Q because Q is the name of the sole component of the sole possrep for type QTY; it takes an argument (specified as an arbitrarily complex expression) of type QTY; and it returns the integer that's the Q component of the possrep for that argument.

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:


POINT ( 5.7, -3.9 )

This is a POINT selector invocation (actually a POINT literal).


THE_X ( P )

This expression returns the NUMERIC value that's the X coordinate of the cartesian possible representation of the point that's contained in the variable P. (That variable must be of type POINT, of course.)

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:


POLAR ( H, K )

This is a POLAR selector invocation; it returns a value of type POINT.


THE_THETA ( P )

This expression returns the NUMERIC value that's the THETA coordinate of the polar possible representation of the point that's contained in the variable P (which again must be of type POINT).

Type Constraints Continued

Now 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:

[*] It doesn't support possreps, either. As for selectors and THE_ operators, the picture is too complicated to describe in detail here; suffice it to say that analogs of those operators are usually available, though they're not always provided "automatically" as they are in Tutorial D.

   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.)



Database in Depth
Database in Depth: Relational Theory for Practitioners
ISBN: 0596100124
EAN: 2147483647
Year: 2006
Pages: 127
Authors: C.J. Date

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net