/*
|
* Licensed to the Apache Software Foundation (ASF) under one
|
* or more contributor license agreements. See the NOTICE file
|
* distributed with this work for additional information
|
* regarding copyright ownership. The ASF licenses this file
|
* to you under the Apache License, Version 2.0 (the
|
* "License"); you may not use this file except in compliance
|
* with the License. You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing,
|
* software distributed under the License is distributed on an
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
* KIND, either express or implied. See the License for the
|
* specific language governing permissions and limitations
|
* under the License.
|
*/
|
|
#include "utils/agtype_ext.h"
|
|
/* define the type and size of the agt_header */
|
#define AGT_HEADER_TYPE uint32
|
#define AGT_HEADER_SIZE sizeof(AGT_HEADER_TYPE)
|
|
static void ag_deserialize_composite(char *base, enum agtype_value_type type,
|
agtype_value *result);
|
|
static short ag_serialize_header(StringInfo buffer, uint32 type)
|
{
|
short padlen;
|
int offset;
|
|
padlen = pad_buffer_to_int(buffer);
|
offset = reserve_from_buffer(buffer, AGT_HEADER_SIZE);
|
*((AGT_HEADER_TYPE *)(buffer->data + offset)) = type;
|
|
return padlen;
|
}
|
|
/*
|
* Function serializes the data into the buffer provided.
|
* Returns false if the type is not defined. Otherwise, true.
|
*/
|
bool ag_serialize_extended_type(StringInfo buffer, agtentry *agtentry,
|
agtype_value *scalar_val)
|
{
|
short padlen;
|
int numlen;
|
int offset;
|
|
switch (scalar_val->type)
|
{
|
case AGTV_INTEGER:
|
padlen = ag_serialize_header(buffer, AGT_HEADER_INTEGER);
|
|
/* copy in the int_value data */
|
numlen = sizeof(int64);
|
offset = reserve_from_buffer(buffer, numlen);
|
*((int64 *)(buffer->data + offset)) = scalar_val->val.int_value;
|
|
*agtentry = AGTENTRY_IS_AGTYPE | (padlen + numlen + AGT_HEADER_SIZE);
|
break;
|
|
case AGTV_FLOAT:
|
padlen = ag_serialize_header(buffer, AGT_HEADER_FLOAT);
|
|
/* copy in the float_value data */
|
numlen = sizeof(scalar_val->val.float_value);
|
offset = reserve_from_buffer(buffer, numlen);
|
*((float8 *)(buffer->data + offset)) = scalar_val->val.float_value;
|
|
*agtentry = AGTENTRY_IS_AGTYPE | (padlen + numlen + AGT_HEADER_SIZE);
|
break;
|
|
case AGTV_VERTEX:
|
{
|
uint32 object_ae = 0;
|
|
padlen = ag_serialize_header(buffer, AGT_HEADER_VERTEX);
|
convert_extended_object(buffer, &object_ae, scalar_val);
|
|
/*
|
* Make sure that the end of the buffer is padded to the next offset and
|
* add this padding to the length of the buffer used. This ensures that
|
* everything stays aligned and eliminates errors caused by compounded
|
* offsets in the deserialization routines.
|
*/
|
object_ae += pad_buffer_to_int(buffer);
|
|
*agtentry = AGTENTRY_IS_AGTYPE |
|
((AGTENTRY_OFFLENMASK & (int)object_ae) + AGT_HEADER_SIZE);
|
break;
|
}
|
|
case AGTV_EDGE:
|
{
|
uint32 object_ae = 0;
|
|
padlen = ag_serialize_header(buffer, AGT_HEADER_EDGE);
|
convert_extended_object(buffer, &object_ae, scalar_val);
|
|
/*
|
* Make sure that the end of the buffer is padded to the next offset and
|
* add this padding to the length of the buffer used. This ensures that
|
* everything stays aligned and eliminates errors caused by compounded
|
* offsets in the deserialization routines.
|
*/
|
object_ae += pad_buffer_to_int(buffer);
|
|
*agtentry = AGTENTRY_IS_AGTYPE |
|
((AGTENTRY_OFFLENMASK & (int)object_ae) + AGT_HEADER_SIZE);
|
break;
|
}
|
|
case AGTV_PATH:
|
{
|
uint32 object_ae = 0;
|
|
padlen = ag_serialize_header(buffer, AGT_HEADER_PATH);
|
convert_extended_array(buffer, &object_ae, scalar_val);
|
|
/*
|
* Make sure that the end of the buffer is padded to the next offset and
|
* add this padding to the length of the buffer used. This ensures that
|
* everything stays aligned and eliminates errors caused by compounded
|
* offsets in the deserialization routines.
|
*/
|
object_ae += pad_buffer_to_int(buffer);
|
|
*agtentry = AGTENTRY_IS_AGTYPE |
|
((AGTENTRY_OFFLENMASK & (int)object_ae) + AGT_HEADER_SIZE);
|
break;
|
}
|
|
default:
|
return false;
|
}
|
return true;
|
}
|
|
/*
|
* Function deserializes the data from the buffer pointed to by base_addr.
|
* NOTE: This function writes to the error log and exits for any UNKNOWN
|
* AGT_HEADER type.
|
*/
|
void ag_deserialize_extended_type(char *base_addr, uint32 offset,
|
agtype_value *result)
|
{
|
char *base = base_addr + INTALIGN(offset);
|
AGT_HEADER_TYPE agt_header = *((AGT_HEADER_TYPE *)base);
|
|
switch (agt_header)
|
{
|
case AGT_HEADER_INTEGER:
|
result->type = AGTV_INTEGER;
|
result->val.int_value = *((int64 *)(base + AGT_HEADER_SIZE));
|
break;
|
|
case AGT_HEADER_FLOAT:
|
result->type = AGTV_FLOAT;
|
result->val.float_value = *((float8 *)(base + AGT_HEADER_SIZE));
|
break;
|
|
case AGT_HEADER_VERTEX:
|
ag_deserialize_composite(base, AGTV_VERTEX, result);
|
break;
|
|
case AGT_HEADER_EDGE:
|
ag_deserialize_composite(base, AGTV_EDGE, result);
|
break;
|
|
case AGT_HEADER_PATH:
|
ag_deserialize_composite(base, AGTV_PATH, result);
|
break;
|
|
default:
|
elog(ERROR, "Invalid AGT header value.");
|
}
|
}
|
|
/*
|
* Deserializes a composite type.
|
*/
|
static void ag_deserialize_composite(char *base, enum agtype_value_type type,
|
agtype_value *result)
|
{
|
agtype_iterator *it = NULL;
|
agtype_iterator_token tok;
|
agtype_parse_state *parse_state = NULL;
|
agtype_value *r = NULL;
|
agtype_value *parsed_agtype_value = NULL;
|
//offset container by the extended type header
|
char *container_base = base + AGT_HEADER_SIZE;
|
|
r = palloc(sizeof(agtype_value));
|
|
it = agtype_iterator_init((agtype_container *)container_base);
|
while ((tok = agtype_iterator_next(&it, r, true)) != WAGT_DONE)
|
{
|
parsed_agtype_value = push_agtype_value(
|
&parse_state, tok, tok < WAGT_BEGIN_ARRAY ? r : NULL);
|
}
|
|
result->type = type;
|
result->val = parsed_agtype_value->val;
|
}
|