Browse Source

move datasource into the variablenode, not the variant

Julius Pfrommer 10 years ago
parent
commit
277ceae206

+ 0 - 1
examples/server.c

@@ -25,7 +25,6 @@ static void stopHandler(int sign) {
 }
 
 static UA_ByteString loadCertificate(void) {
-
     UA_ByteString certificate = UA_STRING_NULL;
 	FILE *fp = NULL;
 	//FIXME: a potiential bug of locating the certificate, we need to get the path from the server's config

+ 14 - 20
examples/server_datasource.c

@@ -26,6 +26,7 @@ static UA_StatusCode readTimeData(const void *handle, UA_DataValue *value) {
     if(!currentTime)
         return UA_STATUSCODE_BADOUTOFMEMORY;
     *currentTime = UA_DateTime_now();
+    value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
     value->value.arrayLength = 1;
     value->value.dataPtr = currentTime;
     value->value.arrayDimensionsSize = -1;
@@ -38,10 +39,6 @@ static void releaseTimeData(const void *handle, UA_DataValue *value) {
     UA_DateTime_delete((UA_DateTime*)value->value.dataPtr);
 }
 
-static UA_StatusCode writeTimeData(const void *handle, const UA_Variant *data) {
-    return UA_STATUSCODE_BADINTERNALERROR;
-}
-
 /**************************/
 /* Read/write data source */
 /**************************/
@@ -56,6 +53,7 @@ static UA_StatusCode readDeviceStatus(const void *handle, UA_DataValue *value) {
     /* In order to reduce blocking time, we could alloc memory for every read
        and return a copy of the data. */
     pthread_rwlock_rdlock(&deviceStatusLock);
+    value->value.type = &UA_TYPES[UA_TYPES_INT32];
     value->value.arrayLength = 1;
     value->value.dataPtr = &deviceStatus;
     value->value.arrayDimensionsSize = -1;
@@ -97,35 +95,31 @@ int main(int argc, char** argv) {
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
 
     // add node with the datetime data source
-    UA_Variant *dateVariant = UA_Variant_new();
-    dateVariant->storage.datasource = (UA_DataSource)
-        {.handle = UA_NULL,
+    UA_DataSource dateDataSource = (UA_DataSource)
+        {.handle = NULL,
          .read = readTimeData,
          .release = releaseTimeData,
-         .write = writeTimeData};
-    dateVariant->type = &UA_TYPES[UA_TYPES_DATETIME];
+         .write = NULL};
     UA_QualifiedName dateName;
     UA_QUALIFIEDNAME_ASSIGN(dateName, "the time");
-    UA_Server_addVariableNode(server, dateVariant, &UA_NODEID_NULL, &dateName,
-                              &UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
-                              &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+    UA_Server_addDataSourceVariableNode(server, dateDataSource, &UA_NODEID_NULL, &dateName,
+                                        &UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
 
     // print the status every 2 sec
-    UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL, .work.methodCall = {.method = printDeviceStatus, .data = UA_NULL} };
-    UA_Server_addRepeatedWorkItem(server, &work, 20000000, UA_NULL);
+    UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
+                        .work.methodCall = {.method = printDeviceStatus, .data = NULL} };
+    UA_Server_addRepeatedWorkItem(server, &work, 20000000, NULL);
 
     // add node with the device status data source
-    UA_Variant *statusVariant = UA_Variant_new();
-    statusVariant->storageType = UA_VARIANT_DATASOURCE;
-    statusVariant->storage.datasource = (UA_VariantDataSource)
-        {.handle = UA_NULL,
+    UA_DataSource deviceStatusDataSource = (UA_DataSource)
+        {.handle = NULL,
          .read = readDeviceStatus,
          .release = releaseDeviceStatus,
          .write = writeDeviceStatus};
-    statusVariant->type = &UA_TYPES[UA_TYPES_INT32];
     UA_QualifiedName statusName;
     UA_QUALIFIEDNAME_ASSIGN(statusName, "device status");
-    UA_Server_addVariableNode(server, statusVariant, &UA_NODEID_NULL, &statusName,
+    UA_Server_addDataSourceVariableNode(server, deviceStatusDataSource, &UA_NODEID_NULL, &statusName,
                               &UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
                               &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
 

+ 21 - 12
include/ua_server.h

@@ -55,20 +55,17 @@ void UA_EXPORT UA_Server_delete(UA_Server *server);
  */
 UA_StatusCode UA_EXPORT UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running);
 
-/** Add a reference to the server's address space */
-UA_StatusCode UA_EXPORT UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item);
-
-UA_StatusCode UA_EXPORT UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, UA_NodeId *nodeId,
-                                                  UA_QualifiedName *browseName, const UA_NodeId *parentNodeId,
-                                                  const UA_NodeId *referenceTypeId);
-
 /** @brief A datasource is the interface to interact with a local data provider.
  *
- *  Implementors of datasources need to provide functions for the callbacks in
- *  this structure. After every read, the handle needs to be released to
- *  indicate that the pointer is no longer accessed. As a rule, datasources are
- *  never copied, but only their content. The only way to write into a
- *  datasource is via the write-service. */
+ * Implementors of datasources need to provide functions for the callbacks in
+ * this structure. After every read, the handle needs to be released to indicate
+ * that the pointer is no longer accessed. As a rule, datasources are never
+ * copied, but only their content. The only way to write into a datasource is
+ * via the write-service.
+ *
+ * It is expected that the read and release callbacks are implemented. The write
+ * callback can be set to null.
+ **/
 typedef struct {
     const void *handle;
     UA_StatusCode (*read)(const void *handle, UA_DataValue *value);
@@ -76,6 +73,18 @@ typedef struct {
     UA_StatusCode (*write)(const void *handle, const UA_Variant *data);
 } UA_DataSource;
 
+/** Add a reference to the server's address space */
+UA_StatusCode UA_EXPORT UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item);
+
+UA_StatusCode UA_EXPORT UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, UA_NodeId *nodeId,
+                                                  UA_QualifiedName *browseName, const UA_NodeId *parentNodeId,
+                                                  const UA_NodeId *referenceTypeId);
+
+UA_StatusCode UA_EXPORT UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
+                                                            UA_NodeId *nodeId, UA_QualifiedName *browseName,
+                                                            const UA_NodeId *parentNodeId,
+                                                            const UA_NodeId *referenceTypeId);
+
 /** Work that is run in the main loop (singlethreaded) or dispatched to a worker
     thread. */
 typedef struct UA_WorkItem {

+ 6 - 9
src/server/ua_nodes.h

@@ -34,6 +34,11 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectTypeNode)
 
 typedef struct {
     UA_STANDARD_NODEMEMBERS
+    UA_Int32 valueRank; /**< n >= 1: the value is an array with the specified number of dimensions.
+                             n = 0: the value is an array with one or more dimensions.
+                             n = -1: the value is a scalar.
+                             n = -2: the value can be a scalar or an array with any number of dimensions.
+                             n = -3:  the value can be a scalar or a one dimensional array. */
     enum {
         UA_VARIABLETYPE_VARIANT,
         UA_VARIABLETYPE_DATASOURCE
@@ -42,12 +47,6 @@ typedef struct {
         UA_Variant variant;
         UA_DataSource dataSource;
     } variable;
-    UA_Int32 valueRank; /**< n >= 1: the value is an array with the specified number of dimensions.
-                             n = 0: the value is an array with one or more dimensions.
-                             n = -1: the value is a scalar.
-                             n = -2: the value can be a scalar or an array with any number of dimensions.
-                             n = -3:  the value can be a scalar or a one dimensional array. */
-    // array dimensions are taken from the value-variant
     UA_Byte accessLevel;
     UA_Byte userAccessLevel;
     UA_Double minimumSamplingInterval;
@@ -57,10 +56,8 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_VariableNode)
 
 typedef struct {
     UA_STANDARD_NODEMEMBERS
-    UA_Variant value;
-    // datatype is taken from the value
     UA_Int32 valueRank;
-    // array dimensions are taken from the value-variant
+    UA_Variant value;
     UA_Boolean isAbstract;
 } UA_VariableTypeNode;
 UA_TYPE_HANDLING_FUNCTIONS(UA_VariableTypeNode)

+ 19 - 18
src/server/ua_server.c

@@ -69,7 +69,7 @@ void UA_Server_delete(UA_Server *server) {
     UA_free(server);
 }
 
-static UA_StatusCode readStatus(const void *handle, UA_VariantData *data) {
+static UA_StatusCode readStatus(const void *handle, UA_DataValue *value) {
     UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
     status->startTime   = ((const UA_Server*)handle)->timeStarted;
     status->currentTime = UA_DateTime_now();
@@ -82,13 +82,19 @@ static UA_StatusCode readStatus(const void *handle, UA_VariantData *data) {
     status->buildInfo.buildDate = UA_DateTime_now();
     status->secondsTillShutdown = 0;
 
-	data->arrayLength = 1;
-    data->dataPtr = status;
-    data->arrayDimensionsSize = -1;
-    data->arrayDimensions = UA_NULL;
+    value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
+	value->value.arrayLength = 1;
+    value->value.dataPtr = status;
+    value->value.arrayDimensionsSize = -1;
+    value->value.arrayDimensions = UA_NULL;
+    value->hasVariant = UA_TRUE;
     return UA_STATUSCODE_GOOD;
 }
 
+static void releaseStatus(const void *handle, UA_DataValue *value) {
+    UA_DataValue_deleteMembers(value);
+}
+
 UA_Server * UA_Server_new(void) {
     UA_Server *server = UA_malloc(sizeof(UA_Server));
     if(!server)
@@ -633,19 +639,14 @@ UA_Server * UA_Server_new(void) {
                       &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASPROPERTY));
 
-    UA_Variant *serverstatus = UA_Variant_new();
-    serverstatus->storageType = UA_VARIANT_DATASOURCE;
-    serverstatus->storage.datasource = (UA_VariantDataSource)
-        {.handle = server,
-         .read = readStatus,
-         .release = UA_NULL,
-         .write = UA_NULL};
-    serverstatus->type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
-    UA_QualifiedName serverstatusname;
-    UA_QUALIFIEDNAME_ASSIGN(serverstatusname, "ServerStatus");
-    UA_Server_addVariableNode(server, serverstatus, &UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS), &serverstatusname,
-    							&UA_NODEID_STATIC(0, UA_NS0ID_SERVER),
-    							&UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT));
+    UA_VariableNode *serverstatus = UA_VariableNode_new();
+    COPYNAMES(serverstatus, "ServerStatus");
+    serverstatus->nodeId = UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS);
+    serverstatus->variableType = UA_VARIABLETYPE_DATASOURCE;
+    serverstatus->variable.dataSource = (UA_DataSource) {.handle = server, .read = readStatus,
+                                                         .release = releaseStatus, .write = UA_NULL};
+    UA_Server_addNode(server, (UA_Node*)serverstatus, &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT));
 
     UA_VariableNode *state = UA_VariableNode_new();
     UA_ServerState *stateEnum = UA_ServerState_new();

+ 23 - 0
src/server/ua_server_addressspace.c

@@ -25,6 +25,29 @@ UA_StatusCode UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, UA
     return res.statusCode;
 }
 
+UA_StatusCode UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
+                                                  UA_NodeId *nodeId, UA_QualifiedName *browseName,
+                                                  const UA_NodeId *parentNodeId,
+                                                  const UA_NodeId *referenceTypeId) {
+    UA_VariableNode *node = UA_VariableNode_new();
+    node->variableType = UA_VARIABLETYPE_DATASOURCE;
+    node->variable.dataSource = dataSource;
+    UA_NodeId_copy(nodeId, &node->nodeId);
+    UA_QualifiedName_copy(browseName, &node->browseName);
+    UA_String_copy(&browseName->name, &node->displayName.text);
+    UA_ExpandedNodeId parentId; // we need an expandednodeid
+    UA_ExpandedNodeId_init(&parentId);
+    parentId.nodeId = *parentNodeId;
+    UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
+                                                         &parentId, referenceTypeId);
+    ADDREFERENCE(res.addedNodeId, UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+    if(res.statusCode != UA_STATUSCODE_GOOD) {
+        UA_VariableNode_delete(node);
+    }
+    return res.statusCode;
+}
+
 /* Adds a one-way reference to the local nodestore */
 static UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session *session,
                                                    const UA_AddReferencesItem *item) {

+ 73 - 75
src/server/ua_services_attribute.c

@@ -127,8 +127,27 @@ static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue
     case UA_ATTRIBUTEID_DATATYPE:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableTypeNode *)node)->value.type->typeId,
-                                          UA_TYPES_NODEID);
+        if(node->nodeClass == UA_NODECLASS_VARIABLETYPE)
+            retval |= UA_Variant_copySetValue(&v->value,
+                                              &((const UA_VariableTypeNode *)node)->value.type->typeId,
+                                              UA_TYPES_NODEID);
+        else {
+            const UA_VariableNode *vn = (const UA_VariableNode*)node;
+            if(vn->variableType == UA_VARIABLETYPE_VARIANT)
+                retval |= UA_Variant_copySetValue(&v->value, &vn->variable.variant.type->typeId,
+                                                  UA_TYPES_NODEID);
+            else {
+                UA_DataValue val;
+                UA_DataValue_init(&val);
+                retval |= vn->variable.dataSource.read(vn->variable.dataSource.handle, &val);
+                if(retval != UA_STATUSCODE_GOOD)
+                    break;
+                retval |= UA_Variant_copySetValue(&v->value, &val.value.type->typeId, UA_TYPES_NODEID);
+                vn->variable.dataSource.release(vn->variable.dataSource.handle, &val);
+                if(retval != UA_STATUSCODE_GOOD)
+                    break;
+            }
+        }
         break;
 
     case UA_ATTRIBUTEID_VALUERANK:
@@ -309,56 +328,6 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
         if(!node)
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
-        UA_Node* (*newNode)(void);
-        void (*deleteNode)(UA_Node*);
-        UA_StatusCode (*copyNode)(const UA_Node*, UA_Node*);
-
-        switch(node->nodeClass) {
-        case UA_NODECLASS_OBJECT:
-            newNode = (UA_Node *(*)(void))UA_ObjectNode_new;
-            deleteNode = (void (*)(UA_Node*))UA_ObjectNode_delete;
-            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_ObjectNode_copy;
-            break;
-        case UA_NODECLASS_VARIABLE:
-            newNode = (UA_Node *(*)(void))UA_VariableNode_new;
-            deleteNode = (void (*)(UA_Node*))UA_VariableNode_delete;
-            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_VariableNode_copy;
-            break;
-        case UA_NODECLASS_METHOD:
-            newNode = (UA_Node *(*)(void))UA_MethodNode_new;
-            deleteNode = (void (*)(UA_Node*))UA_MethodNode_delete;
-            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_MethodNode_copy;
-            break;
-        case UA_NODECLASS_OBJECTTYPE:
-            newNode = (UA_Node *(*)(void))UA_ObjectTypeNode_new;
-            deleteNode = (void (*)(UA_Node*))UA_ObjectTypeNode_delete;
-            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_ObjectTypeNode_copy;
-            break;
-        case UA_NODECLASS_VARIABLETYPE:
-            newNode = (UA_Node *(*)(void))UA_VariableTypeNode_new;
-            deleteNode = (void (*)(UA_Node*))UA_VariableTypeNode_delete;
-            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_VariableTypeNode_copy;
-            break;
-        case UA_NODECLASS_REFERENCETYPE:
-            newNode = (UA_Node *(*)(void))UA_ReferenceTypeNode_new;
-            deleteNode = (void (*)(UA_Node*))UA_ReferenceTypeNode_delete;
-            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_ReferenceTypeNode_copy;
-            break;
-        case UA_NODECLASS_DATATYPE:
-            newNode = (UA_Node *(*)(void))UA_DataTypeNode_new;
-            deleteNode = (void (*)(UA_Node*))UA_DataTypeNode_delete;
-            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_DataTypeNode_copy;
-            break;
-        case UA_NODECLASS_VIEW:
-            newNode = (UA_Node *(*)(void))UA_ViewNode_new;
-            deleteNode = (void (*)(UA_Node*))UA_ViewNode_delete;
-            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_ViewNode_copy;
-            break;
-        default:
-            UA_NodeStore_release(node);
-            return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
-        }
-
         switch(wvalue->attributeId) {
         case UA_ATTRIBUTEID_NODEID:
         case UA_ATTRIBUTEID_NODECLASS:
@@ -375,47 +344,76 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
             retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
             break;
         case UA_ATTRIBUTEID_VALUE:
-            if((node->nodeClass != UA_NODECLASS_VARIABLE) && (node->nodeClass != UA_NODECLASS_VARIABLETYPE)) {
-                retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-                break;
-            }
+            if(node->nodeClass == UA_NODECLASS_VARIABLE) {
+                const UA_VariableNode *vn = (const UA_VariableNode*)node;
+                if(vn->variableType == UA_VARIABLETYPE_DATASOURCE) {
+                    if(!vn->variable.dataSource.write) {
+                        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+                        break;
+                    }
+                    retval = vn->variable.dataSource.write(vn->variable.dataSource.handle, &wvalue->value.value);
+                    done = UA_TRUE;
+                    break;
+                }
 
-            const UA_VariableNode *vn = (const UA_VariableNode*)node;
-            if(vn->variableType == UA_VARIABLETYPE_DATASOURCE) {
-                retval = vn->variable.dataSource.write(vn->variable.dataSource.handle,
-                                                       &wvalue->value.value);
-                done = UA_TRUE;
-            } else {
-                // has the wvalue a variant of the right type?
-                // array sizes are not checked yet..
-                if(!wvalue->value.hasVariant ||
-                   !UA_NodeId_equal(&vn->variable.variant.type->typeId,
-                                    &wvalue->value.value.type->typeId)) {
+                // array sizes are not checked to match
+                if(!wvalue->value.hasVariant || !UA_NodeId_equal(&vn->variable.variant.type->typeId,
+                                                                 &wvalue->value.value.type->typeId)) {
                     retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
                     break;
                 }
 
-                // could be a variable or variabletype node. They fit for the value.. member
-                UA_VariableNode *newVn = (UA_VariableNode*)newNode();
+                UA_VariableNode *newVn = UA_VariableNode_new();
                 if(!newVn) {
                     retval = UA_STATUSCODE_BADOUTOFMEMORY;
                     break;
                 }
-                retval = copyNode((const UA_Node*)vn, (UA_Node*)newVn);
+                retval = UA_VariableNode_copy(vn, newVn);
                 if(retval != UA_STATUSCODE_GOOD) {
-                    deleteNode((UA_Node*)newVn);
+                    UA_VariableNode_delete(newVn);
                     break;
                 }
                 retval = UA_Variant_copy(&wvalue->value.value, &newVn->variable.variant);
                 if(retval != UA_STATUSCODE_GOOD) {
-                    deleteNode((UA_Node*)newVn);
+                    UA_VariableNode_delete(newVn);
+                    break;
+                }
+                if(UA_NodeStore_replace(server->nodestore, node, (UA_Node*)newVn,
+                                        UA_NULL) == UA_STATUSCODE_GOOD)
+                    done = UA_TRUE;
+                else
+                    UA_VariableNode_delete(newVn);
+            } else if(node->nodeClass == UA_NODECLASS_VARIABLETYPE) {
+                const UA_VariableTypeNode *vtn = (const UA_VariableTypeNode*)node;
+                if(!wvalue->value.hasVariant || !UA_NodeId_equal(&vtn->value.type->typeId,
+                                                                 &wvalue->value.value.type->typeId)) {
+                    retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+                    break;
+                }
+
+                UA_VariableTypeNode *newVtn = UA_VariableTypeNode_new();
+                if(!newVtn) {
+                    retval = UA_STATUSCODE_BADOUTOFMEMORY;
+                    break;
+                }
+                retval = UA_VariableTypeNode_copy(vtn, newVtn);
+                if(retval != UA_STATUSCODE_GOOD) {
+                    UA_VariableTypeNode_delete(newVtn);
                     break;
                 }
-                if(UA_NodeStore_replace(server->nodestore,node,(UA_Node*)newVn,UA_NULL) == UA_STATUSCODE_GOOD)
+                retval = UA_Variant_copy(&wvalue->value.value, &newVtn->value);
+                if(retval != UA_STATUSCODE_GOOD) {
+                    UA_VariableTypeNode_delete(newVtn);
+                    break;
+                }
+                if(UA_NodeStore_replace(server->nodestore, node, (UA_Node*)newVtn,
+                                        UA_NULL) == UA_STATUSCODE_GOOD)
                     done = UA_TRUE;
                 else
-                    deleteNode((UA_Node*)newVn);
-            } 
+                    UA_VariableTypeNode_delete(newVtn);
+            } else {
+                retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+            }
             break;
         case UA_ATTRIBUTEID_DATATYPE:
         case UA_ATTRIBUTEID_VALUERANK: