Changeset: 6c8b7012d916 for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=6c8b7012d916 Added Files: sql/backends/monet5/UDF/capi/Tests/capi04.sql sql/backends/monet5/UDF/capi/Tests/capi04.stable.err sql/backends/monet5/UDF/capi/Tests/capi04.stable.out Modified Files: sql/backends/monet5/UDF/capi/Tests/All sql/backends/monet5/UDF/capi/capi.c Branch: jitudf Log Message:
Support strings in C UDFs. diffs (truncated from 335 to 300 lines): diff --git a/sql/backends/monet5/UDF/capi/Tests/All b/sql/backends/monet5/UDF/capi/Tests/All --- a/sql/backends/monet5/UDF/capi/Tests/All +++ b/sql/backends/monet5/UDF/capi/Tests/All @@ -3,3 +3,4 @@ capi00 capi01 capi02 capi03 +capi04 diff --git a/sql/backends/monet5/UDF/capi/Tests/capi04.sql b/sql/backends/monet5/UDF/capi/Tests/capi04.sql new file mode 100644 --- /dev/null +++ b/sql/backends/monet5/UDF/capi/Tests/capi04.sql @@ -0,0 +1,43 @@ +# test strings + +START TRANSACTION; + +CREATE FUNCTION capi04(inp STRING) RETURNS STRING LANGUAGE C { +#include <string.h> + + result->initialize(result, inp.count); + for(size_t i = 0; i < inp.count; i++) { + if (inp.is_null(inp.data[i])) { + result->data[i] = result->null_value; + } else { + // the contract says we must use "malloc" to allocate for the result strings + // "malloc" is a function pointer that actually points to GDKmalloc + result->data[i] = malloc(strlen(inp.data[i]) + 2); + strcpy(result->data[i] + 1, inp.data[i]); + result->data[i][0] = 'H'; + printf("%s\n", result->data[i]); + } + } +}; + +CREATE TABLE strings(i STRING); +INSERT INTO strings VALUES ('ello'), ('ow'), (NULL), ('onestly?'), ('annes'); + +SELECT capi04(i) FROM strings; + +DROP FUNCTION capi04; + +# try to modify one of the input strings +CREATE FUNCTION capi04(inp STRING) RETURNS STRING LANGUAGE C { + result->initialize(result, inp.count); + for(size_t i = 0; i < inp.count; i++) { + result->data[i][0] = 'h'; + } +}; + +SELECT capi04(i) FROM strings; + +ROLLBACK; + + + diff --git a/sql/backends/monet5/UDF/capi/Tests/capi04.stable.err b/sql/backends/monet5/UDF/capi/Tests/capi04.stable.err new file mode 100644 --- /dev/null +++ b/sql/backends/monet5/UDF/capi/Tests/capi04.stable.err @@ -0,0 +1,37 @@ +stderr of test 'capi04` in directory 'sql/backends/monet5/UDF/capi` itself: + + +# 15:50:30 > +# 15:50:30 > "mserver5" "--debug=10" "--set" "gdk_nr_threads=0" "--set" "mapi_open=true" "--set" "mapi_port=32751" "--set" "mapi_usock=/var/tmp/mtest-20003/.s.monetdb.32751" "--set" "monet_prompt=" "--forcemito" "--dbpath=NONE/var/MonetDB/mTests_sql_backends_monet5_UDF_capi" +# 15:50:30 > + +# builtin opt gdk_dbpath = /Users/myth/opt/var/monetdb5/dbfarm/demo +# builtin opt gdk_debug = 0 +# builtin opt gdk_vmtrim = no +# builtin opt monet_prompt = > +# builtin opt monet_daemon = no +# builtin opt mapi_port = 50000 +# builtin opt mapi_open = false +# builtin opt mapi_autosense = false +# builtin opt sql_optimizer = default_pipe +# builtin opt sql_debug = 0 +# cmdline opt gdk_nr_threads = 0 +# cmdline opt mapi_open = true +# cmdline opt mapi_port = 32751 +# cmdline opt mapi_usock = /var/tmp/mtest-20003/.s.monetdb.32751 +# cmdline opt monet_prompt = +# cmdline opt gdk_dbpath = /Users/myth/opt/mTests/sql/backends/monet5/UDF/capi/NONE/var/MonetDB/mTests_sql_backends_monet5_UDF_capi +# cmdline opt gdk_debug = 536870922 + +# 15:50:30 > +# 15:50:30 > "mclient" "-lsql" "-ftest" "-Eutf-8" "-i" "-e" "--host=/var/tmp/mtest-20003" "--port=32751" +# 15:50:30 > + +MAPI = (monetdb) /var/tmp/mtest-20003/.s.monetdb.32751 +QUERY = SELECT capi04(i) FROM strings; +ERROR = !Attempting to write to the input or triggered a segfault/bus error + +# 15:50:31 > +# 15:50:31 > "Done." +# 15:50:31 > + diff --git a/sql/backends/monet5/UDF/capi/Tests/capi04.stable.out b/sql/backends/monet5/UDF/capi/Tests/capi04.stable.out new file mode 100644 --- /dev/null +++ b/sql/backends/monet5/UDF/capi/Tests/capi04.stable.out @@ -0,0 +1,105 @@ +stdout of test 'capi04` in directory 'sql/backends/monet5/UDF/capi` itself: + + +# 15:50:30 > +# 15:50:30 > "mserver5" "--debug=10" "--set" "gdk_nr_threads=0" "--set" "mapi_open=true" "--set" "mapi_port=32751" "--set" "mapi_usock=/var/tmp/mtest-20003/.s.monetdb.32751" "--set" "monet_prompt=" "--forcemito" "--dbpath=NONE/var/MonetDB/mTests_sql_backends_monet5_UDF_capi" +# 15:50:30 > + +# MonetDB 5 server v11.28.0 +# This is an unreleased version +# Serving database 'mTests_sql_backends_monet5_UDF_capi', using 4 threads +# Compiled for x86_64-apple-darwin15.6.0/64bit with 128bit integers +# Found 8.000 GiB available main-memory. +# Copyright (c) 1993-July 2008 CWI. +# Copyright (c) August 2008-2017 MonetDB B.V., all rights reserved +# Visit https://www.monetdb.org/ for further information +# Listening for connection requests on mapi:monetdb://Marks-MBP:32751/ +# Listening for UNIX domain connection requests on mapi:monetdb:///var/tmp/mtest-20003/.s.monetdb.32751 +# MonetDB/SQL module loaded + +Ready. +# SQL catalog created, loading sql scripts once +# loading sql script: 09_like.sql +# loading sql script: 10_math.sql +# loading sql script: 11_times.sql +# loading sql script: 12_url.sql +# loading sql script: 13_date.sql +# loading sql script: 14_inet.sql +# loading sql script: 15_querylog.sql +# loading sql script: 16_tracelog.sql +# loading sql script: 17_temporal.sql +# loading sql script: 18_index.sql +# loading sql script: 20_vacuum.sql +# loading sql script: 21_dependency_functions.sql +# loading sql script: 22_clients.sql +# loading sql script: 23_skyserver.sql +# loading sql script: 25_debug.sql +# loading sql script: 26_sysmon.sql +# loading sql script: 27_rejects.sql +# loading sql script: 39_analytics.sql +# loading sql script: 39_analytics_hge.sql +# loading sql script: 40_json.sql +# loading sql script: 40_json_hge.sql +# loading sql script: 41_md5sum.sql +# loading sql script: 45_uuid.sql +# loading sql script: 46_profiler.sql +# loading sql script: 51_sys_schema_extension.sql +# loading sql script: 60_wlcr.sql +# loading sql script: 72_fits.sql +# loading sql script: 74_netcdf.sql +# loading sql script: 75_storagemodel.sql +# loading sql script: 80_statistics.sql +# loading sql script: 80_udf.sql +# loading sql script: 80_udf_hge.sql +# loading sql script: 90_generator.sql +# loading sql script: 90_generator_hge.sql +# loading sql script: 99_system.sql +Hello +How +Honestly? +Hannes + +# 15:50:30 > +# 15:50:30 > "mclient" "-lsql" "-ftest" "-Eutf-8" "-i" "-e" "--host=/var/tmp/mtest-20003" "--port=32751" +# 15:50:30 > + +#START TRANSACTION; +#CREATE FUNCTION capi04(inp STRING) RETURNS STRING LANGUAGE C { +##include <string.h> +# +# result->initialize(result, inp.count); +# for(size_t i = 0; i < inp.count; i++) { +# if (inp.is_null(inp.data[i])) { +# result->data[i] = result->null_value; +# } else { +# // the contract says we must use "malloc" to allocate for the result strings +# // "malloc" is a function pointer that actually points to GDKmalloc +# result->data[i] = malloc(strlen(inp.data[i]) + 2); +# strcpy(result->data[i] + 1, inp.data[i]); +# result->data[i][0] = 'H'; +#CREATE TABLE strings(i STRING); +#INSERT INTO strings VALUES ('ello'), ('ow'), (NULL), ('onestly?'), ('annes'); +[ 5 ] +#SELECT capi04(i) FROM strings; +% sys.L2 # table_name +% L2 # name +% clob # type +% 9 # length +[ "Hello" ] +[ "How" ] +[ NULL ] +[ "Honestly?" ] +[ "Hannes" ] +#DROP FUNCTION capi04; +#CREATE FUNCTION capi04(inp STRING) RETURNS STRING LANGUAGE C { +# result->initialize(result, inp.count); +# for(size_t i = 0; i < inp.count; i++) { +# result->data[i][0] = 'h'; +# } +#}; +#ROLLBACK; + +# 15:50:31 > +# 15:50:31 > "Done." +# 15:50:31 > + diff --git a/sql/backends/monet5/UDF/capi/capi.c b/sql/backends/monet5/UDF/capi/capi.c --- a/sql/backends/monet5/UDF/capi/capi.c +++ b/sql/backends/monet5/UDF/capi/capi.c @@ -140,19 +140,20 @@ static void tpename##_initialize(struct self->data = wrapped_GDK_malloc(count * sizeof(self->null_value)); \ } -#define GENERATE_BASE_FUNCTIONS(tpe) \ -GENERATE_BASE_HEADERS(tpe, tpe); \ -static int tpe##_is_null(tpe value) { \ - return value == tpe##_nil; \ +#define GENERATE_BASE_FUNCTIONS(tpe, tpename) \ +GENERATE_BASE_HEADERS(tpe, tpename); \ +static int tpename##_is_null(tpe value) { \ + return value == tpename##_nil; \ } -GENERATE_BASE_FUNCTIONS(bte); -GENERATE_BASE_FUNCTIONS(sht); -GENERATE_BASE_FUNCTIONS(int); -GENERATE_BASE_FUNCTIONS(lng); -GENERATE_BASE_FUNCTIONS(flt); -GENERATE_BASE_FUNCTIONS(dbl); +GENERATE_BASE_FUNCTIONS(bte, bte); +GENERATE_BASE_FUNCTIONS(sht, sht); +GENERATE_BASE_FUNCTIONS(int, int); +GENERATE_BASE_FUNCTIONS(lng, lng); +GENERATE_BASE_FUNCTIONS(flt, flt); +GENERATE_BASE_FUNCTIONS(dbl, dbl); +GENERATE_BASE_HEADERS(char*, str); GENERATE_BASE_HEADERS(cudf_data_date, date); GENERATE_BASE_HEADERS(cudf_data_time, time); GENERATE_BASE_HEADERS(cudf_data_timestamp, timestamp); @@ -195,7 +196,7 @@ GENERATE_BASE_HEADERS(cudf_data_timestam GENERATE_BAT_OUTPUT_BASE(tpe); \ bat_data->count = 0; \ bat_data->data = NULL; \ - bat_data->null_value = tpe##_nil;\ + bat_data->null_value = (tpe) tpe##_nil;\ } #define GENERATE_SCALAR_INPUT(tpe) \ @@ -603,7 +604,31 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal } else if (bat_type == TYPE_dbl) { GENERATE_BAT_INPUT(input_bats[index], dbl); } else if (bat_type == TYPE_str) { - assert(0); + BATiter li; + BUN p = 0, q = 0; + str mprotect_retval; + GENERATE_BAT_INPUT_BASE(input_bats[index], str); + bat_data->count = BATcount(input_bats[index]); + bat_data->data = GDKmalloc(sizeof(char*) * bat_data->count); + if (!bat_data->data) { + msg = createException(MAL, "cudf.eval", MAL_MALLOC_FAIL); + goto wrapup; + } + j = 0; + + li = bat_iterator(input_bats[index]); + BATloop(input_bats[index], p, q) { + char *t = (char *)BUNtail(li, p); + bat_data->data[j] = t; + j++; + } + // for string columns, mprotect the varheap of the BAT + assert(input_bats[index]->tvheap); + mprotect_retval = mprotect_region(input_bats[index]->tvheap->base, input_bats[index]->tvheap->size, PROT_READ, ®ions); + if (mprotect_retval) { + msg = createException(MAL, "cudf.eval", "Failed to mprotect region: %s", mprotect_retval); + goto wrapup; + } } else if (bat_type == TYPE_date) { date* baseptr; GENERATE_BAT_INPUT_BASE(input_bats[index], date); @@ -657,7 +682,6 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal } } // output types - // FIXME: deal with SQL types for (i = 0; i < output_count; i++) { size_t index = i; int bat_type = getBatType(getArgType(mb, pci, i)); @@ -676,7 +700,7 @@ CUDFeval(Client cntxt, MalBlkPtr mb, Mal } else if (bat_type == TYPE_dbl) { GENERATE_BAT_OUTPUT(dbl); } else if (bat_type == TYPE_str) { - assert(0); + GENERATE_BAT_OUTPUT(str); } else if (bat_type == TYPE_date) { GENERATE_BAT_OUTPUT_BASE(date); _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list