in Unix/base/instance.c [589:956]
MI_Result MI_CALL Instance_InitConvert(
MI_Instance* self_,
const MI_ClassDecl* cd1,
const MI_Instance* inst_,
MI_Boolean keysOnly,
MI_Boolean allowKeylessInst,
MI_Boolean copy,
Batch* batch_,
MI_Uint32 flags)
{
Instance* self;
const Instance* inst = _SelfOf(inst_);
MI_Uint32 i;
MI_Result r;
const MI_ClassDecl* cd2;
const MI_SchemaDecl* sd1;
Batch* batch = batch_;
/* Check parameters */
if (!self_ || !cd1 || !inst)
MI_RETURN(MI_RESULT_INVALID_PARAMETER);
/* Create a new batch */
if (!batch)
{
batch = Batch_New(_NUM_PAGES);
if (!batch)
return MI_RESULT_SERVER_LIMITS_EXCEEDED;
}
/* Resolve the schema declaration (based on type) */
if (cd1->flags & MI_FLAG_METHOD)
sd1 = ((MI_MethodDecl*)cd1)->schema;
else if (cd1->flags & MI_FLAG_CLASS)
sd1 = cd1->schema;
else
{
return MI_RESULT_FAILED;
}
cd2 = inst->classDecl;
/* Initialize the instance */
r = Instance_Construct(self_, cd1, batch);
if (r != MI_RESULT_OK)
{
goto failed;
}
/* Get the self pointer from the newly initialized instance */
self = _SelfOf(self_);
/* Arrange to release the batch */
self->releaseBatch = batch == batch_ ? MI_FALSE : MI_TRUE;
/* Copy the nameSpace */
if (inst->nameSpace)
{
self->nameSpace = BStrdup(batch, inst->nameSpace, CALLSITE);
if (!self->nameSpace)
{
r = MI_RESULT_SERVER_LIMITS_EXCEEDED;
goto failed;
}
}
/* Copy the serverName */
if (inst->serverName)
{
self->serverName = BStrdup(batch, inst->serverName, CALLSITE);
if (!self->serverName)
{
r = MI_RESULT_SERVER_LIMITS_EXCEEDED;
goto failed;
}
}
/* Validate that the two instances share the same key structure */
if (!allowKeylessInst)
{
for (i = 0; i < cd1->numProperties; i++)
{
const MI_PropertyDecl* pd1 = cd1->properties[i];
if (pd1->flags & MI_FLAG_KEY)
{
MI_Uint32 index;
index = _FindPropertyDecl(cd2, pd1->name);
if (index == (MI_Uint32)-1)
{
if (pd1->value)
{
//add default key value
MI_Value* value = (MI_Value*)pd1->value;
r = MI_Instance_SetElementAt(self_, i, value, pd1->type, MI_FLAG_BORROW);
if (r != MI_RESULT_OK)
{
goto failed;
}
}
else
{
r = MI_RESULT_NO_SUCH_PROPERTY;
goto failed;
}
}
}
}
for (i = 0; i < cd2->numProperties; i++)
{
const MI_PropertyDecl* pd2 = cd2->properties[i];
if (pd2->flags & MI_FLAG_KEY)
{
MI_Uint32 index;
index = _FindPropertyDecl(cd1, pd2->name);
if (index == (MI_Uint32)-1)
{
r = MI_RESULT_NO_SUCH_PROPERTY;
goto failed;
}
}
}
}
/* ATTN: ignore unknown properties? */
/* Set non-null properties */
for (i = 0; i < cd2->numProperties; i++)
{
const MI_PropertyDecl* pd2 = cd2->properties[i];
Field* field = (Field*)((char*)inst + pd2->offset);
/* If requested, ignore non-keys */
if (keysOnly && !(pd2->flags & MI_FLAG_KEY))
continue;
/* Set the non-null key values */
if (Field_GetExists(field, pd2->type))
{
if (pd2->type == MI_STRING)
{
r = Instance_SetElementFromString(self_, pd2->name,
((MI_Value*)field)->string, flags);
if (r != MI_RESULT_OK)
{
goto failed;
}
}
else if (pd2->type == MI_STRINGA)
{
r = Instance_SetElementFromStringA(self_, pd2->name,
(const ZChar**)((MI_Value*)field)->stringa.data,
((MI_Value*)field)->stringa.size,
flags);
if (r != MI_RESULT_OK)
{
goto failed;
}
}
else if (pd2->type == MI_INSTANCE || pd2->type == MI_REFERENCE)
{
MI_Instance* tmpInst;
MI_ClassDecl* tmpCd;
MI_Type type;
MI_Boolean allowKeylessEmbedInst = (pd2->type == MI_INSTANCE) ? MI_TRUE : MI_FALSE;
/* Find the class declaration in the schema */
tmpCd = SchemaDecl_FindClassDecl(sd1,
_SelfOf(((MI_Value*)field)->instance)->classDecl->name);
if (!tmpCd)
{
r = MI_RESULT_NO_SUCH_PROPERTY;
goto failed;
}
/* Allocate static instance of this class */
r = Instance_New(&tmpInst, tmpCd, batch);
if (r != MI_RESULT_OK)
{
goto failed;
}
/* Convert instance */
r = Instance_InitConvert(tmpInst, tmpCd,
((MI_Value*)field)->instance, keysOnly, allowKeylessEmbedInst, copy,
((Instance*)tmpInst)->batch, flags);
if (r != MI_RESULT_OK)
{
__MI_Instance_Delete(tmpInst);
goto failed;
}
/* Get the target property type */
{
MI_PropertyDecl* pd = _LookupPropertyDecl(cd1, pd2->name);
if (!pd)
{
r = MI_RESULT_NO_SUCH_PROPERTY;
goto failed;
}
type = pd->type;
}
/* Reject if not instance or reference */
switch (type)
{
case MI_INSTANCE:
case MI_REFERENCE:
{
MI_Value v;
v.instance = tmpInst;
r = __MI_Instance_SetElement(
self_,
pd2->name,
&v,
type,
MI_FLAG_ADOPT);
break;
}
case MI_INSTANCEA:
case MI_REFERENCEA:
{
MI_Value v;
v.instancea.size = 1;
v.instancea.data =
BAlloc(batch, sizeof(void*), CALLSITE);
if (!v.instancea.data)
{
__MI_Instance_Delete(tmpInst);
r = MI_RESULT_FAILED;
goto failed;
}
v.instancea.data[0] = tmpInst;
r = __MI_Instance_SetElement(
self_,
pd2->name,
&v,
type,
MI_FLAG_ADOPT);
break;
}
default:
{
r = MI_RESULT_TYPE_MISMATCH;
break;
}
}
if (r != MI_RESULT_OK)
{
__MI_Instance_Delete(tmpInst);
r = MI_RESULT_TYPE_MISMATCH;
goto failed;
}
}
else if (pd2->type == MI_INSTANCEA || pd2->type == MI_REFERENCEA)
{
MI_Value v;
MI_Uint32 j;
MI_Boolean allowKeylessEmbedInst = (pd2->type == MI_INSTANCEA) ? MI_TRUE : MI_FALSE;
v.instancea.size = ((MI_Value*)field)->instancea.size;
v.instancea.data = BAlloc(batch,
v.instancea.size * sizeof(void*), CALLSITE);
if (!v.instancea.data)
{
r = MI_RESULT_SERVER_LIMITS_EXCEEDED;
goto failed;
}
for (j = 0; j < v.instancea.size; j++)
{
MI_Instance* tmpInst;
MI_ClassDecl* tmpCd;
/* Find the schema declaration */
tmpCd = SchemaDecl_FindClassDecl(sd1, _SelfOf(((
MI_Value*)field)->instancea.data[j])->classDecl->name);
if (!tmpCd)
{
r = MI_RESULT_NO_SUCH_PROPERTY;
goto failed;
}
/* Allocate the instance for the provider */
r = Instance_New(&tmpInst,tmpCd,batch);
if (r != MI_RESULT_OK)
{
goto failed;
}
r = Instance_InitConvert(tmpInst, tmpCd,
((MI_Value*)field)->instancea.data[j], keysOnly, allowKeylessEmbedInst, copy,
((Instance*)tmpInst)->batch, flags);
if (r != MI_RESULT_OK)
{
MI_Uint32 k;
for (k = 0; k < j; k++)
__MI_Instance_Delete(v.instancea.data[k]);
goto failed;
}
v.instancea.data[j] = tmpInst;
}
/* Set the value */
r = __MI_Instance_SetElement(self_, pd2->name, &v, pd2->type,
MI_FLAG_ADOPT);
/* Allow conversion from reference array to instance array */
if (r == MI_RESULT_TYPE_MISMATCH && pd2->type == MI_INSTANCEA)
{
r = __MI_Instance_SetElement(self_, pd2->name, &v,
MI_REFERENCEA, MI_FLAG_ADOPT);
}
if (r != MI_RESULT_OK)
{
for (j = 0; j < v.instancea.size; j++)
__MI_Instance_Delete(v.instancea.data[j]);
goto failed;
}
}
else
{
MI_Uint32 tmpFlags = copy ? 0 : MI_FLAG_BORROW;
/* Set the value */
r = __MI_Instance_SetElement(self_, pd2->name, (MI_Value*)field,
pd2->type, tmpFlags);
if (r != MI_RESULT_OK)
{
goto failed;
}
}
}
}
failed:
if (batch != batch_)
Batch_Delete(batch);
return r;
}