void asval_to_clobject(as_val * val, cl_object * obj) { switch(val->type) { case AS_NIL: { citrusleaf_object_init_null(obj); break; } case AS_INTEGER: { as_integer * v = as_integer_fromval(val); citrusleaf_object_init_int(obj, as_integer_toint(v)); break; } case AS_STRING: { as_string * v = as_string_fromval(val); citrusleaf_object_init_str(obj, as_string_get(v)); break; } case AS_BYTES: { as_bytes * v = as_bytes_fromval(val); citrusleaf_object_init_blob2(obj, v->value, v->size, (cl_type)v->type); break; } case AS_LIST:{ as_buffer buffer; as_buffer_init(&buffer); as_serializer ser; as_msgpack_init(&ser); as_serializer_serialize(&ser, val, &buffer); as_serializer_destroy(&ser); citrusleaf_object_init_blob_handoff(obj, buffer.data, buffer.size, CL_LIST); break; } case AS_MAP: { as_buffer buffer; as_buffer_init(&buffer); as_serializer ser; as_msgpack_init(&ser); as_serializer_serialize(&ser, val, &buffer); as_serializer_destroy(&ser); citrusleaf_object_init_blob_handoff(obj, buffer.data, buffer.size, CL_MAP); break; } default: { // raise an error break; } } }
TEST( record_udf_1, "echo bin a of {a = 123, b = 456 }" ) { as_rec * rec = map_rec_new(); as_rec_set(rec, "a", (as_val *) as_integer_new(123)); as_list * arglist = (as_list *) as_arraylist_new(1,0); as_list_append_str(arglist, "a"); as_result * res = as_success_new(NULL); int rc = as_module_apply_record(&mod_lua, &as, "records", "getbin", rec, arglist, res); assert_int_eq( rc, 0 ); assert_true( res->is_success ); assert_not_null( res->value ); assert_int_eq( as_integer_toint((as_integer *) res->value), 123 ); as_rec_destroy(rec); as_list_destroy(arglist); as_result_destroy(res); } TEST( record_udf_2, "concat bins a and b of {a = 'abc', b = 'def' }" ) { as_rec * rec = map_rec_new(); as_rec_set(rec, "a", (as_val *) as_string_new("abc",false)); as_rec_set(rec, "b", (as_val *) as_string_new("def",false)); as_list * arglist = (as_list *) as_arraylist_new(2,0); as_list_append_str(arglist, "a"); as_list_append_str(arglist, "b");
/* * Internal Function: Entry function from UDF code path to send * success result to the caller. Performs * value translation. */ void send_result(as_result * res, udf_call * call, void *udata) { // The following "no-op" line serves to quiet the compiler warning of an // otherwise unused variable. udata = udata; as_val * v = res->value; if ( res->is_success ) { if ( cf_context_at_severity(AS_UDF, CF_DETAIL) ) { char * str = as_val_tostring(v); cf_detail(AS_UDF, "SUCCESS: %s", str); cf_free(str); } if ( v != NULL ) { switch( as_val_type(v) ) { case AS_NIL: { send_success(call, AS_PARTICLE_TYPE_NULL, NULL, 0); break; } case AS_BOOLEAN: { as_boolean * b = as_boolean_fromval(v); int64_t bi = as_boolean_tobool(b) == true ? 1 : 0; send_success(call, AS_PARTICLE_TYPE_INTEGER, &bi, 8); break; } case AS_INTEGER: { as_integer * i = as_integer_fromval(v); int64_t ri = as_integer_toint(i); send_success(call, AS_PARTICLE_TYPE_INTEGER, &ri, 8); break; } case AS_STRING: { // this looks bad but it just pulls the pointer // out of the object as_string * s = as_string_fromval(v); char * rs = (char *) as_string_tostring(s); send_success(call, AS_PARTICLE_TYPE_STRING, rs, as_string_len(s)); break; } case AS_BYTES: { as_bytes * b = as_bytes_fromval(v); uint8_t * rs = as_bytes_get(b); send_success(call, AS_PARTICLE_TYPE_BLOB, rs, as_bytes_size(b)); break; } case AS_MAP: case AS_LIST: { as_buffer buf; as_buffer_init(&buf); as_serializer s; as_msgpack_init(&s); int res = as_serializer_serialize(&s, v, &buf); if (res != 0) { const char * error = "Complex Data Type Serialization failure"; cf_warning(AS_UDF, "%s (%d)", (char *)error, res); as_buffer_destroy(&buf); send_cdt_failure(call, AS_PARTICLE_TYPE_STRING, (char *)error, strlen(error)); } else { // Do not use this until after cf_detail_binary() can accept larger buffers. // cf_detail_binary(AS_UDF, buf.data, buf.size, CF_DISPLAY_HEX_COLUMNS, // "serialized %d bytes: ", buf.size); send_success(call, to_particle_type(as_val_type(v)), buf.data, buf.size); // Not needed stack allocated - unless serialize has internal state // as_serializer_destroy(&s); as_buffer_destroy(&buf); } break; } default: { cf_debug(AS_UDF, "SUCCESS: VAL TYPE UNDEFINED %d\n", as_val_type(v)); send_success(call, AS_PARTICLE_TYPE_STRING, NULL, 0); break; } } } else { send_success(call, AS_PARTICLE_TYPE_NULL, NULL, 0); } } else { // Else -- NOT success as_string * s = as_string_fromval(v); char * rs = (char *) as_string_tostring(s); cf_debug(AS_UDF, "FAILURE when calling %s %s %s", call->filename, call->function, rs); send_udf_failure(call, AS_PARTICLE_TYPE_STRING, rs, as_string_len(s)); } }
/** * Get specified bin's value as an int64_t. * ~~~~~~~~~~{.c} * int64_t value = as_record_get_int64(rec, "bin", INT64_MAX); * ~~~~~~~~~~ * @param rec The record containing the bin. * @param name The name of the bin. * @param fallback The default value to use, if the bin doesn't exist or is not an integer. * @return the value if it exists, otherwise 0. */ int64_t as_record_get_int64(const as_record * rec, const as_bin_name name, int64_t fallback) { as_integer * val = as_integer_fromval((as_val *) as_record_get(rec, name)); return val ? as_integer_toint(val) : fallback; }