Eliminate a JavaScript memory leak

This commit is contained in:
Christopher Jones 2019-11-05 10:54:10 +11:00
parent fb52b59d03
commit 29baa93978
8 changed files with 178 additions and 180 deletions

View File

@ -1,5 +1,12 @@
# Change Log
## node-oracledb v4.0.2 (DD Mon YYYY)
**This release is under development**
- Fixed a JavaScript memory leak when getting Oracle Database named type
information, such as with `getDbObjectClass()`.
## node-oracledb v4.0.1 (19 Aug 2019)
- Fixed a regression causing a segfault when setting `oracledb.connectionClass`

View File

@ -291,6 +291,10 @@ function close(a1, a2) {
self._close(options, function(err) {
if (!err) {
for (const cls of Object.values(this._dbObjectClasses)) {
cls.prototype.constructor = Object;
cls.prototype = null;
}
self.emit('_after_close');
}
@ -376,6 +380,31 @@ function unsubscribe(name, cb) {
self._unsubscribe.call(self, name, cb);
}
// build a database object class
function buildDbObjectClass(schema, name, fqn) {
const DbObject = function(initialValue) {
if (this.isCollection) {
const proxy = new Proxy(this, BaseDbObject._collectionProxyHandler);
if (initialValue !== undefined) {
for (let i = 0; i < initialValue.length; i++) {
this.append(initialValue[i]);
}
}
return proxy;
} else if (initialValue !== undefined) {
Object.assign(this, initialValue)
}
}
DbObject.prototype = Object.create(BaseDbObject.prototype);
DbObject.prototype.constructor = DbObject;
DbObject.prototype.schema = schema;
DbObject.prototype.name = name;
DbObject.prototype.fqn = fqn;
DbObject.toString = function() {
return 'DbObjectClass [' + fqn + ']';
};
return DbObject;
}
// define class
class Connection extends EventEmitter {
@ -409,18 +438,8 @@ class Connection extends EventEmitter {
const fqn = `${schema}.${name}`;
let cls = this._dbObjectClasses[fqn];
if (!cls) {
class DbObject extends BaseDbObject {
get [Symbol.toStringTag]() {
return fqn;
}
}
this._dbObjectClasses[fqn] = cls = DbObject;
cls.prototype.schema = schema;
cls.prototype.name = name;
cls.prototype.fqn = fqn;
cls.toString = function() {
return 'DbObjectClass [' + fqn + ']';
};
cls = buildDbObjectClass(schema, name, fqn);
this._dbObjectClasses[fqn] = cls;
}
return cls;
}

View File

@ -21,8 +21,78 @@
const util = require('util');
// define base database object class; instances of this class are never
// instantiated; instead, classes subclassed from this one will be
// instantiated; a cache of these classes are maintained on each connection
class BaseDbObject {
// extend class with promisified functions
_extend(oracledb) {
this._oracledb = oracledb;
}
// initialize object with value
_initialize(initialValue) {
if (this.isCollection) {
for (let i = 0; i < initialValue.length; i++) {
this.append(initialValue[i]);
}
} else {
Object.assign(this, initialValue);
}
}
// return as a plain object
_toPojo() {
if (this.isCollection) {
return this.getValues();
}
const result = {};
for (let name in this.attributes) {
let value = this[name];
if (value instanceof BaseDbObject) {
value = value._toPojo();
}
result[name] = value;
}
return result;
}
// custom inspection routine
[util.inspect.custom](depth, options) {
return '[' + this.fqn + '] ' + util.inspect(this._toPojo(), options);
}
[Symbol.iterator]() {
if (this.isCollection) {
const values = this.getValues();
return values[Symbol.iterator]();
}
throw TypeError("obj is not iterable");
}
[Symbol.toPrimitive](hint) {
switch (hint) {
case 'number':
return NaN;
default:
return '[' + this.fqn + '] ' + util.inspect(this._toPojo(), {});
}
}
get [Symbol.toStringTag]() {
return this.fqn;
}
toJSON() {
return this._toPojo();
}
}
// define proxy handler used for collections
const collectionProxyHandler = {
BaseDbObject._collectionProxyHandler = {
deleteProperty(target, prop) {
if (typeof prop === 'string') {
@ -70,73 +140,5 @@ const collectionProxyHandler = {
};
// define base database object class; instances of this class are never
// instantiated; instead, classes subclassed from this one will be
// instantiated; a cache of these classes are maintained on each connection
class BaseDbObject {
constructor(initialValue) {
if (this.isCollection) {
const proxy = new Proxy(this, collectionProxyHandler);
if (initialValue) {
for (let i = 0; i < initialValue.length; i++) {
this.append(initialValue[i]);
}
}
return proxy;
} else if (initialValue) {
Object.assign(this, initialValue);
}
}
// extend class with promisified functions
_extend(oracledb) {
this._oracledb = oracledb;
}
// return as a plain object
_toPojo() {
if (this.isCollection) {
return this.getValues();
}
const result = {};
for (let name in this.attributes) {
let value = this[name];
if (value instanceof BaseDbObject) {
value = value._toPojo();
}
result[name] = value;
}
return result;
}
// custom inspection routine
[util.inspect.custom](depth, options) {
return '[' + this.fqn + '] ' + util.inspect(this._toPojo(), options);
}
[Symbol.iterator]() {
if (this.isCollection) {
const values = this.getValues();
return values[Symbol.iterator]();
}
throw TypeError("obj is not iterable");
}
[Symbol.toPrimitive](hint) {
switch (hint) {
case 'number':
return NaN;
default:
return '[' + this.fqn + '] ' + util.inspect(this._toPojo(), {});
}
}
toJSON() {
return this._toPojo();
}
}
module.exports = BaseDbObject;

View File

@ -2350,8 +2350,9 @@ static bool njsConnection_scanExecuteBindUnit(njsBaton *baton,
NJS_CHECK_NAPI(env, napi_get_named_property(env, args[1], "type", &value));
NJS_CHECK_NAPI(env, napi_typeof(env, value, &valueType));
if (valueType == napi_function) {
NJS_CHECK_NAPI(env, napi_get_prototype(env, value, &prototype))
NJS_CHECK_NAPI(env, napi_strict_equals(env, prototype,
NJS_CHECK_NAPI(env, napi_get_named_property(env, value, "prototype",
&prototype))
NJS_CHECK_NAPI(env, napi_instanceof(env, prototype,
baton->jsBaseDbObjectConstructor, &check))
if (!check)
return njsBaton_setError(baton, errInvalidBindDataType, 2);

View File

@ -52,9 +52,10 @@ static NJS_NAPI_FINALIZE(njsDbObject_finalize);
static NJS_NAPI_FINALIZE(njsDbObjectType_finalize);
// properties for collections
static const napi_property_descriptor njsCollectionProperties[] = {
static const napi_property_descriptor njsClassProperties[] = {
{ "append", NULL, njsDbObject_append, NULL, NULL, NULL, napi_default,
NULL },
{ "copy", NULL, njsDbObject_copy, NULL, NULL, NULL, napi_default, NULL },
{ "deleteElement", NULL, njsDbObject_deleteElement, NULL, NULL, NULL,
napi_default, NULL },
{ "getElement", NULL, njsDbObject_getElement, NULL, NULL, NULL,
@ -81,6 +82,12 @@ static const napi_property_descriptor njsCollectionProperties[] = {
{ NULL, NULL, NULL, NULL, NULL, NULL, napi_default, NULL }
};
// class definition
const njsClassDef njsClassDefBaseDbObject = {
"BaseDbObject", sizeof(njsDbObject), njsDbObject_finalize,
njsClassProperties, NULL, false
};
// other methods used internally
static bool njsDbObject_getAttrValueHelper(napi_env env,
napi_callback_info info, napi_value *value);
@ -96,8 +103,8 @@ static bool njsDbObject_transformToOracle(njsDbObject *obj, napi_env env,
napi_value value, dpiNativeTypeNum *nativeTypeNum, dpiData *data,
char **strBuffer, njsDbObjectAttr *attr);
static bool njsDbObject_validateArgs(napi_env env, napi_callback_info info,
size_t numArgs, napi_value *args, njsDbObjectType **objType,
njsDbObjectAttr **attr, njsDbObject **obj);
size_t numArgs, napi_value *args, njsDbObjectAttr **attr,
njsDbObject **obj);
static bool njsDbObjectType_populate(njsDbObjectType *objType,
dpiObjectType *objectTypeHandle, napi_env env, napi_value jsObjectType,
dpiObjectTypeInfo *info, njsBaton *baton);
@ -113,7 +120,6 @@ static bool njsDbObject_wrap(napi_env env, napi_value value,
//-----------------------------------------------------------------------------
static napi_value njsDbObject_append(napi_env env, napi_callback_info info)
{
njsDbObjectType *objType = NULL;
dpiNativeTypeNum nativeTypeNum;
napi_value value;
char *str = NULL;
@ -121,9 +127,9 @@ static napi_value njsDbObject_append(napi_env env, napi_callback_info info)
dpiData data;
int status;
if (!njsDbObject_validateArgs(env, info, 1, &value, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 1, &value, NULL, &obj))
return NULL;
nativeTypeNum = objType->elementTypeInfo.nativeTypeNum;
nativeTypeNum = obj->type->elementTypeInfo.nativeTypeNum;
if (!njsDbObject_transformToOracle(obj, env, value, &nativeTypeNum, &data,
&str, NULL))
return NULL;
@ -131,7 +137,7 @@ static napi_value njsDbObject_append(napi_env env, napi_callback_info info)
if (str)
free(str);
if (status < 0)
njsUtils_throwErrorDPI(env, objType->oracleDb);
njsUtils_throwErrorDPI(env, obj->type->oracleDb);
return NULL;
}
@ -180,12 +186,11 @@ static napi_value njsDbObject_copy(napi_env env, napi_callback_info info)
static napi_value njsDbObject_deleteElement(napi_env env,
napi_callback_info info)
{
njsDbObjectType *objType = NULL;
napi_value args[1];
njsDbObject *obj;
int32_t index;
if (!njsDbObject_validateArgs(env, info, 1, args, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 1, args, NULL, &obj))
return NULL;
if (!njsUtils_getIntArg(env, args, 0, &index))
return NULL;
@ -240,7 +245,7 @@ static bool njsDbObject_getAttrValueHelper(napi_env env,
njsDbObject *obj;
dpiData data;
if (!njsDbObject_validateArgs(env, info, 0, NULL, NULL, &attr, &obj))
if (!njsDbObject_validateArgs(env, info, 0, NULL, &attr, &obj))
return false;
if (dpiObject_getAttributeValue(obj->handle, attr->handle,
attr->typeInfo.nativeTypeNum, &data) < 0)
@ -257,21 +262,20 @@ static bool njsDbObject_getAttrValueHelper(napi_env env,
static napi_value njsDbObject_getElement(napi_env env, napi_callback_info info)
{
napi_value args[1], value = NULL;
njsDbObjectType *objType = NULL;
njsDbObject *obj;
int32_t index;
dpiData data;
if (!njsDbObject_validateArgs(env, info, 1, args, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 1, args, NULL, &obj))
return NULL;
if (!njsUtils_getIntArg(env, args, 0, &index))
return NULL;
if (dpiObject_getElementValueByIndex(obj->handle, index,
objType->elementTypeInfo.nativeTypeNum, &data) < 0 ) {
obj->type->elementTypeInfo.nativeTypeNum, &data) < 0 ) {
njsUtils_throwErrorDPI(env, obj->type->oracleDb);
return NULL;
}
if (!njsDbObject_transformFromOracle(obj, env, &objType->elementTypeInfo,
if (!njsDbObject_transformFromOracle(obj, env, &obj->type->elementTypeInfo,
&data, &value, NULL))
return NULL;
return value;
@ -315,13 +319,12 @@ bool njsDbObject_getInstance(njsOracleDb *oracleDb, napi_env env,
static napi_value njsDbObject_getFirstIndex(napi_env env,
napi_callback_info info)
{
njsDbObjectType *objType;
napi_value value = NULL;
njsDbObject *obj;
int32_t index;
int exists;
if (!njsDbObject_validateArgs(env, info, 0, NULL, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 0, NULL, NULL, &obj))
return NULL;
if (dpiObject_getFirstIndex(obj->handle, &index, &exists) < 0) {
njsUtils_throwErrorDPI(env, obj->type->oracleDb);
@ -356,14 +359,13 @@ static napi_value njsDbObject_getKeys(napi_env env, napi_callback_info info)
static bool njsDbObject_getKeysHelper(napi_env env, napi_callback_info info,
napi_value *returnValue)
{
njsDbObjectType *objType = NULL;
int32_t index, exists, size;
napi_value arr, temp;
uint32_t arrayPos;
njsDbObject *obj;
// get object instance from caller
if (!njsDbObject_validateArgs(env, info, 0, NULL, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 0, NULL, NULL, &obj))
return false;
// determine the size of the collection and create an array of that length
@ -394,13 +396,12 @@ static bool njsDbObject_getKeysHelper(napi_env env, napi_callback_info info,
static napi_value njsDbObject_getLastIndex(napi_env env,
napi_callback_info info)
{
njsDbObjectType *objType;
napi_value value = NULL;
njsDbObject *obj;
int32_t index;
int exists;
if (!njsDbObject_validateArgs(env, info, 0, NULL, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 0, NULL, NULL, &obj))
return NULL;
if (dpiObject_getLastIndex(obj->handle, &index, &exists) < 0) {
njsUtils_throwErrorDPI(env, obj->type->oracleDb);
@ -420,11 +421,10 @@ static napi_value njsDbObject_getLastIndex(napi_env env,
//-----------------------------------------------------------------------------
static napi_value njsDbObject_getLength(napi_env env, napi_callback_info info)
{
njsDbObjectType *objType;
njsDbObject *obj;
int32_t size;
if (!njsDbObject_validateArgs(env, info, 0, NULL, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 0, NULL, NULL, &obj))
return NULL;
if (dpiObject_getSize(obj->handle, &size) < 0) {
njsUtils_throwErrorDPI(env, obj->type->oracleDb);
@ -442,12 +442,11 @@ static napi_value njsDbObject_getNextIndex(napi_env env,
napi_callback_info info)
{
napi_value args[1], value = NULL;
njsDbObjectType *objType;
njsDbObject *obj;
int32_t index;
int exists;
if (!njsDbObject_validateArgs(env, info, 1, args, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 1, args, NULL, &obj))
return NULL;
if (!njsUtils_getIntArg(env, args, 0, &index))
return NULL;
@ -471,12 +470,11 @@ static napi_value njsDbObject_getPrevIndex(napi_env env,
napi_callback_info info)
{
napi_value args[1], value = NULL;
njsDbObjectType *objType;
njsDbObject *obj;
int32_t index;
int exists;
if (!njsDbObject_validateArgs(env, info, 1, args, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 1, args, NULL, &obj))
return NULL;
if (!njsUtils_getIntArg(env, args, 0, &index))
return NULL;
@ -572,7 +570,6 @@ static napi_value njsDbObject_getValues(napi_env env, napi_callback_info info)
static bool njsDbObject_getValuesHelper(napi_env env, napi_callback_info info,
napi_value *returnValue)
{
njsDbObjectType *objType = NULL;
int32_t index, exists, size;
napi_value arr, temp;
uint32_t arrayPos;
@ -580,7 +577,7 @@ static bool njsDbObject_getValuesHelper(napi_env env, napi_callback_info info,
dpiData data;
// get object instance from caller
if (!njsDbObject_validateArgs(env, info, 0, NULL, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 0, NULL, NULL, &obj))
return false;
// determine the size of the collection and create an array of that length
@ -595,10 +592,10 @@ static bool njsDbObject_getValuesHelper(napi_env env, napi_callback_info info,
return njsUtils_throwErrorDPI(env, obj->type->oracleDb);
while (exists) {
if (dpiObject_getElementValueByIndex(obj->handle, index,
objType->elementTypeInfo.nativeTypeNum, &data) < 0)
obj->type->elementTypeInfo.nativeTypeNum, &data) < 0)
return njsUtils_throwErrorDPI(env, obj->type->oracleDb);
if (!njsDbObject_transformFromOracle(obj, env,
&objType->elementTypeInfo, &data, &temp, NULL))
&obj->type->elementTypeInfo, &data, &temp, NULL))
return false;
NJS_CHECK_NAPI(env, napi_set_element(env, arr, arrayPos++, temp))
if (dpiObject_getNextIndex(obj->handle, index, &index, &exists) < 0)
@ -616,13 +613,12 @@ static bool njsDbObject_getValuesHelper(napi_env env, napi_callback_info info,
//-----------------------------------------------------------------------------
static napi_value njsDbObject_hasElement(napi_env env, napi_callback_info info)
{
njsDbObjectType *objType = NULL;
napi_value args[1], result;
njsDbObject *obj;
int32_t index;
int exists;
if (!njsDbObject_validateArgs(env, info, 1, args, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 1, args, NULL, &obj))
return NULL;
if (!njsUtils_getIntArg(env, args, 0, &index))
return NULL;
@ -692,7 +688,7 @@ static bool njsDbObject_setAttrValueHelper(napi_env env,
int status;
// get object instance and validate number of arguments
if (!njsDbObject_validateArgs(env, info, 1, &value, NULL, &attr, &obj))
if (!njsDbObject_validateArgs(env, info, 1, &value, &attr, &obj))
return false;
// transform to value required by ODPI-C
@ -719,7 +715,6 @@ static bool njsDbObject_setAttrValueHelper(napi_env env,
//-----------------------------------------------------------------------------
static napi_value njsDbObject_setElement(napi_env env, napi_callback_info info)
{
njsDbObjectType *objType = NULL;
dpiNativeTypeNum nativeTypeNum;
napi_value args[2];
njsDbObject *obj;
@ -728,11 +723,11 @@ static napi_value njsDbObject_setElement(napi_env env, napi_callback_info info)
dpiData data;
int status;
if (!njsDbObject_validateArgs(env, info, 2, args, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 2, args, NULL, &obj))
return NULL;
if (!njsUtils_getIntArg(env, args, 0, &index))
return NULL;
nativeTypeNum = objType->elementTypeInfo.nativeTypeNum;
nativeTypeNum = obj->type->elementTypeInfo.nativeTypeNum;
if (!njsDbObject_transformToOracle(obj, env, args[1], &nativeTypeNum,
&data, &str, NULL))
return NULL;
@ -974,12 +969,11 @@ static bool njsDbObject_transformToOracle(njsDbObject *obj, napi_env env,
//-----------------------------------------------------------------------------
static napi_value njsDbObject_trim(napi_env env, napi_callback_info info)
{
njsDbObjectType *objType = NULL;
uint32_t numToTrim;
napi_value args[1];
njsDbObject *obj;
if (!njsDbObject_validateArgs(env, info, 1, args, &objType, NULL, &obj))
if (!njsDbObject_validateArgs(env, info, 1, args, NULL, &obj))
return NULL;
if (!njsUtils_getUnsignedIntArg(env, args, 0, &numToTrim))
return NULL;
@ -997,8 +991,8 @@ static napi_value njsDbObject_trim(napi_env env, napi_callback_info info)
// all. In that case, a new instance is created and associated with the object.
//-----------------------------------------------------------------------------
static bool njsDbObject_validateArgs(napi_env env, napi_callback_info info,
size_t numArgs, napi_value *args, njsDbObjectType **objType,
njsDbObjectAttr **attr, njsDbObject **obj)
size_t numArgs, napi_value *args, njsDbObjectAttr **attr,
njsDbObject **obj)
{
njsOracleDb *oracleDb;
napi_value thisArg;
@ -1012,14 +1006,13 @@ static bool njsDbObject_validateArgs(napi_env env, napi_callback_info info,
if (actualArgs != numArgs)
return njsUtils_throwError(env, errInvalidNumberOfParameters);
// data will either be an object type or an attribute, determined by which
// pointer is not NULL
// data will either be an attribute or a pointer to the global njsOracleDb
// instance
if (attr) {
*attr = (njsDbObjectAttr*) data;
oracleDb = (*attr)->oracleDb;
} else {
*objType = (njsDbObjectType*) data;
oracleDb = (*objType)->oracleDb;
oracleDb = (njsOracleDb*) data;
}
return njsDbObject_getInstance(oracleDb, env, thisArg, obj);
@ -1105,25 +1098,17 @@ static void njsDbObjectType_finalize(napi_env env, void *finalizeData,
//-----------------------------------------------------------------------------
// njsDbObjectType_getFromClass()
// Acquires the object type from a class. The object type instance is stored
// on the prototype so a new instance needs to be created, the prototype
// acquired from that new instance, and then the object type instance
// unwrapped. There is a slight complication, however, in that collections are
// proxied, so we need to acquire the actual target first.
// Acquires the object type from a class by acquiring the prototype and then
// unwrapping it to find the object type instance.
//-----------------------------------------------------------------------------
bool njsDbObjectType_getFromClass(napi_env env, napi_value cls,
njsDbObjectType **objType)
{
napi_value prototype, temp, tempObj;
napi_value prototype;
NJS_CHECK_NAPI(env, napi_new_instance(env, cls, 0, NULL, &tempObj))
NJS_CHECK_NAPI(env, napi_get_prototype(env, tempObj, &prototype))
if (napi_unwrap(env, prototype, (void**) objType) != napi_ok) {
NJS_CHECK_NAPI(env, napi_get_named_property(env, tempObj, "_target",
&temp))
NJS_CHECK_NAPI(env, napi_get_prototype(env, temp, &prototype))
NJS_CHECK_NAPI(env, napi_unwrap(env, prototype, (void**) objType))
}
NJS_CHECK_NAPI(env, napi_get_named_property(env, cls, "prototype",
&prototype))
NJS_CHECK_NAPI(env, napi_unwrap(env, prototype, (void**) objType))
return true;
}
@ -1139,9 +1124,9 @@ static bool njsDbObjectType_populate(njsDbObjectType *objType,
{
dpiObjectAttr **attrHandles;
dpiObjectAttrInfo attrInfo;
size_t numProperties, p;
napi_value attrs, temp;
njsDbObjectAttr *attr;
size_t numProperties;
napi_value element;
uint16_t i;
@ -1178,28 +1163,9 @@ static bool njsDbObjectType_populate(njsDbObjectType *objType,
}
// determine the number of descriptors to create; collections use a
// standard set of descriptors, whereas objects with attributes have one
// property created for each attribute; both types always have one extra
// descriptor to create a copy of an object
if (info->isCollection) {
for (numProperties = 0;
njsCollectionProperties[numProperties].utf8name;
numProperties++);
} else {
numProperties = info->numAttributes;
}
numProperties++;
objType->descriptors = calloc(numProperties,
sizeof(napi_property_descriptor));
if (!objType->descriptors)
return njsBaton_setError(baton, errInsufficientMemory);
objType->descriptors[0].utf8name = "copy";
objType->descriptors[0].method = njsDbObject_copy;
objType->descriptors[0].data = objType;
// process collections object types
if (info->isCollection) {
numProperties = 0;
if (!njsDbObjectType_populateTypeInfo(&objType->elementTypeInfo,
baton, env, &info->elementTypeInfo))
return false;
@ -1207,13 +1173,14 @@ static bool njsDbObjectType_populate(njsDbObjectType *objType,
info->elementTypeInfo.oracleTypeNum,
objType->elementTypeInfo.objectType))
return false;
memcpy(&objType->descriptors[1], njsCollectionProperties,
(numProperties - 1) * sizeof(napi_property_descriptor));
for (p = 1; p < numProperties; p++)
objType->descriptors[p].data = objType;
// process object types with attributes
} else {
numProperties = info->numAttributes;
objType->descriptors = calloc(numProperties,
sizeof(napi_property_descriptor));
if (!objType->descriptors)
return njsBaton_setError(baton, errInsufficientMemory);
NJS_CHECK_NAPI(env, napi_create_object(env, &attrs))
for (i = 0; i < info->numAttributes; i++) {
attr = &objType->attributes[i];
@ -1232,20 +1199,20 @@ static bool njsDbObjectType_populate(njsDbObjectType *objType,
return false;
NJS_CHECK_NAPI(env, napi_create_string_utf8(env, attrInfo.name,
attrInfo.nameLength, &temp))
objType->descriptors[i + 1].name = temp;
objType->descriptors[i + 1].getter = njsDbObject_getAttrValue;
objType->descriptors[i + 1].setter = njsDbObject_setAttrValue;
objType->descriptors[i + 1].data = &objType->attributes[i];
objType->descriptors[i].name = temp;
objType->descriptors[i].getter = njsDbObject_getAttrValue;
objType->descriptors[i].setter = njsDbObject_setAttrValue;
objType->descriptors[i].data = &objType->attributes[i];
NJS_CHECK_NAPI(env, napi_set_property(env, attrs, temp, element))
}
NJS_CHECK_NAPI(env, napi_set_named_property(env, jsObjectType,
"attributes", attrs))
if (numProperties > 0) {
NJS_CHECK_NAPI(env, napi_define_properties(env, jsObjectType,
numProperties, objType->descriptors))
}
}
// define properties
NJS_CHECK_NAPI(env, napi_define_properties(env, jsObjectType,
numProperties, objType->descriptors))
// keep a reference to the constructor
NJS_CHECK_NAPI(env, napi_get_named_property(env, jsObjectType,
"constructor", &temp))

View File

@ -68,6 +68,9 @@ static napi_value njsModule_externalInit(napi_env env, napi_callback_info info)
if (!njsOracleDb_prepareClass(oracleDb, env, instance,
&njsClassDefAqQueue, &oracleDb->jsAqQueueConstructor))
return NULL;
if (!njsOracleDb_prepareClass(oracleDb, env, instance,
&njsClassDefBaseDbObject, &oracleDb->jsBaseDbObjectConstructor))
return NULL;
if (!njsOracleDb_prepareClass(oracleDb, env, instance,
&njsClassDefConnection, &oracleDb->jsConnectionConstructor))
return NULL;

View File

@ -253,6 +253,7 @@ extern const njsClassDef njsClassDefAqDeqOptions;
extern const njsClassDef njsClassDefAqEnqOptions;
extern const njsClassDef njsClassDefAqMessage;
extern const njsClassDef njsClassDefAqQueue;
extern const njsClassDef njsClassDefBaseDbObject;
extern const njsClassDef njsClassDefConnection;
extern const njsClassDef njsClassDefLob;
extern const njsClassDef njsClassDefOracleDb;

View File

@ -1122,12 +1122,6 @@ bool njsOracleDb_new(napi_env env, napi_value instanceObj,
return njsUtils_genericThrowError(env);
}
// keep a reference to the base database object class
NJS_CHECK_NAPI(env, napi_get_named_property(env, instanceObj,
"BaseDbObject", &temp))
NJS_CHECK_NAPI(env, napi_create_reference(env, temp, 1,
&oracleDb->jsBaseDbObjectConstructor))
// create object for storing subscriptions
NJS_CHECK_NAPI(env, napi_create_object(env, &temp))
NJS_CHECK_NAPI(env, napi_create_reference(env, temp, 1,
@ -1179,6 +1173,10 @@ bool njsOracleDb_prepareClass(njsOracleDb *oracleDb, napi_env env,
return false;
}
// store the instance on each of the properties as a convenience
for (i = 0; i < numProperties; i++)
allProperties[i].data = oracleDb;
// populate the properties
memcpy(allProperties, classDef->properties,
sizeof(napi_property_descriptor) * numBaseProperties);