1
/* Copyright (C) 2007 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
17
#include <my_global.h>
23
#include <xmlrpc-c/base.h>
24
#include <xmlrpc-c/client.h>
27
#include <mysqld_error.h>
28
#include <mysql/plugin.h>
30
#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8)
31
#define __attribute__(A)
35
The external name must be an xmlrpc or xmlrpcs URL scheme
36
for example xmlrpc://time.userland.com/RPC2;currentTime.getCurrentTime
41
struct st_mysql_psmroutine
43
xmlrpc_server_info *server;
48
struct my_xmlrpc_session
50
xmlrpc_client *client;
55
extern char server_version[];
56
extern CHARSET_INFO *system_charset_info;
58
/* the following function is copied from sql_string.h */
60
uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
61
const char *from, uint32 from_length,
62
CHARSET_INFO *from_cs, uint *errors);
66
static MYSQL_THDVAR_OPAQUE(session, struct my_xmlrpc_session);
70
static xmlrpc_client *acquire_session(xmlrpc_env *env, MYSQL_THD thd)
72
struct my_xmlrpc_session *session;
73
if (!(session= THDVAR(thd, session)))
75
if (!(session= (struct my_xmlrpc_session *)
76
my_malloc(sizeof(*session), MYF(MY_WME))))
79
xmlrpc_client_create(env, XMLRPC_CLIENT_NO_FLAGS,
80
my_progname, server_version,
81
NULL, 0, &session->client);
83
if (env->fault_occurred)
85
my_free((void*) session, MYF(0));
89
#ifdef HAVE_XMLRPC_CLIENT_SET_INTERRUPT
90
xmlrpc_client_set_interrupt(session->client, thd_killed_ptr(thd));
92
session->use_count= 1;
94
THDVAR(thd, session)= session;
99
return session->client;
103
static void release_session(MYSQL_THD thd)
105
struct my_xmlrpc_session *session= THDVAR(thd, session);
106
if (!--(session->use_count))
108
xmlrpc_client_destroy(session->client);
109
THDVAR(thd, session)= 0;
110
my_free((void*) session, MYF(0));
117
Initialize the PSM plugin at server start or plugin installation.
120
simple_psm_plugin_init()
127
1 failure (cannot happen)
130
static int xmlrpc_plugin_init(void *arg __attribute__((unused)))
134
xmlrpc_env_init(&env);
136
xmlrpc_client_setup_global_const(&env);
138
xmlrpc_env_clean(&env);
144
Terminate the PSM plugin at server shutdown or plugin deinstallation.
147
simple_psm_plugin_deinit()
152
1 failure (cannot happen)
156
static int xmlrpc_plugin_deinit(void *arg __attribute__((unused)))
158
xmlrpc_client_teardown_global_const();
164
static const char *parse_xmlrpc_arg(xmlrpc_env *env, const char pos)
166
if (!strncmp(pos, "array(", 6))
170
pos= parse_xmlrpc_urlarg(env, pos + 1);
171
XMLRPC_FAIL_IF_FAULT(env);
172
} while (*pos == ',');
174
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "')' expected");
177
if (!strncmp(pos, "struct(", 7))
181
pos= parse_xmlrpc_urlname(env, pos + 1);
182
XMLRPC_FAIL_IF_FAULT(env);
184
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "'=' expected");
185
pos= parse_xmlrpc_urlarg(env, pos + 1);
186
XMLRPC_FAIL_IF_FAULT(env);
187
} while (*pos == ',');
189
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "')' expected");
192
if (!strncmp(pos, "string:", 7))
193
return parse_xmlrpc_urldata(env, pos + 7);
194
if (!strncmp(pos, "int:", 4))
195
return parse_xmlrpc_urldata(env, pos + 4);
196
if (!strncmp(pos, "boolean:", 8))
197
return parse_xmlrpc_urldata(env, pos + 8);
198
if (!strncmp(pos, "double:", 7))
199
return parse_xmlrpc_urldata(env, pos + 7);
200
if (!strncmp(pos, "base64:", 7))
201
return parse_xmlrpc_urldata(env, pos + 7);
202
if (!strncmp(pos, "dateTime.iso8601:", 17))
203
return parse_xmlrpc_urldata(env, pos + 17);
211
static xmlrpc_server_info *
212
parse_xmlrpc_url(xmlrpc_env *env, const char *url, int url_length,
213
char *method_name, int *method_name_length)
216
xmlrpc_server_info *server= NULL;
217
const char *scheme_end, *login_end, *path_end, *method_end;
218
const char *hostname_start, *password_start;
222
if (!(tmp= (char*) my_malloc(url_length + 1, MYF(MY_WME))))
223
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
224
url= strmake(tmp, url, url_length);
227
if (!(scheme_end= strstr(url, "://")))
228
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "malformed url");
230
if (!(login_end= strchr(scheme_end + 3, '/')))
231
login_end= url + url_length;
233
if (!(path_end= strchr(login_end, ';')))
234
path_end= url + url_length;
236
if (!(method_end= strchr(path_end, '?')))
237
method_end= url + url_length;
239
if (method_end == path_end)
240
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "malformed url");
242
hostname_start= login_end;
243
while (hostname_start[0] != '@' && hostname_start > scheme_end + 2)
246
password_start= scheme_end + 2;
247
while (password_start[0] != ':' && password_start < (hostname_start + 1))
251
/* now its time to parse the complicated argument list */
254
char *pos= method_end;
256
pos= parse_xmlrpc_urlarg(env, pos + 1);
257
XMLRPC_FAIL_IF_NULL(pos, env, XMLRPC_INTERNAL_ERROR, "malformed url");
258
} while (*pos == ',');
261
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "malformed url");
265
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "malformed url");
268
if (*method_name_length < (int) (method_end - path_end))
269
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "malformed url");
270
*method_name_length= my_snprintf(method_name, *method_name_length, "%*s",
271
(int)(method_end - path_end) - 1,
274
if (strncasecmp(url, "xmlrpc", 6) || ((url + 6 != scheme_end) &&
275
(url + 7 != scheme_end || (url[6] != 's' && url[6] != 'S'))))
276
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "malformed url");
280
char *server_url= (char*) my_alloca((int)(path_end - hostname_start) + 8);
281
strmake(strxmov(server_url, (url[6] == ':') ? "http" : "https",
283
hostname_start + 1, (int)(path_end - hostname_start) - 1);
284
server= xmlrpc_server_info_new(env, server_url);
285
my_afree((void*) server_url);
286
XMLRPC_FAIL_IF_FAULT(env);
289
if (hostname_start != scheme_end + 2)
291
int username_length= (int) (password_start - scheme_end) - 3;
292
int password_length= (int) (hostname_start - password_start);
293
char *username= (char*) my_alloca(username_length + 1);
294
char *password= (char*) my_alloca(password_length + 1);
296
xmlrpc_server_info_set_basic_auth(env, server,
297
strmake(username, scheme_end + 3, username_length),
298
strmake(password, password_start + 1, password_length));
299
my_afree((void*) password);
300
my_afree((void*) username);
301
XMLRPC_FAIL_IF_FAULT(env);
307
my_free((void*) tmp, MYF(MY_ALLOW_ZERO_PTR));
309
xmlrpc_server_info_free(server);
314
static int xmlrpc_plugin_find(MYSQL_PSM_ROUTINE *handle,
315
const char *name, int name_length)
318
xmlrpc_server_info *server= NULL;
319
char method_name[64];
320
int method_name_length= sizeof(method_name);
322
xmlrpc_env_init(&env);
324
server= parse_xmlrpc_url(&env, name, name_length,
325
method_name, &method_name_length);
326
XMLRPC_FAIL_IF_FAULT(&env);
328
*handle= (MYSQL_PSM_ROUTINE)
329
my_malloc(sizeof(**handle) + method_name_length, MYF(MY_WME));
330
XMLRPC_FAIL_IF_NULL(*handle, &env, XMLRPC_INTERNAL_ERROR, "out of memory");
332
(*handle)->server= server;
333
strmake((*handle)->method_name, method_name, method_name_length);
335
xmlrpc_env_clean(&env);
340
xmlrpc_server_info_free(server);
341
xmlrpc_env_clean(&env);
346
static long long get_value_integer(xmlrpc_env *env, xmlrpc_value *result,
349
switch (xmlrpc_value_type(result)) {
350
case XMLRPC_TYPE_INT:
353
xmlrpc_read_int(env, result, &intvalue);
354
XMLRPC_FAIL_IF_FAULT(env);
358
case XMLRPC_TYPE_BOOL:
360
xmlrpc_bool boolvalue;
361
xmlrpc_read_bool(env, result, &boolvalue);
362
XMLRPC_FAIL_IF_FAULT(env);
364
return boolvalue ? 1 : 0;
366
case XMLRPC_TYPE_DOUBLE:
368
double dblvalue= 0.0;
369
xmlrpc_read_double(env, result, &dblvalue);
370
XMLRPC_FAIL_IF_FAULT(env);
371
if ((*is_unsigned= (dblvalue > 0.0)))
374
return (unsigned long long) dblvalue;
376
return (long long) dblvalue;
378
case XMLRPC_TYPE_DATETIME:
383
xmlrpc_read_datetime_str(env, result, &str);
384
XMLRPC_FAIL_IF_FAULT(env);
385
str_to_datetime(str, strlen(str), &l_time, TIME_FUZZY_DATE, &cut);
387
return (long long) TIME_to_ulonglong(&l_time);
389
case XMLRPC_TYPE_STRING:
393
xmlrpc_read_string(env, result, &str);
394
XMLRPC_FAIL_IF_FAULT(env);
396
return my_strtoll10(str, NULL, &dummy);
398
case XMLRPC_TYPE_BASE64:
400
unsigned char buffer[8];
401
const unsigned char *ptr;
404
xmlrpc_read_base64(env, result, &len, &ptr);
405
XMLRPC_FAIL_IF_FAULT(env);
406
bzero(buffer, sizeof(buffer));
407
memcpy(buffer, ptr, min(len, sizeof(buffer)));
408
value= sint8korr(buffer);
420
static double get_value_double(xmlrpc_env *env, xmlrpc_value *result,
423
switch (xmlrpc_value_type(result)) {
424
case XMLRPC_TYPE_INT:
427
xmlrpc_read_int(env, result, &intvalue);
428
XMLRPC_FAIL_IF_FAULT(env);
430
return (double) intvalue;
432
case XMLRPC_TYPE_BOOL:
434
xmlrpc_bool boolvalue;
435
xmlrpc_read_bool(env, result, &boolvalue);
436
XMLRPC_FAIL_IF_FAULT(env);
438
return boolvalue ? 1.0 : 0.0;
440
case XMLRPC_TYPE_DOUBLE:
442
double dblvalue= 0.0;
443
xmlrpc_read_double(env, result, &dblvalue);
444
XMLRPC_FAIL_IF_FAULT(env);
448
case XMLRPC_TYPE_DATETIME:
453
xmlrpc_read_datetime_str(env, result, &str);
454
XMLRPC_FAIL_IF_FAULT(env);
455
str_to_datetime(str, strlen(str), &l_time, TIME_FUZZY_DATE, &cut);
457
return (long long) TIME_to_ulonglong(&l_time);
459
case XMLRPC_TYPE_STRING:
463
xmlrpc_read_string(env, result, &str);
464
XMLRPC_FAIL_IF_FAULT(env);
466
return my_strtod(str, NULL, &dummy);
468
case XMLRPC_TYPE_BASE64:
470
unsigned char buffer[sizeof(double)];
471
const unsigned char *ptr;
474
xmlrpc_read_base64(env, result, &len, &ptr);
475
XMLRPC_FAIL_IF_FAULT(env);
476
bzero(buffer, sizeof(buffer));
477
memcpy(buffer, ptr, min(len, sizeof(buffer)));
478
float8get(value, buffer);
490
static void get_value_time(xmlrpc_env *env, xmlrpc_value *result,
494
switch (xmlrpc_value_type(result)) {
495
case XMLRPC_TYPE_INT:
498
xmlrpc_read_int(env, result, &intvalue);
499
XMLRPC_FAIL_IF_FAULT(env);
500
number_to_datetime(intvalue, p_time, TIME_FUZZY_DATE, &cut);
503
case XMLRPC_TYPE_BOOL:
504
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "cannot convert BOOL to time");
506
case XMLRPC_TYPE_DOUBLE:
508
double dblvalue= 0.0;
509
xmlrpc_read_double(env, result, &dblvalue);
510
XMLRPC_FAIL_IF_FAULT(env);
511
number_to_datetime((longlong) dblvalue, p_time, TIME_FUZZY_DATE, &cut);
514
case XMLRPC_TYPE_DATETIME:
517
xmlrpc_read_datetime_str(env, result, &str);
518
XMLRPC_FAIL_IF_FAULT(env);
519
str_to_datetime(str, strlen(str), p_time, TIME_FUZZY_DATE, &cut);
522
case XMLRPC_TYPE_STRING:
526
xmlrpc_read_string_lp(env, result, &len, &str);
527
XMLRPC_FAIL_IF_FAULT(env);
528
str_to_datetime(str, len, p_time, TIME_FUZZY_DATE, &cut);
531
case XMLRPC_TYPE_BASE64:
533
unsigned char buffer[sizeof(longlong)];
534
const unsigned char *ptr;
536
xmlrpc_read_base64(env, result, &len, &ptr);
537
XMLRPC_FAIL_IF_FAULT(env);
538
bzero(buffer, sizeof(buffer));
539
memcpy(buffer, ptr, min(len, sizeof(buffer)));
540
number_to_datetime(sint8korr(buffer), p_time, TIME_FUZZY_DATE, &cut);
546
bzero(p_time, sizeof(*p_time));
552
static const char *get_value_string(xmlrpc_env *env, xmlrpc_value *result,
553
char *buf, int *len, CHARSET_INFO **cs)
555
switch (xmlrpc_value_type(result)) {
556
case XMLRPC_TYPE_INT:
559
xmlrpc_read_int(env, result, &intvalue);
560
XMLRPC_FAIL_IF_FAULT(env);
561
*len= (int) (longlong10_to_str(intvalue, buf, 10) - buf);
562
cs= &my_charset_latin1;
565
case XMLRPC_TYPE_BOOL:
567
xmlrpc_bool boolvalue;
568
xmlrpc_read_bool(env, result, &boolvalue);
569
XMLRPC_FAIL_IF_FAULT(env);
570
*len= my_sprintf(buf, (buf, boolvalue ? "TRUE" : "FALSE"));
571
cs= &my_charset_latin1;
574
case XMLRPC_TYPE_DOUBLE:
576
double dblvalue= 0.0;
577
xmlrpc_read_double(env, result, &dblvalue);
578
XMLRPC_FAIL_IF_FAULT(env);
579
*len= my_sprintf(buf, (buf, "%.14g", dblvalue));
580
cs= &my_charset_latin1;
583
case XMLRPC_TYPE_DATETIME:
586
xmlrpc_read_datetime_str(env, result, &str);
587
XMLRPC_FAIL_IF_FAULT(env);
588
*len= my_snprintf(buf, *len, "%s", str);
589
cs= &my_charset_latin1;
592
case XMLRPC_TYPE_STRING:
597
xmlrpc_read_string_lp(env, result, &length, &str);
598
XMLRPC_FAIL_IF_FAULT(env);
599
if ((length >= (size_t) *len) && !(buf= (char*) malloc(length + 1)))
600
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
601
*len= (int) (strmake(buf, str, length) - buf);
602
*cs= &my_charset_utf8_general_ci;
605
case XMLRPC_TYPE_BASE64:
607
const unsigned char *ptr;
609
xmlrpc_read_base64(env, result, &length, &ptr);
610
XMLRPC_FAIL_IF_FAULT(env);
612
*cs= &my_charset_bin;
613
return (const char *) ptr;
622
static void store_value(xmlrpc_env *env, MYSQL_PSM_CONTEXT context,
623
xmlrpc_value *result, int type)
625
if (xmlrpc_value_type(result) == XMLRPC_TYPE_NIL)
626
type= MYSQL_TYPE_NULL;
630
case MYSQL_TYPE_LONGLONG:
633
long long val= get_value_integer(env, result, &is_unsigned);
634
XMLRPC_FAIL_IF_FAULT(env);
635
context->cb->store_integer(context, -1, val, is_unsigned);
638
case MYSQL_TYPE_DOUBLE:
641
double val= get_value_double(env, result, &precision);
642
XMLRPC_FAIL_IF_FAULT(env);
643
context->cb->store_double(context, -1, val, precision);
646
case MYSQL_TYPE_DATETIME:
649
get_value_time(env, result, &l_time);
650
XMLRPC_FAIL_IF_FAULT(env);
651
context->cb->store_time(context, -1, &l_time);
654
case MYSQL_TYPE_STRING:
657
int len= sizeof(buffer);
659
const char *str= get_value_string(env, result, buffer, &len, &cs);
660
XMLRPC_FAIL_IF_FAULT(env);
661
context->cb->store_string(context, -1, str, len, cs);
663
my_free((void*) str, MYF(0));
666
case MYSQL_TYPE_NULL:
669
context->cb->store_null(context, -1);
676
prepare_column_one_element(xmlrpc_env *env, xmlrpc_value *elem,
677
int mask, int *width, int *precision)
682
switch (xmlrpc_value_type(elem)) {
683
case XMLRPC_TYPE_INT:
688
case XMLRPC_TYPE_BOOL:
691
case XMLRPC_TYPE_DOUBLE:
698
case XMLRPC_TYPE_DATETIME:
700
xmlrpc_read_datetime_str(env, elem, &ptr);
701
if ((int) (size= strlen(ptr)) > *width)
704
case XMLRPC_TYPE_STRING:
706
xmlrpc_read_string_lp(env, elem, &size, &ptr);
707
if ((int) size > *width)
710
case XMLRPC_TYPE_BASE64:
712
xmlrpc_read_base64_size(env, elem, &size);
713
if ((int) size > *width)
724
mask_to_mysql_type(int mask)
727
return MYSQL_TYPE_STRING;
728
if (mask & 16 || ((mask & 8) && (mask & ~8)))
729
return MYSQL_TYPE_STRING;
731
return MYSQL_TYPE_DATETIME;
733
return MYSQL_TYPE_DOUBLE;
735
return MYSQL_TYPE_LONGLONG;
737
return MYSQL_TYPE_LONGLONG;
738
return MYSQL_TYPE_NULL;
743
prepare_column_type(xmlrpc_env *env, xmlrpc_value *result,
744
int *type, int *width, int *precision)
746
int max_rows= xmlrpc_array_size(env, result), row, mask= 0;
748
*type= MYSQL_TYPE_STRING;
752
for (row= 0; row < max_rows; row++)
756
xmlrpc_array_read_item(env, result, row, &elem);
758
mask= prepare_column_one_element(env, elem, mask, width, precision);
761
*type= mask_to_mysql_type(mask);
767
static void store_struct(xmlrpc_env *env, MYSQL_PSM_CONTEXT context,
768
xmlrpc_value *result)
770
xmlrpc_value *key, *value;
771
int columns= xmlrpc_struct_size(env, result), i;
772
int *types, *widths, *precision;
773
xmlrpc_value **names, **column;
776
my_alloca(columns * (3*sizeof(int) + 2*sizeof(xmlrpc_value*)));
778
types= (int*) ptr; ptr+= columns * sizeof(int);
779
widths= (int*) ptr; ptr+= columns * sizeof(int);
780
precision= (int*) ptr; ptr+= columns * sizeof(int);
781
names= (xmlrpc_value**) ptr; ptr+= columns * sizeof(xmlrpc_value*);
782
column= (xmlrpc_value**) ptr; ptr+= columns * sizeof(xmlrpc_value*);
785
xmlrpc_struct_read_member(env, result, 0, &key, &value);
787
if (xmlrpc_value_type(value) == XMLRPC_TYPE_ARRAY)
790
int *rows= (int*) my_alloca(columns * sizeof(int));
796
prepare_column_type(env, value, types, widths, precision);
797
for (i= 1; i < columns; i++)
799
xmlrpc_struct_read_member(env, result, i, &key, &value);
801
rows[i]= prepare_column_type(env, value,
802
&types[i], &widths[i], &precision[i]);
803
if (rows[i] > max_rows)
811
for (i= 0; i < columns; i++)
814
xmlrpc_read_string(env, names[i], &name);
815
if (context->cb->row_field(context, name,
816
types[i], widths[i], precision[i]))
817
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
820
if (context->cb->row_prepare(context))
821
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
822
for (row= 0; row < max_rows; row++)
824
if (row && context->cb->row_prepare(context))
825
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
827
for (i= 0; i < columns; i++)
829
if (types[i] == MYSQL_TYPE_NULL || row >= rows[i])
830
context->cb->store_null(context, -1);
834
xmlrpc_array_read_item(env, column[i], row, &elem);
835
store_value(env, context, elem, types[i]);
838
context->cb->row_send(context);
840
context->cb->row_send_eof(context);
846
types[0]= mask_to_mysql_type(
847
prepare_column_one_element(env, value, 0,
848
&widths[0], &precision[0]));
849
for (i= 1; i < columns; i++)
851
xmlrpc_struct_read_member(env, result, i, &key, &value);
853
types[i]= mask_to_mysql_type(
854
prepare_column_one_element(env, value, 0,
855
&widths[i], &precision[i]));
860
for (i= 0; i < columns; i++)
863
xmlrpc_read_string(env, names[i], &name);
864
if (context->cb->row_field(context, name,
865
types[i], widths[i], precision[i]))
866
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
869
if (context->cb->row_prepare(context))
870
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
872
for (i= 0; i < columns; i++)
874
store_value(env, context, column[i], types[i]);
876
context->cb->row_send(context);
877
context->cb->row_send_eof(context);
881
my_afree((void*) types);
885
static void store_array(xmlrpc_env *env, MYSQL_PSM_CONTEXT context,
886
xmlrpc_value *result)
888
int max_rows= xmlrpc_array_size(env, result);
889
xmlrpc_value *first= NULL, *new_results= NULL;
893
xmlrpc_array_read_item(env, result, 0, &first);
894
XMLRPC_FAIL_IF_FAULT(env);
897
if (first && xmlrpc_value_type(first) == XMLRPC_TYPE_STRUCT)
900
transform this resultset into a struct of arrays and call store_struct
902
int columns= xmlrpc_struct_size(env, first), i;
904
new_results= xmlrpc_struct_new(env);
905
XMLRPC_FAIL_IF_FAULT(env);
907
for (i= 0; i < columns; i++)
909
xmlrpc_value *key, *value, *column;
912
xmlrpc_struct_read_member(env, first, i, &key, &value);
913
XMLRPC_FAIL_IF_FAULT(env);
914
column= xmlrpc_array_new(env);
915
XMLRPC_FAIL_IF_FAULT(env);
916
xmlrpc_struct_set_value_v(env, new_results, key, column);
917
XMLRPC_FAIL_IF_FAULT(env);
919
for (row= 0; row < max_rows; row++)
923
xmlrpc_array_read_item(env, result, row, &value);
924
XMLRPC_FAIL_IF_FAULT(env);
925
xmlrpc_struct_find_value_v(env, value, key, &cell);
926
XMLRPC_FAIL_IF_FAULT(env);
928
xmlrpc_array_append_item(env, column, cell);
930
xmlrpc_array_append_item(env, column, xmlrpc_nil_new(env));
931
XMLRPC_FAIL_IF_FAULT(env);
934
store_struct(env, context, new_results);
938
int type= MYSQL_TYPE_NULL, width=4, precision=0, row;
941
prepare_column_type(env, result, &type, &width, &precision);
943
if (context->cb->row_field(context, "ARRAY",
944
type, width, precision))
945
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
947
if (context->cb->row_prepare(context))
948
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
950
for (row= 0; row < max_rows; row++)
953
if (row && context->cb->row_prepare(context))
954
XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
955
xmlrpc_array_read_item(env, result, row, &elem);
956
store_value(env, context, elem, type);
957
context->cb->row_send(context);
959
context->cb->row_send_eof(context);
964
xmlrpc_DECREF(new_results);
969
static void store_result(xmlrpc_env *env, MYSQL_PSM_CONTEXT context,
970
xmlrpc_value *result)
972
switch (xmlrpc_value_type(result))
974
case XMLRPC_TYPE_INT:
977
xmlrpc_read_int(env, result, &value);
978
XMLRPC_FAIL_IF_FAULT(env);
979
context->cb->store_integer(context, -1, value, 0);
982
case XMLRPC_TYPE_BOOL:
985
xmlrpc_read_bool(env, result, &value);
986
XMLRPC_FAIL_IF_FAULT(env);
987
context->cb->store_integer(context, -1, value ? 1 : 0, 0);
990
case XMLRPC_TYPE_DOUBLE:
993
xmlrpc_read_double(env, result, &value);
994
XMLRPC_FAIL_IF_FAULT(env);
995
context->cb->store_double(context, -1, value, 53);
998
case XMLRPC_TYPE_DATETIME:
1001
xmlrpc_read_datetime_str(env, result, &str);
1002
XMLRPC_FAIL_IF_FAULT(env);
1003
context->cb->store_string(context, -1, str, strlen(str),
1004
&my_charset_latin1);
1007
case XMLRPC_TYPE_STRING:
1011
xmlrpc_read_string_lp(env, result, &len, &str);
1012
XMLRPC_FAIL_IF_FAULT(env);
1013
context->cb->store_string(context, -1, str, len,
1014
&my_charset_utf8_general_ci);
1017
case XMLRPC_TYPE_BASE64:
1019
const unsigned char *ptr;
1021
xmlrpc_read_base64(env, result, &len, &ptr);
1022
XMLRPC_FAIL_IF_FAULT(env);
1023
context->cb->store_string(context, -1, ptr, len,
1029
case XMLRPC_TYPE_ARRAY:
1031
If the first element of the array is a structure, assume that
1032
all subsequent elements are structures containing the same elements.
1033
Otherwise, assume that only one column exists for this resultset
1035
store_array(env, context, result);
1038
case XMLRPC_TYPE_STRUCT:
1040
If the first element of this structure is an array, assume that
1041
all other elements are arrays and return a resultset.
1042
Otherwise, assume that only one row exists for this resultset
1044
store_struct(env, context, result);
1049
context->cb->store_null(context, -1);
1055
static xmlrpc_value *
1056
val_field(xmlrpc_env *env, MYSQL_PSM_CONTEXT context, int i)
1058
CHARSET_INFO * const utf8= &my_charset_utf8_general_ci;
1059
xmlrpc_value *value= NULL;
1060
int field_type, length, cut;
1063
if (context->cb->field_ptr(context, i, &field_type, &ptr, &length) ||
1064
context->cb->val_null(context, i))
1065
field_type= MYSQL_TYPE_NULL;
1069
case MYSQL_TYPE_LONG:
1070
case MYSQL_TYPE_LONGLONG:
1071
case MYSQL_TYPE_TIMESTAMP:
1072
#ifdef HAVE_XMLRPC_CLIENT_SET_INTERRUPT
1073
value= xmlrpc_i8_new(env, context->cb->val_integer(context, i));
1077
case MYSQL_TYPE_TINY:
1078
case MYSQL_TYPE_SHORT:
1079
case MYSQL_TYPE_INT24:
1080
value= xmlrpc_int_new(env, (int) context->cb->val_integer(context, i));
1083
case MYSQL_TYPE_FLOAT:
1084
case MYSQL_TYPE_DOUBLE:
1085
value= xmlrpc_double_new(env, context->cb->val_double(context, i));
1088
case MYSQL_TYPE_YEAR:
1091
my_snprintf(buf, sizeof(buf)-1, "%04d",
1092
(int) context->cb->val_integer(context, i));
1093
value= xmlrpc_datetime_new_str(env, buf);
1097
case MYSQL_TYPE_DATE:
1098
case MYSQL_TYPE_NEWDATE:
1103
if (!context->cb->val_string(context, i, buf, &length, &cs) ||
1104
str_to_datetime(buf, length, &l_time, TIME_FUZZY_DATE,
1105
&cut) <= MYSQL_TIMESTAMP_ERROR)
1107
my_snprintf(buf, sizeof(buf)-1, "%04d%02d%02d",
1108
l_time.year, l_time.month, l_time.day);
1109
value= xmlrpc_datetime_new_str(env, buf);
1113
case MYSQL_TYPE_TIME:
1118
if (!context->cb->val_string(context, i, buf, &length, &cs) ||
1119
str_to_time(buf, length, &l_time, &cut))
1121
my_snprintf(buf, sizeof(buf)-1, "%02d%02d%02d",
1122
l_time.hour, l_time.minute, l_time.second);
1123
value= xmlrpc_datetime_new_str(env, buf);
1127
case MYSQL_TYPE_DATETIME:
1132
if (!context->cb->val_string(context, i, buf, &length, &cs) ||
1133
str_to_datetime(buf, length, &l_time, TIME_FUZZY_DATE,
1134
&cut) <= MYSQL_TIMESTAMP_ERROR)
1136
snprintf(buf, sizeof(buf)-1, "%04d%02d%02dT%02d:%02d:%02d",
1137
l_time.year, l_time.month, l_time.day,
1138
l_time.hour, l_time.minute, l_time.second);
1139
value= xmlrpc_datetime_new_str(env, buf);
1143
case MYSQL_TYPE_VARCHAR:
1144
case MYSQL_TYPE_VAR_STRING:
1145
case MYSQL_TYPE_STRING:
1146
case MYSQL_TYPE_ENUM:
1147
case MYSQL_TYPE_SET:
1148
case MYSQL_TYPE_DECIMAL:
1150
int alloc_length= (length + 64) & ~63;
1151
CHARSET_INFO *cs= system_charset_info;
1152
char *str= (char*) my_alloca((length= alloc_length));
1153
const char *res= context->cb->val_string(context, i, str, &length, &cs);
1154
if (res && length < alloc_length && length < 4096)
1156
int addlen= length / cs->mbminlen * utf8->mbmaxlen;
1157
char *tgtstr= (char*) my_alloca(addlen+1);
1158
int tgtlen= copy_and_convert(tgtstr, addlen, utf8,
1159
res, length, cs, &cut);
1161
value= xmlrpc_string_new_lp(env, tgtlen, tgtstr);
1162
my_afree((void*) tgtstr);
1165
if (res && length < alloc_length)
1167
int addlen= length / cs->mbminlen * utf8->mbmaxlen, tgtlen;
1168
char *tgtstr= (char*) my_malloc(addlen+1, MYF(MY_WME));
1171
tgtlen= copy_and_convert(tgtstr, addlen, utf8,
1172
res, length, cs, &cut);
1174
value= xmlrpc_string_new_lp(env, tgtlen, tgtstr);
1175
my_free((void*) tgtstr, MYF(0));
1177
my_afree((void*) str);
1181
case MYSQL_TYPE_BIT:
1182
case MYSQL_TYPE_GEOMETRY:
1183
case MYSQL_TYPE_NEWDECIMAL:
1184
value= xmlrpc_base64_new(env, length, ptr);
1187
case MYSQL_TYPE_TINY_BLOB:
1188
case MYSQL_TYPE_MEDIUM_BLOB:
1189
case MYSQL_TYPE_LONG_BLOB:
1190
case MYSQL_TYPE_BLOB:
1191
value= xmlrpc_base64_new(env, length, ptr);
1194
case MYSQL_TYPE_NULL:
1197
value= xmlrpc_nil_new(env);
1204
static xmlrpc_value *
1205
build_parameter(xmlrpc_env *env, MYSQL_PSM_CONTEXT context)
1207
xmlrpc_value *parameters;
1210
parameters= xmlrpc_array_new(env);
1211
XMLRPC_FAIL_IF_FAULT(env);
1213
for (i= 0; i < context->arg_count; i++)
1215
xmlrpc_value *value= val_field(env, context, i);
1216
XMLRPC_FAIL_IF_FAULT(env);
1217
xmlrpc_array_append_item(env, parameters, value);
1218
XMLRPC_FAIL_IF_FAULT(env);
1223
xmlrpc_DECREF(parameters);
1228
static int xmlrpc_plugin_execute(MYSQL_PSM_ROUTINE handle,
1229
MYSQL_PSM_CONTEXT context)
1232
xmlrpc_value *parameters, *result;
1233
struct xmlrpc_client *client;
1235
xmlrpc_env_init(&env);
1237
client= acquire_session(&env, context->thd);
1239
parameters= build_parameter(&env, context);
1241
XMLRPC_FAIL_IF_FAULT(&env);
1243
xmlrpc_client_call2(&env, client, handle->server, handle->method_name,
1244
parameters, &result);
1246
XMLRPC_FAIL_IF_FAULT(&env);
1248
store_result(&env, context, result);
1250
xmlrpc_DECREF(result);
1252
release_session(context->thd);
1254
xmlrpc_env_clean(&env);
1258
my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
1259
"XMLRPC", env.fault_string);
1260
release_session(context->thd);
1261
xmlrpc_env_clean(&env);
1266
static int xmlrpc_plugin_release(MYSQL_PSM_ROUTINE handle)
1268
if (handle && handle->server)
1269
xmlrpc_server_info_free(handle->server);
1270
my_free(handle, MYF(MY_ALLOW_ZERO_PTR));
1276
Plugin type-specific descriptor
1279
static struct st_mysql_psmlanguage xmlrpc_plugin_descriptor=
1281
MYSQL_PSM_LANGUAGE_INTERFACE_VERSION, /* interface version */
1282
xmlrpc_plugin_find, /* function resolution function */
1283
xmlrpc_plugin_release, /* function release function */
1284
xmlrpc_plugin_execute /* execute function */
1289
Plugin system variables.
1292
static struct st_mysql_sys_var* xmlrpc_plugin_variables[]= {
1293
MYSQL_SYSVAR(session),
1299
Plugin library descriptor
1302
mysql_declare_plugin(xmlrpc)
1304
MYSQL_PSMLANGUAGE_PLUGIN, /* type */
1305
&xmlrpc_plugin_descriptor, /* descriptor */
1306
"XMLRPC", /* name */
1307
"MySQL AB", /* author */
1308
"XML-RPC Language Demo", /* description */
1310
xmlrpc_plugin_init, /* init function (when loaded) */
1311
xmlrpc_plugin_deinit, /* deinit function (when unloaded) */
1312
0x0001, /* version */
1313
NULL, /* status variables */
1314
xmlrpc_plugin_variables, /* system variables */
1317
mysql_declare_plugin_end;