To handle both C and C++ objects in the same application, the easiest way is to write in C++ and use the C++ interface to handle the C++ objects and simultaneously use the C Interface to handle the C objects. The only times that it makes sense to mismatch interfaces is when you want a C object to reference a C++ object, or vice versa.
Use the following approach to access C objects with the C++ Interface:
Include the C interface header file in the following manner:
extern "C" { #include "omapi.h" }; // right way
If you include the C interface header file as:
#include "omapi.h" // wrong way
..your C++ compiler will think that the C/VERSANT functions in omapi.h
should have a C++ linkage, which will result in linker errors for each C/VERSANT function referenced.
Also, you should include cxxcls/pobject.h
before omapi.h
.
LinkAny
or o_object
instead of Link<type>
.
For vstrs, use either Vstr<type>
or VstrAny
.
For link vstrs, use LinkVstrAny
instead of LinkVstr<type>
.
To retrieve objects from a database, use the C function o_locateobj()
instead of the C++ dereference operators ->, type*
, or PObject*
.
To acquire a write lock and mark an object for update, use o_preptochange()
instead of the C++ PObject::dirty()
method.
To modify an attribute, acquire a write lock, and mark an object for update, use o_setattr()
instead of a C++ method.
To create a new C object, use o_createobj()
rather than the C++ O_NEW_PERSISTENT()
syntax.
To access C++ objects with the C Interface, use o_locateobj(), o_setattr(),
and o_getattr()
in a normal manner to retrieve and access C++ objects.
struct
pointer
to access the fields. Objects deriving from PObject
have one attribute of type PClass*
that will show at the top of your objects.You cannot run the methods on an object created with the C Interface since the internal C++ pointers are not initialized properly.
1. Define classes using C++/VERSANT.
PObject
or from a subclass of PObject
.
#importSchema:
to the ODBInterface
class.
#importSchema:
is:
importSchema: schemaName fromDB: dbName
...where schemaName
is the the name of the class to be imported and dbName
is the name of the database containing the class definition.
If you change the database, attribute definition of a class after you have imported that class into your Smalltalk Image, you must reimport the class definition into your Smalltalk Image or else an error will be raised the next time you try to access an instance of that class. You must also take care when you access a class in a different database that has the same name but a different class defintion.
Smalltalk/VERSANT will disallow any changes to imported classes that will alter the number of instance variables or change the private class methods that are generated by Smalltalk/VERSANT.
In your Image, you can make the following changes to imported classes without creating and reimporting new definitions:
You can rename instance variables, as long as the total number of instance variables remains the same.
You can add and change methods except those that are generated by Smalltalk/VERSANT.
Information about imported classes is generated automatically and then internally accessed by the private class methods #vCxxSchemaSignature
, #vDataAttributeNames
, #vDataAttributePositions
, #vDataAttributeRepeatFactors
, #vDerivedStorageTransforms
and #vFullSetAttributeNames
.
No multiple inheritance is allowed.
VDate
and VTime
attributes: these attributes are mapped to instances of the Smalltalk Date
and Timestamp
classes.
You can override the default and have VERSANT check to make sure that your Image has the methods as the database class by overwriting the #needSourceVerification
method in your classes so that it returns true
.
ODB-Imported
Classes
.
ODB-Imported
Classes
category.
Object
.
PObject
or PVirtual
. When imported, the class will still derive from PObject
, but since in Smalltalk/VERSANT the PObject
and PVirtual
classes derive from the Smalltalk Object
class, instances of an imported class will share all behavior of the Object
class.
If the class derives from PObject
, the PObject
class will provide services for updating the database source or updating the imported class with the database source. The PVirtual
class provides services for computing combined hash values expected for accessing or updating collection objects.
[
]
<
>
and :
, that are not allowed in Smalltalk. When classes are imported, Smalltalk/VERSANT will do the following:
VVSet<Employee>::Person
.name
, Smalltalk/VERSANT will use name
as the instance variable.
2. It may not be possible for Smalltalk/VERSANT to use the leaf term. For example, there may already be an instance variable with the same name as the leaf term. If Smalltalk/VERSANT must use a full name as defined in C++/VERSANT, it will convert non-allowed characters to underscores. For example, for VVSet<Employee>::Person
.name
, Smalltalk/VERSANT may find it necessary to use VVSet_Employee___Person.name
.
To refer to classes with non-allowed characters, you can do either of the following.
(Smalltalk at: #'VVSet<Employee>')
. Assign the class to a global variable and then use the global variable as an alias to the class.
All C++/VERSANT collection classes may be used.
You can compute an elemental hash value by sending #vElementalHash
to an instance of Integer
, Float
, Double
, Character
, ByteString
, or PObject
. You can compute a combined hash value by using #vElementalCombinedHash:..
in the PVirtual
class.
With these hashing methods, you can develop a sharable persistent collection that involves hash look up. A sample program which allows a Smalltalk user to manage a VVSet<Type>
collection can be found in the VERSANT filein/demos
directory.
VMetaType
class.
#metaInfoFor:
to the Smalltalk/VERSANT VMetaType
class. You will receive a VMetaType
instance that describes the corresponding database schema without your having to import the corresponding class. This is particularly useful if you need to view schemas defined from C++/VERSANT which are not intended for object sharing.
#VSI_ST_NIL
storage transform.
Attribute names added by C++/VERSANT, such as __what
and __vptr
also have a #VSI_ST_NIL
storage transform, but you should not use them to store runtime information, because future VERSANT releases may suppress these attributes when classes are imported into Smalltalk/VERSANT.
If you want to use an attribute to store transient, runtime information, then create and reserve an attribute in the class when you define it in C++.
When you import a class, the data types defined for the class in its database are often mapped to corresponding Smalltalk/VERSANT data types (see the following section for information on how types are mapped.) For example, the database elemental type o_4b
is mapped to the Smalltalk SmallInteger
and LargeInteger
classes. Also, importing will cause a flattening of structure as expected by Smalltalk.
#databaseAttributeNameFor:
If you are querying on an elemental data type, because of possible variants in the way Smalltalk can map values (to SmallInteger
or LargeInteger
), you must prefix the value key with a type indicator in a pair of angle brackets.
age
attribute in a Person
class, and the age
attribute has the database type o_u1b
, then you must specify the query string as age=<VSI_ST_U1B>55
rather than age=55
.The database types and their corresponding type indicators are:
o_u1b <VSI_ST_U1B>
o_u2b <VSI_ST_U2B>
o_2b <VSI_ST_2B>
o_u4b <VSI_ST_U4B>
o_4b <VSI_ST_4B>
The default type indicator is <VSI_ST_4B>
.
VDate
or VTime
classes, you must also provide a type indicator.
VDate <VSI_ST_VDATE>
VTime <VSI_ST_VTIME>
For example, for an embedded VTime
attribute, all the following predicate strings are both valid and equivalent to one another:
"Use actual seconds of the VTime attribute."
'time = 811836204'
"Use the Timestamp formatted string."
'time = <VSI_ST_VTIME>''9/22/95 11:04pm'''
"Use term key substitution."
| timestamp pred |
timestamp := Timestamp readFrom: '9/22/95 11:04pm'.
p := VPredicate from: 'time = <VSI_ST_VTIME>:x'.
p valuesAt: #(#x) put: (Array with: timestamp).
Due to language differences, the mapping between a database data type and Smalltalk type may be supported only within a given range.
For example, suppose that a database contains a class with an attribute of data type o_u1b
(a one-byte, unsigned integer). When an object of that class is read from a database, the data type o_u1b
will be mapped to the Smalltalk class SmallInteger
. When that object is written back to a database, VERSANT will attempt to convert the value of type SmallInteger
back to type o_u1b
. This can cause problems, because a SmallInteger
can contain a larger value than o_u1b
. Similarly, a Smalltalk Character
can have value from 0
to the largest SmallInteger
, while the corresponding database data type char
can only assum the values between -128
and 127
.
In general, you must take responsibility for choosing the right C++ data type when creating classes whose instances will be used by both C++ and Smalltalk applications.
The following table lists all the type mapping supported in the current Smalltalk/VERSANT interface. The first column of the table list the data type that you might be using in your C++/VERSANT application when define the persistent classes. The second column lists the data type that the corresponding first column would be converted to. The third column is the name of the class that the corresponding database data type would be mapped to. The fourth column gives the corresponding storage transform symbol. For basic elemental data types, the supported data range is also listed.
C++ |
Database |
Smalltalk |
Transform |
Allowable |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
C++ |
Database |
Smalltalk |
Transform |
VDate
|
VDate
|
Date
|
#VSI_ST_VDATE
|
VTime
|
VTime
|
Timestamp
|
#VSI_ST_VTIME
|
VDate
and VTime
are C++/VERSANT classes used for attributes. When brought into Smalltalk, attributes are instantiated as instances of Date
and Timestamp
.
These two embedded types are handled specially, because they are widely used in C++/VERSANT applications. Mapping these types to the Smalltalk Date
and Timestamp
class allows objects to share the behavior of the two existing Smalltalk classes. Also, it eliminates the need to duplicate the effort in providing methods for manipulating related attributes in each application specific imported class.
Methods are available to do date and timestamp value conversion between Date
to VDate
and and between Timestamp
and VTime
.
C++ |
Database |
Smalltalk |
Transform |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
C++ |
Database |
Smalltalk |
Transform |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ODBInterface
importSchema:
— Import a class definition.
PObject
fileInSourceFromDB:
— Answer file-out source text.
loadSourceFromDB:
— Load file-out source.
storeSourceToDB:
— Store file-out source.
vElementalHash
— Answer an integer value that can be used as a hash index in a collection.
PVirtual
vElementalCombinedHash:
— Answer a combined hash value.
VMetaType
allCXXDefinedSchemsFromDB:
— Answer descriptions of all database classes.
attributes
— Answer descriptions of class attributes.
metaInfoFor:
— Answer a description of a database class.
name
— Answer the name of a database class.
supers
— Answer descriptions of super classes.
VAttribute
domain
— Answer the database class name.
name
— Answer the attribute name.
repeatFactor
— Answer the attribute repeat factor.
storageTransform
— Answer the derived storage transformation symbol for the attribute.
type
— Answer the attribute type.
ByteString
vElementalHash
— Answer a hash value for a ByteString
object.
Character
vElementalHash
— Answer a hash value for a Character
object.
Double
vElementalHash
— Answer a hash value for a Double
object.
Float
vElementalHash
— Answer a hash value for a Float
object.
Integer
vElementalHash
— Answer a hash value for an Integer
object.
This online documentation is confidential and proprietary to Versant Corporation and is licensed to you, or to your organization, pursuant to the terms of an agreement between you and Versant that restricts the use of this documentation. Please refer to the agreement for more information or call Versant at 510-789-1500 with any questions.