The basic concept of the EYEDB object model is the class which, as in any
traditionnal object model, modelize a set
of objects of similar properties (attributes) and behaviors (methods).
The attributes can be basic types, user types, references, arrays, collections.
The methods can be defined in C++ or in OQL (Object Query Language).
ODL allows one to specify classes, attributes, methods, triggers, constraints,
enumerate types, indexes and implementation hints.
We are going to introduced in details all the features of ODL.
// this is a simple line comments /* this is a multi line comments */
| byte | 1-byte integer |
| char | 1-byte character |
| short | 2-byte integer |
| int | 4-byte integer |
| long | 8-byte integer |
| double | 8-byte floating point |
| oid | 8-byte internal object identifier |
| enum | 4-byte integer |
class C {
attribute byte b;
attribute char c;
attribute short s;
attribute int i;
attribute long l;
attribute double d;
attribute oid o;
};
Notes :
class C {
byte b;
char c;
// ...
};
class C {
attribute char c1, c2, c3; // NOT correct
// ...
};
enum E1 {
A, // A == 0
B, // B == 1
C // C == 2
};
enum E2 {
D = 3, // D == 3
E, // E == 4
F = 100, // F == 100
G, // G == 101
H // H == 102
};
class C {
attribute int i;
E1 e1;
E2 e2;
};
class C {
attribute byte b_a[4]; // fixed length mono-dimensionnal array
attribute char str[]; // variable size mono-dimensionnal array
attribute int i_a[3][4][8]; // multi-dimensionnal fixed size array
attribute long l_a[][4][8]; // multi-dimensionnal variable size array
};
One particular interesting array type is the array of characters, which
can be denoted as string as follows:
class C {
attribute string s; // <=> char s[] (unlimited size string)
attribute string<32> bs; // <=> char bs[32] (bounded string)
};
Note that in a multi-dimensionnal array, only the extreme left dimension can be
variable:
class C {
attribute long l_a1[][4][8]; // correct
attribute long l_a2[4][][8]; // NOT correct
attribute long l_a2[4][8][]; // NOT correct
};
class C1 {
attribute int i;
};
class C {
attribute C1 l_c1; // literal attribute included in C
attribute C1 *o_c1; // object attribute referenced by C (or &oc1_1)
};
Let c an instance of the class C.
|
Do not confuse the * ODL meaning and the * C/C++ meaning: in C/C++, the * type modifier denotes an address to an area of the indicated type instances: it is a pointer to an address. This pointer can be incremented and decremented to change its location in the area. |
| In ODL, the * denotes a reference to one and only one object, it is why the & token is also accepted, although the meaning of this token is a little bit different in C++. |
| So, in ODL the construct C1 **oc1 makes no sense, in the same manner that the construct C1 &&oc1 makes no sense in C++. |
class C {
attribute C1 l_c1_1[2];
attribute C1 l_c1_2[];
attribute C1 l_c1_3[][10][20];
attribute C1 *o_c1_1[4];
attribute C1 *o_c1_2[];
attribute C1 *o_c1_3[][4][5];
};
class C {
attribute set<int> i_lset; // literal set of int
attribute set<C1> l_c1_lset; // literal set of C1 literals
attribute set<C1 *> o_c1_lset; // literal set of C1 objects
attribute set<int> *i_oset; // object set of int
attribute set<C1> *l_c1_oset; // object set of C1 literals
attribute set<C1 *> *o_c1_oset; // object set of C1 objects
attribute bag<C1 *> o_c1_lbag; // literal bag of C1 objects
attribute array<C1 *> o_c1_larr; // literal array of C1 objects
attribute bag<C1 *> o_c1_lbag[]; // array of literal bag of C1 objects
// multi-dimensionnal array of literal bag of set of array of C1 objects
attribute bag<set<array<set<C1 *> > > > x[2][3][4];
};
The differences between an array collection (i.e.
array<type> and an attribute array (i.e.
type []) are:
class C1 {
attribute string c1;
};
class C2 extends C1 {
attribute string c2;
};
class C3 extends C2 {
attribute string c3;
};
As in usual object conception, an object of class C2 includes the two
attributes c1 and c2 and an object of class C3
includes the three attributes c1, c2 and c3.
class C4 {
attribute C1 *oc1;
attribute C2 *oc2;
attribute C3 *oc3;
attribute C1 lc1;
attribute C2 lc2;
attribute C3 lc3;
};
The attribute oc1 may be of type C1, C2 or
C3.
class C {
attribute string s1;
attribute string s2;
attribute string s3;
constraint<notnull> on s1;
constraint<notnull> on s2;
constraint<unique> on s2;
constraint<unique> on s3;
};
The attribute s1 must not be null.
class C2 extends C {
attribute string c2;
};
When one creates an C2 object, the attributes s1 and
s2 must not be null and the attributes s2 and
s3 must be unique.
class C {
attribute string s1;
attribute string s2;
attribute string s3;
constraint<notnull, propagate = off> on s1;
constraint<notnull> on s2;
constraint<unique, propagate = off> on s2;
constraint<unique> on s3;
};
class C2 extends C {
attribute string c2;
};
The notnull constraint on C::s1 and the unique constraint
on C1::s2 will not be propagated to C2, but the
notnull constraint on C::s1 and the unique constraint on
C::s3 will be propagated to C2.
class C1 {
attribute string s1;
attribute int i1;
};
class C {
attribute C1 c1;
constraint<notnull> on c1.s1;
constraint<unique> on c1.i1;
};
class A {
attribute string sa;
attribute B *b;
};
class B {
attribute string sb;
attribute A *a;
};
In the previous cas, EYEDB maintains only partially the referential
integrity: for instance, one cannot create an object A
with an attribute b which refers an non-existent B
object. But, if the referenced B object is removed, the attribute
b will still referenced the removed object.
class A {
attribute string sa;
relationship B *b inverse B::b; // or inverse b
};
class B {
attribute string sb;
relationship A *a inverse A::b; // or inverse a
};
Note attribute has been replaced by relationship in
this case: this is mandatory.
class A {
attribute string sa;
relationship set<B *> b_set inverse a;
};
class B {
attribute string sb;
relationship A *a inverse b_set;;
};
and a many-to-many relationship:
class A {
attribute string sa;
relationship set<B *> b_set inverse a_set;
};
class B {
attribute string sb;
relationship set<A *> a_set inverse b_set;;
};
class C1 {
attribute string c1;
};
class C2 {
attribute string c2;
int perform(in int size, in string str, out double, in C1 &, inout C2 &);
};
Note that the & symbol may be replaced by the * symbol
or no symbol as anyhow only a persistent object (not a litteral) may
be passed to a method call.
class C2 {
attribute string c2;
int perform(in int size, in string str, out double, in C1 &, inout C2 &);
int perform(in double, out string mystr);
};
One can defined OQL methods in ODL. In this case, the name of the
arguments must be given:
class C2 {
attribute string c2;
int append(in string s)
%oql{
this.s2 += s;
return strlen(this.s);
%};
};
The OQL this variable denotes the calling instance.
class C {
static int perform1(in string); // or
classmethod int perform2(in string);
instmethod int perform3(in string); // <=> int perform3(in string)
};
If you want to execute a method on the client side, you must
use the keyword client as follows:
class C {
instmethod<client> int perform1(in string);
classmethod<client> int perform2(in string);
instmethod<server> int perform3(in string); // <=> int perform3(...)
classmethod<server> int perform4(in string); // <=> classmethod perform3(...)
};
class C {
attribute string s;
// C++ triggers
trigger<create_before> c_b();
trigger<create_after> c_a();
trigger<update_before> u_b();
trigger<update_after> u_a();
trigger<load_before> l_a();
trigger<load_after> l_b();
trigger<remove_before> r_b();
trigger<remove_after> r_a();
trigger<create_before> c_b2(); // one can have several create_before triggers
// OQL trigger
trigger<create_before> l_a2()
%oql{
if (strlen(this.s) > 100)
throw "invalid length";
%};
};
class C {
attribute string s;
attribute int i;
index on s;
index on i;
};
Note that we cannot define one index on several attributes.
class C {
attribute string s;
attribute int i;
index on s;
index on i;
};
class C2 extends C {
attribute long l;
};
Indexes are created for C::s, C::i, C2::s
and C2::i.
class C {
attribute string s;
attribute int i;
index<propagate=off> on s;
index<propagate=off> on i;
};
class C2 extends C {
attribute long l;
};
Indexes are created only for only C::s and C::i.
class C1 {
attribute int i;
attribute double d;
};
class C {
attribute string s;
C1 c1; // literal composite type
index on s;
index on c1.i;
index on c1.d;
};
class C {
attribute string<32> s;
attribute int i;
index<type = btree> on s; // default is hash: change to btree
index<type = hash> on i; // default is btree: change to hash
};
Important note: one cannot set a BTree index on non bounded string.
One can set implementation parameters for indexes as follows:
class C {
attribute string<32> s;
attribute int i;
index<type = btree, hints = "degree = 64;"> on s;
index<type = hash, hints = "key_count = 4096; initial_size = 4096;
extend_coef = 1; size_max = 4096;"> on i;
};
EyeDB manual