Crucible query system6006224Abstract A database system including a query mechanism for accessing data stored in the database. The database system includes classes comprising stored code enabling User generated database queries comprise data indicating one or more addresses at which the desired data resides. The query mechanism parses a query in to a plurality of query components. A query class in the query system instantiates a query component object for each of the query components. The query component objects are chained together to form query chains that enable message passing between the query component objects. Claims We claim: Description BACKGROUND OF THE INVENTION
______________________________________
SELECT Patient->Physicians->EmployedBy.CompanyName
FROM Patient WHERE Patient.Age < Patient->Spouse.Age
______________________________________
The difficulty with the preceding query in prior systems is that there is an implied join between Patients, Spouses, Physicians and Hospitals that must be carefully managed. The new query system iterates through all traversals to form the full cross product of associated objects. In the preceding example, if a Patient had two Physicians and two Spouses the query would correctly execute for each Physician/Spouse pairing. Subclass traversals can be interspersed with Relationship traversals, as in the following example:
______________________________________
SELECT Physician->Intern->Advisor.LastName
FROM Physician
______________________________________
where Intern is a subclass of Physician. The subclass traversal restricts the class of physicians, making available attributes and relationships defined within the subclass. Although the selection is from all Physicians, only instances of the Intern subclass are returned. CQL in accordance with the present invention extends the query system to do more than just Select statements. Just as in SQL the present invention extends Update, Insert, Delete, Connect and Disconnect. Their function is as follows: Update: Access a group of specified objects, and modify their attributes and relationships. Insert: Create a new object and set the values of its attributes and relationships. Delete: Delete the specified group of objects. Connect: Open a connection to the specified database, and return the Session object that is created. Disconnect: Close a database connection. A more detailed description of the CQL query language syntax and the query system features and capabilities follows. 1. Select Queries An example select query is:
______________________________________
SELECT P.LastName, Today() - P.DOB,
P->EmployeeOf.CompanyName
FROM Patient As P, P->PatientOf AS Doc, P->
Spouse AS S
WHERE (P.Age < S.IQ) and Doc.Salary > 100000)
ORDERBY P.LastName, P.FirstName, sqrt(P.Age)
______________________________________
The preceding query illustrates several of the features of the Select statement in accordance with the present invention. As described above, ".fwdarw." is used to specify relationships and "." is used to specify attributes. In a particular example, relationship traversal can be specified anywhere, and attributes can be specified anywhere except the FROM clause. This convenience greatly improves the ease with which complex queries are written. The SELECT clause specifies the projection or result of the query (i.e., P.LastName, Today()-P.DOB, P.fwdarw.Employee Of Company Name in the example above). A particular implementation supports three options: the name of a single class or correlation name optionally followed by relationship traversals, an asterisk, or a series of attribute specifications separated by commas. The asterisk implies the name of the class in the FROM clause, and is ambiguous unless only one class is named. If a series of attributes is specified their values are concatenated and returned as a single string. The FROM clause specifies the target objects to be searched. It can include class names, relationship traversal and subqueries. Targets may be given correlation names within the FROM clause by using he AS keyword. In other clauses the correlation name can be used instead of the full classname/relationship. Note that when relationships are used in other clauses it is as if they had also been listed in the FROM clause. That is, SELECT Patient.fwdarw.Spouse FROM Patient is semantically equivalent to SELECT S FROM Patient, Patient.fwdarw.Spouse as S. The WHERE clause comprises a series of predicates. Simple predicates use comparison operators on attributes and literal values. Compound predicates use Boolean OR, AND and NOT to combine the simple predicates. Attribute comparison is based on the Semantic Type of the attribute. The optional ORDERBY clause allows you to establish a sort order on the objects return by the Query. Additionally, several functions are added to the query syntax. Functions may be used wherever an attribute or literal might have been used. Included in the list of functions are Log, Ln, Cos, Sin, Sqr and Sqrt. Available math operators are +, -, *, / and %. There are also several intrinsic functions to support date arithmetic and comparisons, including Today(), Day(), Month(), and Year(). Set Functions are available that take entire queries as their argument. They include Min(), Max(), Sum() and Avg(). There is also the Coun() set function that takes a relationship traversal, and returns the successor count. Queries can be combined through the Intersection, Union and Except keywords. Parenthesis can be used to override the order of precedence, which is in the order specified above. 2. Connection Queries The Connect and Disconnect statements are used to establish and break, respectively, a connection with a remote database server. Example connection queries are:
______________________________________
CONNECT dbl@jeeves USER long DBTYPE matisse
SERVICE dev
DISCONNECT dbl@jeeves USER long
______________________________________
In previous systems remote connections were established by making databaseOpen() and vLogin() calls through a Database or the Database Manager. These connection queries in accordance with the present invention are added so that these routine chores could be accomplished through a single interface. This allows utilities such as an Export Tool to only have to deal with the Query System, and not to have to deal with Proxy or Database sub-systems. Optional arguments to the CONNECT statement include USER, PASSWORD, DBTYPE and SERVICE. On successful execution of a Connect statement the connection query returns the Session object that was created for the connection. On successful execution of the Disconnect statement the query returns any pending messages associated with the terminated Session. 3. Insert Queries The Insert statement creates new persistent objects of the specified class such as in the following example:
______________________________________
INSERT INTO Patient VALUES (LastName = `Long`,
FirstName = `James`, PatientId = `1234`,
PatientOf = (SELECT * FROM Physician Where
PhysicianId = `A4637`)
______________________________________
The value list in parentheses comprises a series of attribute or relationship names, each followed by an equal sign then a new value. In the case of the Attributes the value comprises a literal or a query that has a projection. In the case of a Relationship the value comprises a query that returns the object or objects to which the newly created object will be associated. Inserts are not conditional. Each time they are executed they will create exactly one object of the specified class. 4. Update Queries The Update statement is used to modify an existing object of the specified class as in the following example:
______________________________________
UPDATE P
FROM Patient AS P, P->Spouse AS S
WHERE S.PatientID = `473798`
VALUES (P.LastName = S.LastName)
______________________________________
The syntax is like a Select combined with an Insert's Value clause. The Select portion access the Object(s) to modify, and the Value portion describes the modification to perform. Both the Update and Insert use a non-standard form of the Value() clause as compared to standard SQL. In standard SQL the Update form is SET col1=col2=val2 . . . The Insert is col1, col2, col3 VALUE (val1, val2 val3), where specifying the columns is optional. 5. Delete Queries The Delete statement essentially a Select statement with the SELECT keyword replaced with DELETE:
______________________________________
DELETE S FROM Patient As P, P->Spouse as S
WHERE P.Deceased = TRUE and S.Insurance = FALSE
______________________________________
When executed the Delete query will deleted all the objects return by its query from the database 201. Desirably, after execution the Delete holds the Proxies of the deleted objects in Proxy system 101C and/or 101S. 6. Constraints The Constraint is a predicate that is tied to a Class, Attribute or Relationship. An example Constraint follows:
______________________________________
CONSTRAINT PasswordRequired ON User.Password
WHERE User.Password <> ""
______________________________________
Before a transaction is committed each Class Constraint, as well as the Attribute and Relationship constraints for all modified or created properties, will be evaluated by the Trigger System. If any Constraint fails then the transaction is aborted. 7. Triggers A Trigger is a side effect associated with the modification of a Class, Attribute or Relationship. Each Trigger has a name followed a keyword as in the example:
______________________________________
TRIGGER AssignPatientId BeforeCommit
ON Patient WHERE Patient.PatientID = ``
DO (UPDATE Patient VALUES (PatientID = 1 + Max
(Select P.PatientId FROM Patient AS P))
______________________________________
In this example the keyword (BeforeCommit above) defines when the trigger will be fired. Next is the On clause that is essentially a Select statement. This allows a Trigger to be fired conditionally based on the evaluation of a predicate. The final portion of the Trigger is the Do clause that specifies a series of subqueries that will be executed. Multiple subqueries within the Do clause are separated by commas. 8. Operations In many ways an Operation is like a Trigger. Each operation should have a name, be attached to a class, and should have a DO() clause that specifies some series of Inserts, Deletes and Updates to perform. A major difference between the Trigger and the Operation is with respect to parameters. An Operation replaces formal parameters with actual parameters before execution. Intensional and Extensional Queries An intensional query is one that accesses a group of objects from the database 201 according to some rule, such as: SELECT * FROM Patient. An intensional query is given a QueryDef that is the name of the class to access, and optionally a simple WHERE clause. When the intensional query is executed it sends it's simple query to the database, and returns a collection of proxies. In contrast, an extensional query is one that is tied to a specific set of objects that it will return. The extensional query is created through a persistent proxy of itself from the database. When it is constructed it already has its resultant proxy list. Intensional queries can become Extensional queries by giving them a collection of Proxies with the vEstablishGatewayAs() method call. An intensional that becomes extensional in this way will then ignore calls to the vExecute() method. When it is told to save itself to the database with vMakePersistent() it will save as an Extensional Query. An advantage of the foregoing procedure is that user interface software is allowed to compose or describe views in a hierarchy. One view might be given the query:
______________________________________
SELECT Patient->Episodes FROM Patient WHERE
Patient.DOB < 1956:07:01.
______________________________________
If this query were simply executed it would retrieve all Patients in the database that were over 40 and return all of their Episodes. But this Dynamic View might be nested within another Dynamic View. The outer View might have the query:
______________________________________
SELECT P->Patients FROM Physician As P WHERE
P.LastName = `Bukstein`
______________________________________
In this case the Query of the nest View would be given all Bukstein's patients to start with. When it executed it would only return Episodes of Bukstein's Patients who were over 40. The nested query is not made extensional to begin with because it is unknown whether an intensional query will be given proxies as an entry point into the database until it happens. The query chain is constructed earlier and the syntax of the query does not provide this information. Because the present invention stores queries as persistent database objects, it is necessary to know the class in order to properly save the query. A standard technique for defining the syntax of a computer language is to use Backus-Naur Form (BNF). Although the present invention can be readily implemented with alternative syntax commands, the following BNF describing CQL in accordance with the present invention is provided for purposes of completeness and to better enable complete understanding of the inventive concepts described herein. The BNF description provided below uses the following conventions: 1. Syntactic categories are defined using the form: syntactic.sub.-- category::=definition 2. Words inside angle brackets < > represent syntactic categories (i.e. nonterminals). 3. Square brackets ([ ]) surround optional items. 4. A vertical line (.vertline.) separates alternatives. Note that the BNF provided in accordance with the present invention is a similar to but less extensive than the BNF for SQL-92. The parenthesized number following each production is the page number where a corresponding definition is found in the SQL-92 specification.
______________________________________
<any query> ::=
<connection specification>
.vertline. <disconnection specification>
.vertline. <insert specification>
.vertline. <update specification>
.vertline. <query expression>
<connection specification> ::= (p.306)
CONNECT [TO] <database> @ <host> <connection
options>
<connection options> ::=
USER <user>
.vertline. PASSWORD <password>
.vertline. DBTYPE <database type>
.vertline. SERVICE <service>
<disconnection specification> ::= (p.306)
DISCONNECT [FROM] <database> @ <host>
.vertline. DISCONNECT [FROM] <database> @ <host> USER
<user>
<insert specification> ::= (p.513)
INSERT [INTO] <class name>
VALUES ( <insert attributes> <insert
relationships> )
<insert attributes> ::=
<attribute name> = <value expression>
.vertline. <attribute name> = <value expression>
<insert attributes>
<insert relationships> ::=
<relationship name> = <any query>
.vertline. <relationship name> = <any query> , <insert
relationships>
<update specification> ::= (p.513)
UPDATE <correlation name> <table expression>
VALUES ( <insert attributes> <insert
relationships> )
<delete specification> ::= (p.513)
DELETE <correlation name> <table expression>
<constraint specification> ::=
CONSTRAIN <constrain name>
ON <class> [ .multidot. <attribute> .vertline. ->
<relationship> ]
<WHERE clause>
<trigger specification> ::=
TRIGGER <trigger name> <trigger timing>
ON <class> [ .multidot. <attribute> .vertline. ->
<relationship> ]
WHERE <predicate>
DO ( <any query> [,<any query>. . . ] )
<trigger timing> ::=
AFTERRELATIONREMOVE
.vertline. AFTERRELATIONADD
.vertline. AFTERATTRIBUTEWRITE
.vertline. AFTERCREATE
.vertline. BEFOREDELETE
.vertline. AFTERDELETE
.vertline. BEFORECOMMITATTRIBUTE
.vertline. AFTERCOMMITATTRIBUTE
.vertline. BEFORECOMMITRELATIONSHIP
.vertline. AFTERCOMMITRELATIONSHIP
.vertline. BEFORECOMMITCLASS
.vertline. AFTERCOMMITCLASS
<operation specification> ::=
OPERATION <operation name>
WITH ( <arglist> )
DO ( <any query> [,<any query>. . . ] )
<query specification> ::= (p.498)
SELECT [ DISTINCT .vertline. ALL ] <select list>
<table expression>
<select list> ::= (p.498)
<asterisk>
.vertline. <object identifier>
.vertline. <object identifier>.<asterisk>
.vertline. <object identifier> <value list>
.vertline. <value list>
<value list> ::=
<value expression>
.vertline. <value expression> , <value list>
<correlation name> ::= <identifier>
<identifier> ::= (p.41)
Leading alpha followed by alphanumeric and
underscore.
Identifiers in SQL are not case sensitive.
<table expression> ::= (p.498)
<FROM clause> [ <WHERE clause> ] [ <orderby
clause> ]
<FROM clause> ::= (p.498)
FROM <table reference> [, <table
reference>. . . ]
<table reference> ::= (p.498)
<object identifier> [ AS <correlation name> ]
.vertline. <flattened oid> [ AS <correlation name> ]
.vertline. <subquery> [ AS <correlation name> ]
<object identifier> ::=
<class name>
.vertline. <class name> <relationship spec>
.vertline. <correlation name>
.vertline. <correlation name> <relationship spec>
<relationship spec> ::=
-> <relationship name>
.vertline. -> <relationship name> <relationship spec>
.vertline. -> <subclass name> <relationship spec>
<class name>
::= <identifier>
<attribute name>
::= <identifier>
<relationship name>
::= <identifier>
<flattened oid>
::= <database> @ <host> : <oid>
<database>
::= <identifier>
<host> ::= <identifier>
<oid> ::= An alphanumeric string
containing no
special characters.
<subquery> ::= (p.497)
<left paren> <query expression> <right paren>
<query expression> ::= (p.497)
<query term>
.vertline. <query expression> UNION [ALL] <query term>
.vertline. <query expression> EXCEPT [ALL] <query term>
<query term> ::= (p.497)
<query primary>
.vertline. <query term> INTERSECT [ALL] <query primary>
<query primary> ::= (p.498)
<query specification>
.vertline. <subquery>
<orderby clause> ::= (p.499)
ORDER [BY] <value list> [ ASC .vertline. DESC ]
<WHERE clause> ::= (p.499)
WHERE <search condition>
<search condition> ::= (p.494)
<boolean term>
.vertline. <search condition> OR <boolean term>
<boolean term> ::= (p.494)
<boolean factor>
.vertline. <boolean term> AND <boolean factor>
<boolean factor> ::= (p.495)
[ NOT ] <boolean primary>
<boolean primary> ::= (p.495)
<predicate>
.vertline. <left paren> <search condition> <right paren>
<predicate> ::= (p.495)
<comparison predicate>
.vertline. <between predicate> ??
.vertline. <in predicate> ??
.vertline. <like predicate> ??
.vertline. <exists predicate> ??
<comparison predicate> ::= (p.495)
<value expression> <comp op> <value
expression>
<comp op> ::= (p.127)
= .vertline. <> .vertline. > .vertline. < .vertline. >= .vertline. <=
<value expression> ::= (p.495)
<numeric value expression>
.vertline. <string literal>
<string literal> ::= (p.86)
Any set of characters delimited by
apostrophes.
To use an apostrophe within a string quote it
with a
second apostrophe.
<numeric value expression> ::= (p.495)
<term>
.vertline. <numeric value expression> <plus sign> <term>
.vertline. <numeric value expression> <minus sign>
<term>
<term> ::= (p.495)
<factor>
.vertline. <term> <asterisk> <factor>
.vertline. <term> <solidus> <factor>
<factor> ::= (p.495)
<numeric primary>
.vertline. <sign> <numeric primary>
.vertline. <unary function> ( <numeric primary> )
<unary function>::=
SQRT
.vertline. SQR
.vertline. SIN
.vertline. COS
.vertline. LOG
.vertline. LN
<numeric primary> ::= (p.496)
<unsigned numeric literal>
.vertline.
OPERATION Query system 102C and query system 102S comprise object-oriented query classes that include variable declarations and methods for constructing query objects. One of the methods in the query class is a constructor method that constructs query objects from, for example, user supplied input or from a textual query definition stored in a persistent query object. The CQL query may be parsed and when parsed looks very much like a conventional SQL query. However, queries are actually processed and stored as atomic query components that are referentially linked back to the data of the database's logical schema. The only information that needs to be coded is the query component types (such as the WHERE clause, the value clause, and the like) if these components should ever change. It should be noted that this kind of change is not an application change. Query system 102C, for example, constructs a data query by referring to a class map that is stored as data. The class map identifies what attributes in a class map to and from attributes in an query object. Essentially, the class map specifies how objects link to each other and how they can pass messages. Queries are constructed from a textual query definition as in: CQL.sub.-- Query(CQL.sub.-- String sQueryDef, CQL.sub.-- String sGroupName); This query definition conforms to the query language BNF as specified hereinbefore. The CQL prefix in terms represented herein indicates that the associated suffix term is a CQL-specific extension to standard SQL implementations. The CQL.sub.-- query may be a Select, Update, Connect, etc. Queries may also be constructed given the Proxy of a persistent query as in the example:
______________________________________
CQL.sub.-- Query( CQL.sub.-- Proxy proxyOfQuery, CQL.sub.-- String
sGroupName );
______________________________________
Queries are stored in the database as several query objects chained together. The proxy supplied to this constructor (i.e., proxyOfQuery in the statement above) is the first persistent query in the stored chain of query objects. As each query is constructed on the client the persistent relationships are traversed and additional constructor calls are made for all the sub-queries within the persistent query chain. The query class also comprises methods enabling the query object to save the proxies to the database. Proxies are saved to the database by first creating them on the client from a textual Query Definition, and then calling their method vMakePersistent() as follows: void vMakePersistent(CQL.sub.-- String sQueryName ); This method takes as an argument the name under which the query may latter be accessed. Care should be taken in naming these persistent queries to aid query reuse. When a query is executed it performs its defined function against an open database using a method contained in the query object such as: void vExecute(); In the case of a Connect query, execution causes a database connection to be established and the Session proxy returned. For a Select query execution causes a group of Proxies to be brought over from the database according to the various clauses of the Select statement. Instead of being executed a Query may be given a group of Proxies through the vEstablishGatewayAs() method illustrated below:
______________________________________
void vEstablishGatewayAs( CQL.sub.-- ProxyList
proxylistOfGateway );
void vEstablishGatewayAs( CQL.sub.-- ProxyList
proxylistOfGateway, CQL.sub.-- String
sAlias="" );
______________________________________
When this occurs an Intensional query will become Extensional. This query will ever after ignore calls to vExecute(). Once a query becomes Extensional it remains that way until it is destructed. This mechanism is used to nest subqueries. A single query may comprise multiple intensional subqueries, such as, SELECT * FROM Patient as P, Physician AS D where P.LastName=D.Lastname. Executed as it stands this query would compare all Patients to all Physicians. If we were to call vEstablishGatewayAs() and pass in one Physician Proxy and then call vExecute() the query would compare all Patients against the specified Physician. And if you called vEstablishGatewayAs() a second time and passed in a collection of 3 Patient Proxies, the query would then execute against the 3 Patients and 1 Physician, only. If you were to then save the Query to persistent storage it would be saved as two Extensional queries forever bound to the specified Patients and Physician. It is useful to note that the second method invocation includes the Alias or Correlation name of the query to which the command is directed. Many of the Query methods include a Alias as the final argument so that a method may be directed to a particular Query in the chain. This is described in greater detail hereinbelow with reference to the structure of query chains. Once a query is executed the query object executes methods to dispense (i.e., returns to the user) the Proxies it has accessed from the database.
______________________________________
void vProxyFirst(CQL.sub.-- String sAlias="");
void vPrcxyNext(CQL.sub.-- String sAlias="");
CQL.sub.-- Boolean bProxyValid(CQL.sub.-- String sAlias="");
CQL.sub.-- Proxy proxyCurrent(CQL.sub.-- String sAlias="");
______________________________________
In a particular example, the application programming interface (API) uses a standard First/Next iterator idiom to index through the returned proxies. In addition to reading the collection of Proxies, in many cases you can also write to the collection. Using statements such as:
______________________________________
CQL.sub.-- Boolean bInsertable(CQL.sub.-- String sAlias="");
void vProxyInsert(CQL.sub.-- Proxy proxyToInsert,
CQL.sub.-- String sAlias="");
void vProxyRemove(CQL.sub.-- Proxy proxyToRemove,
CQL.sub.-- String sAlias="");
void vProxyRemoveCurrent(CQL.sub.-- String sAlias="");
void ProxyRemoveAll(CQL.sub.-- String sAlias="");
______________________________________
the query system 103C can ask a Query object whether or not it can be written to through the bInsertable() method. If it returns TRUE then you can insert and remove selected Proxies. The following queries show examples of queries that can and cannot have Proxies insert or remove:
______________________________________
SELECT P->Dependent FROM Patient AS P WHERE P.PID =
`A78932`
SELECT P FROM Patient AS P WHERE P.LastName =
`Jones`
______________________________________
The first Query can have a Proxy inserted. The result would be to hook the select Patient to the new Proxy through the Dependent relationship. The second query is not insertable. Insertion into a set based on attribute values is not allowed in the preferred implementation. Another feature in accordance with a preferred implementation is that every Query can be asked for its value using statements such as:
______________________________________
CQL.sub.-- String
svalue();
CQL.sub.-- String
sValue(CQL.sub.-- String sAttribute,
CQL.sub.-- String sAlias="");
______________________________________
In many cases that value is explicit in the SELECT definition, such as, SELECT P.Lastname FROM Patient AS P. After execution we can use a First/Next mechanism to index through the collection of all Patients, accessing each Lastname by making a call to sValue(). In addition to the explicit value returned from a Query, it is also desirable to access attributes from any intermediate object within the query. Consider the Query:
______________________________________
SELECT * FROM Patient->PatientsOf->PracticeAt as H
WHERE H.Location = `Riverside`.
______________________________________
Once executed, this Query returns by default the Patients of all Physicians who practice at the Riverside clinic. As you First/Next through the resultant Proxies you can query any object for any attribute. For example, sValue("Patient", "LastName") returns the Patient's lastname, while sValue("Patient.fwdarw.PatientsOf", "PhID") returns the Physician ID of the current Physician. This mechanism can be used to access various attributes one at a time so that they can be properly formatted for export. Since the values read comprise object attributes from the various proxies returned from query execution, it is a straightforward process to write, as well as read, these values as follows:
______________________________________
CQL.sub.-- Boolean
bReadOnly(
CQL.sub.-- String sAlias="" );
CQL.sub.-- Boolean
bWritable(
CQL.sub.-- String sAlias="" );
void vWriteValue(
CQL.sub.-- String sNewValue,
CQL.sub.-- String sAttribute="",
CQL.sub.-- String sAlias="" );
void vWriteAllValues (
CQL.sub.-- String sNewValue,
CQL.sub.-- String sAttribute="",
CQL.sub.-- String sAlias="" );
______________________________________
If an attribute is not specified then the explicit value of the SELECT is written to. It is generally safer to specify the attribute you intend to modify. Query objects in accordance with the preferred implementation include methods to provide the standard Proxy API to Refresh, Update, and Delete whole groups of Proxies. The sublclasses CQL.sub.-- Update, CQL.sub.-- Delete, CQL.sub.-- Trigger shown in FIG. 3 comprise methods used to construct these query objects.
______________________________________
void vRefreshCurrent( );
void vRefreshGroup( );
void vDeleteCurrent( );
void vUpdateCurrent( );
void vUpdateGroup( );
______________________________________
Employing this technique enables users of the Query System 102C to handle all aspects of Proxy manipulation without having to know anything about Proxies. CQL Queries received from the user interface 103 or as stored text strings from the proxy of a persistent query are parsed in a conventional manner. Each portion of the parsed query statement is implemented as a single component query object. These components query objects are then connected together as a query chain, and only the terminal end (also called a stub end) of the chain is visible to user interface 103C. This terminal end passes method calls, such as vExecute(), down the chain as needed. Each portion of the query statement is implemented as a single component. These components are then connected together to form a query chain or query net, and only the terminal end of the query chain (also called a query stub) is visible to the user of the query. This terminal passes method calls, such as vExecute(), down the query chain as needed. At run time when a query executes the query executor reads the query-chain and uses information from the class map to read database 201 and retrieve objects. Query objects are instantiated as application-neutral proxies and served up to the user interface 103 processes. A useful way to understand query construction in accordance with the present invention is to follow the development of query chains that represent particular query expressions. FIG. 4 through FIG. 7 illustrate development of a query chain or query net using a method in accordance with the present invention. In FIG. 4, the query component: SELECT * FROM Patient AS P, P.fwdarw.Spouse AS S is graphically illustrated in directed acyclic graph form. In FIG. 4-FIG. 7, each block represents an atomic query component object. The notation within each block enclosed in parentheses indicates the subclass shown in FIG. 3 from which the query component object was generated. The unidirectional lines coupling indicate relationships between the query component objects where these relationships are specified by data within the objects and implemented by messages passed between the query component objects. As shown in FIG. 4, three query component objects are instantiated and chained together to form the query. A From object passes messages to both the intensional object PatientP and the traversal object Spouse S. The Spouse S object passes messages back to the Patient P intensional object to implement the query. The DAG shown in FIG. 5 illustrates the query: SELECT P.Age FROM Patient AS P WHERE P.IQ<150 which includes a WHERE clause. As shown in FIG. 5, FROM object passes messages to the WHERE object and to the Patient P intensional object. The WHERE object passes the message onto a second FROM object which in turn passes messages to the Patient P intensional object. The where object also passes a message to the predicate object that handles the condition expressed in the condition of the query. The predicate object communicates with the IQ attribute object and the "150" literal object. The attribute object couples to the Patient P intensional object to provide results of the predicate. The graph shown in FIG. 6 illustrates the query:
______________________________________
SELECT P->PatientOff->EmployedBy.Location FROM
Patient AS P
______________________________________
which includes multiple traversals in the SELECT clause. As shown in FIG. 6, an attribute object Location passes messages to the from object and the EmployedBy traversal object. The FROM object passes messages to the Patient P intensional object, the EmployedBy traversal object, and to the PatientOf traversal object. One useful aspect of the query system in accordance with the present invention is that Extensional, Intensional and Traversals are contained within the From query decorator (shown in FIG. 3). This is useful for performing join-like queries such as:
______________________________________
SELECT P.LastName, C.Location FROM Physician as D,
D->Patients as P, D->Clinics as C WHERE P.Age <
C.Age
______________________________________
Each Physician may have multiple Patients and Clinics. The FROM clause has the job of iterating through all Patients for every Clinic for each Physician. This cross product is managed by ordering traversal dependencies. When you send the Next message to the FROM it iterates through the dependent queries before the thing they depend on. In this way we process the query for every combination of attributes in the WHERE clause. The DAG shown in FIG. 7 represents a somewhat more complex query:
______________________________________
SELECT * FROM Physician
WHERE Physician.Salary < 100000
EXCEPT
SELECT C->Employee FROM Clinic AS C, C->TownOf as T
WHERE T.Population < 5000
______________________________________
The detail of the objects and couplings between objects is apparent from the drawing and is not described further to ease understanding. Significantly, the except object manages two otherwise independent query chains. A significant feature in accordance with the present invention is that entire query chains are stored within the database 201. Each query component object is attached to the CQL subclass (shown in FIG. 3) to which it corresponds and thereby saved as a persistent query object. This provides a convenient way to access all named queries associated with a particular class. Significantly, the query objects are stored with only data as the objects themselves do not include procedural code. When a query chain is saved only the lead query object or stub object receives a name. Only a named query associated with a class may be re-used. FIG. 8 illustrates in DAG form the structure of persistent queries stored in database 201 by query system 102S (shown in FIG. 2). As shown in FIG. 8, not all of the objects that can be constructed from client-side query subclasses (shown in FIG. 3) are represented within the database. For instance, there are no UNION, INTERSECTION nor EXCEPT queries in the database. Instead, all three are made persistent through the CQL.sub.-- Merge class. When a UNION query is made persistent it creates and stores a CQL.sub.-- Merge object, and writes "UNION" as the query definition. The definition is then used to determine the type of object to construct when the query chain is rebuilt on the client. Significantly, each query object is made persistent by storing data that will allow the query object to be rebuilt when it is desired to reuse the query object. The integrity of the stored query objects can be verified using any available data integrity technique. Because data integrity verification techniques are more reliable and faster than code verification techniques, the structure and method in accordance with the present invention offer high reliability and can be verified readily. Moreover, maintenance and upgrades are readily performed. Further, because data can be changed without halting a computer system, the underlying functionality of the query system in accordance with the present invention can be upgraded without halting the database function simply by modifying the stored data. When the query is rebuilt, the new functionality from the upgrade is immediately available. Although the invention has been described and illustrated with a certain degree of particularity, it is understood that the present disclosure has been made only by way of example, and that numerous changes in the combination and arrangement of parts can be resorted to by those skilled in the art without departing from the spirit and scope of the invention, as hereinafter claimed.
|
Same subclass Same class Consider this |
||||||||||
