~starbuggers/sakila-server/mysql-5.1-wl820

« back to all changes in this revision

Viewing changes to plugin/xmlrpc_udf/xmlrpc.c

  • Committer: Antony T Curtis
  • Date: 2008-04-10 06:09:05 UTC
  • mto: (2542.76.4 mysql-5.1-wl820)
  • mto: This revision was merged to the branch mainline in revision 2772.
  • Revision ID: antony@anubis.xiphis.org-20080410060905-itpom5iyz8ae4dhh
Initial import into Bazaar repository

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2007 MySQL AB
 
2
 
 
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.
 
6
 
 
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.
 
11
 
 
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 */
 
15
 
 
16
#include <stdlib.h>
 
17
#include <my_global.h>
 
18
#include <my_sys.h>
 
19
#include <my_time.h>
 
20
#include <m_ctype.h>
 
21
#include <m_string.h>
 
22
 
 
23
#include <xmlrpc-c/base.h>
 
24
#include <xmlrpc-c/client.h>
 
25
 
 
26
#include <mysql.h>
 
27
#include <mysqld_error.h>
 
28
#include <mysql/plugin.h>
 
29
 
 
30
#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__)  || __GNUC__ == 2 && __GNUC_MINOR__ < 8)
 
31
#define __attribute__(A)
 
32
#endif
 
33
 
 
34
/*
 
35
  The external name must be an xmlrpc or xmlrpcs URL scheme
 
36
  for example xmlrpc://time.userland.com/RPC2;currentTime.getCurrentTime
 
37
*/
 
38
 
 
39
 
 
40
 
 
41
struct st_mysql_psmroutine
 
42
{
 
43
  xmlrpc_server_info *server;
 
44
  char method_name[1];
 
45
};
 
46
 
 
47
 
 
48
struct my_xmlrpc_session
 
49
{
 
50
  xmlrpc_client *client;
 
51
  uint use_count;
 
52
};
 
53
 
 
54
 
 
55
extern char server_version[];
 
56
extern CHARSET_INFO *system_charset_info;
 
57
 
 
58
/* the following function is copied from sql_string.h */
 
59
extern
 
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);
 
63
 
 
64
 
 
65
 
 
66
static MYSQL_THDVAR_OPAQUE(session, struct my_xmlrpc_session);
 
67
 
 
68
 
 
69
 
 
70
static xmlrpc_client *acquire_session(xmlrpc_env *env, MYSQL_THD thd)
 
71
{
 
72
  struct my_xmlrpc_session *session;
 
73
  if (!(session= THDVAR(thd, session)))
 
74
  {
 
75
    if (!(session= (struct my_xmlrpc_session *)
 
76
                   my_malloc(sizeof(*session), MYF(MY_WME))))
 
77
      return NULL;
 
78
 
 
79
    xmlrpc_client_create(env, XMLRPC_CLIENT_NO_FLAGS, 
 
80
                         my_progname, server_version, 
 
81
                         NULL, 0, &session->client);
 
82
 
 
83
    if (env->fault_occurred)
 
84
    {
 
85
      my_free((void*) session, MYF(0));
 
86
      return NULL;
 
87
    }
 
88
 
 
89
#ifdef HAVE_XMLRPC_CLIENT_SET_INTERRUPT
 
90
    xmlrpc_client_set_interrupt(session->client, thd_killed_ptr(thd));
 
91
#endif
 
92
    session->use_count= 1;
 
93
 
 
94
    THDVAR(thd, session)= session;
 
95
  }
 
96
  else
 
97
    session->use_count++;
 
98
 
 
99
  return session->client;
 
100
}
 
101
 
 
102
 
 
103
static void release_session(MYSQL_THD thd)
 
104
{
 
105
  struct my_xmlrpc_session *session= THDVAR(thd, session);
 
106
  if (!--(session->use_count))
 
107
  {
 
108
    xmlrpc_client_destroy(session->client);
 
109
    THDVAR(thd, session)= 0;
 
110
    my_free((void*) session, MYF(0));
 
111
  }
 
112
}
 
113
 
 
114
 
 
115
 
 
116
/*
 
117
  Initialize the PSM plugin at server start or plugin installation.
 
118
 
 
119
  SYNOPSIS
 
120
    simple_psm_plugin_init()
 
121
 
 
122
  DESCRIPTION
 
123
    Does nothing.
 
124
 
 
125
  RETURN VALUE
 
126
    0                    success
 
127
    1                    failure (cannot happen)
 
128
*/
 
129
 
 
130
static int xmlrpc_plugin_init(void *arg __attribute__((unused)))
 
131
{
 
132
  xmlrpc_env env;
 
133
  
 
134
  xmlrpc_env_init(&env);
 
135
  
 
136
  xmlrpc_client_setup_global_const(&env);
 
137
  
 
138
  xmlrpc_env_clean(&env);
 
139
  return(0);
 
140
}
 
141
 
 
142
 
 
143
/*
 
144
  Terminate the PSM plugin at server shutdown or plugin deinstallation.
 
145
 
 
146
  SYNOPSIS
 
147
    simple_psm_plugin_deinit()
 
148
    Does nothing.
 
149
 
 
150
  RETURN VALUE
 
151
    0                    success
 
152
    1                    failure (cannot happen)
 
153
 
 
154
*/
 
155
 
 
156
static int xmlrpc_plugin_deinit(void *arg __attribute__((unused)))
 
157
{
 
158
  xmlrpc_client_teardown_global_const();
 
159
  return(0);
 
160
}
 
161
 
 
162
 
 
163
#if 0
 
164
static const char *parse_xmlrpc_arg(xmlrpc_env *env, const char pos)
 
165
{
 
166
  if (!strncmp(pos, "array(", 6))
 
167
  {
 
168
    pos+= 5;
 
169
    do {
 
170
      pos= parse_xmlrpc_urlarg(env, pos + 1);
 
171
      XMLRPC_FAIL_IF_FAULT(env);
 
172
    } while (*pos == ',');
 
173
    if (*pos != ')')
 
174
      XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "')' expected");
 
175
    return pos + 1;
 
176
  }
 
177
  if (!strncmp(pos, "struct(", 7))
 
178
  {
 
179
    pos+= 6;
 
180
    do {
 
181
      pos= parse_xmlrpc_urlname(env, pos + 1);
 
182
      XMLRPC_FAIL_IF_FAULT(env);
 
183
      if (*pos != '=')
 
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 == ',');
 
188
    if (*pos != ')')
 
189
      XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "')' expected");
 
190
    return pos + 1;          
 
191
  }
 
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);
 
204
 
 
205
cleanup:
 
206
  return NULL;  
 
207
}
 
208
#endif
 
209
 
 
210
 
 
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)
 
214
{
 
215
  char *tmp= NULL;
 
216
  xmlrpc_server_info *server= NULL;
 
217
  const char *scheme_end, *login_end, *path_end, *method_end;
 
218
  const char *hostname_start, *password_start;
 
219
  
 
220
  if (url[url_length])
 
221
  {
 
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);
 
225
  }
 
226
  
 
227
  if (!(scheme_end= strstr(url, "://")))
 
228
    XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "malformed url");
 
229
 
 
230
  if (!(login_end= strchr(scheme_end + 3, '/')))
 
231
    login_end= url + url_length;
 
232
 
 
233
  if (!(path_end= strchr(login_end, ';')))
 
234
    path_end= url + url_length;
 
235
  
 
236
  if (!(method_end= strchr(path_end, '?')))
 
237
    method_end= url + url_length;
 
238
  
 
239
  if (method_end == path_end)
 
240
    XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "malformed url");
 
241
 
 
242
  hostname_start= login_end;
 
243
  while (hostname_start[0] != '@' && hostname_start > scheme_end + 2)
 
244
    hostname_start--;
 
245
  
 
246
  password_start= scheme_end + 2;
 
247
  while (password_start[0] != ':' && password_start < (hostname_start + 1))
 
248
    password_start++;
 
249
 
 
250
#if 0
 
251
  /* now its time to parse the complicated argument list */
 
252
  if (*method_end)
 
253
  {
 
254
    char *pos= method_end;
 
255
    do {
 
256
      pos= parse_xmlrpc_urlarg(env, pos + 1);
 
257
      XMLRPC_FAIL_IF_NULL(pos, env, XMLRPC_INTERNAL_ERROR, "malformed url");
 
258
    } while (*pos == ',');
 
259
 
 
260
    if (*pos)
 
261
      XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "malformed url");
 
262
  }
 
263
#else
 
264
  if (*method_end)
 
265
    XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "malformed url");
 
266
#endif
 
267
 
 
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,
 
272
                                   path_end + 1);
 
273
 
 
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");
 
277
 
 
278
  if (1)
 
279
  {  
 
280
    char *server_url= (char*) my_alloca((int)(path_end - hostname_start) + 8);
 
281
    strmake(strxmov(server_url, (url[6] == ':') ? "http" : "https",
 
282
                     "://", NullS),
 
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);
 
287
  } 
 
288
  
 
289
  if (hostname_start != scheme_end + 2)
 
290
  {
 
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);
 
295
    
 
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);
 
302
  }
 
303
 
 
304
  return server;
 
305
  
 
306
cleanup:
 
307
  my_free((void*) tmp, MYF(MY_ALLOW_ZERO_PTR));
 
308
  if (server)
 
309
    xmlrpc_server_info_free(server);
 
310
  return NULL;
 
311
}
 
312
 
 
313
 
 
314
static int xmlrpc_plugin_find(MYSQL_PSM_ROUTINE *handle,
 
315
                              const char *name, int name_length)
 
316
{
 
317
  xmlrpc_env env;
 
318
  xmlrpc_server_info *server= NULL;
 
319
  char method_name[64];
 
320
  int method_name_length= sizeof(method_name);
 
321
  
 
322
  xmlrpc_env_init(&env);
 
323
  
 
324
  server= parse_xmlrpc_url(&env, name, name_length, 
 
325
                           method_name, &method_name_length);
 
326
  XMLRPC_FAIL_IF_FAULT(&env);
 
327
 
 
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");
 
331
 
 
332
  (*handle)->server= server;
 
333
  strmake((*handle)->method_name, method_name, method_name_length);
 
334
 
 
335
  xmlrpc_env_clean(&env);
 
336
  return 0;
 
337
  
 
338
cleanup:
 
339
  if (server)
 
340
    xmlrpc_server_info_free(server);
 
341
  xmlrpc_env_clean(&env);
 
342
  return -1;
 
343
}
 
344
 
 
345
 
 
346
static long long get_value_integer(xmlrpc_env *env, xmlrpc_value *result,
 
347
                                   char *is_unsigned)
 
348
{
 
349
  switch (xmlrpc_value_type(result)) {
 
350
  case XMLRPC_TYPE_INT:
 
351
  {
 
352
    int intvalue;
 
353
    xmlrpc_read_int(env, result, &intvalue);
 
354
    XMLRPC_FAIL_IF_FAULT(env);
 
355
    *is_unsigned= 0;
 
356
    return intvalue;
 
357
  }
 
358
  case XMLRPC_TYPE_BOOL:
 
359
  {
 
360
    xmlrpc_bool boolvalue;
 
361
    xmlrpc_read_bool(env, result, &boolvalue);
 
362
    XMLRPC_FAIL_IF_FAULT(env);
 
363
    *is_unsigned= 1;
 
364
    return boolvalue ? 1 : 0;
 
365
  }
 
366
  case XMLRPC_TYPE_DOUBLE:
 
367
  {
 
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)))
 
372
    {
 
373
      *is_unsigned= 1;
 
374
      return (unsigned long long) dblvalue;
 
375
    }
 
376
    return (long long) dblvalue;
 
377
  }
 
378
  case XMLRPC_TYPE_DATETIME:
 
379
  {
 
380
    const char *str;
 
381
    MYSQL_TIME l_time;
 
382
    int cut;
 
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);
 
386
    *is_unsigned= 1;
 
387
    return (long long) TIME_to_ulonglong(&l_time);
 
388
  }
 
389
  case XMLRPC_TYPE_STRING:
 
390
  {
 
391
    const char *str;
 
392
    int dummy;
 
393
    xmlrpc_read_string(env, result, &str);
 
394
    XMLRPC_FAIL_IF_FAULT(env);
 
395
    *is_unsigned= 0;
 
396
    return my_strtoll10(str, NULL, &dummy);
 
397
  }
 
398
  case XMLRPC_TYPE_BASE64:
 
399
  {
 
400
    unsigned char buffer[8];
 
401
    const unsigned char *ptr;
 
402
    size_t len;
 
403
    long long value;
 
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);
 
409
    free((void*) ptr);
 
410
    return value;
 
411
  }
 
412
  default:
 
413
  cleanup:
 
414
    *is_unsigned= 1;
 
415
    return 0;
 
416
  }
 
417
}
 
418
 
 
419
 
 
420
static double get_value_double(xmlrpc_env *env, xmlrpc_value *result,
 
421
                               int *precision)
 
422
{
 
423
  switch (xmlrpc_value_type(result)) {
 
424
  case XMLRPC_TYPE_INT:
 
425
  {
 
426
    int intvalue;
 
427
    xmlrpc_read_int(env, result, &intvalue);
 
428
    XMLRPC_FAIL_IF_FAULT(env);
 
429
    *precision= 11;
 
430
    return (double) intvalue;
 
431
  }
 
432
  case XMLRPC_TYPE_BOOL:
 
433
  {
 
434
    xmlrpc_bool boolvalue;
 
435
    xmlrpc_read_bool(env, result, &boolvalue);
 
436
    XMLRPC_FAIL_IF_FAULT(env);
 
437
    *precision= 1;
 
438
    return boolvalue ? 1.0 : 0.0;
 
439
  }
 
440
  case XMLRPC_TYPE_DOUBLE:
 
441
  {
 
442
    double dblvalue= 0.0;
 
443
    xmlrpc_read_double(env, result, &dblvalue);
 
444
    XMLRPC_FAIL_IF_FAULT(env);
 
445
    *precision=53;
 
446
    return dblvalue;
 
447
  }
 
448
  case XMLRPC_TYPE_DATETIME:
 
449
  {
 
450
    const char *str;
 
451
    MYSQL_TIME l_time;
 
452
    int cut;
 
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);
 
456
    *precision=13;
 
457
    return (long long) TIME_to_ulonglong(&l_time);
 
458
  }
 
459
  case XMLRPC_TYPE_STRING:
 
460
  {
 
461
    const char *str;
 
462
    int dummy;
 
463
    xmlrpc_read_string(env, result, &str);
 
464
    XMLRPC_FAIL_IF_FAULT(env);
 
465
    *precision= 53;
 
466
    return my_strtod(str, NULL, &dummy);
 
467
  }
 
468
  case XMLRPC_TYPE_BASE64:
 
469
  {
 
470
    unsigned char buffer[sizeof(double)];
 
471
    const unsigned char *ptr;
 
472
    size_t len;
 
473
    double value;
 
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);
 
479
    free((void*) ptr);
 
480
    return value;
 
481
  }
 
482
  default:
 
483
  cleanup:
 
484
    *precision= 0;
 
485
    return 0.0;
 
486
  }
 
487
}
 
488
 
 
489
 
 
490
static void get_value_time(xmlrpc_env *env, xmlrpc_value *result,
 
491
                           MYSQL_TIME *p_time)
 
492
{
 
493
  int cut;
 
494
  switch (xmlrpc_value_type(result)) {
 
495
  case XMLRPC_TYPE_INT:
 
496
  {
 
497
    int intvalue;
 
498
    xmlrpc_read_int(env, result, &intvalue);
 
499
    XMLRPC_FAIL_IF_FAULT(env);
 
500
    number_to_datetime(intvalue, p_time, TIME_FUZZY_DATE, &cut);
 
501
    break;
 
502
  }
 
503
  case XMLRPC_TYPE_BOOL:
 
504
    XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "cannot convert BOOL to time");
 
505
 
 
506
  case XMLRPC_TYPE_DOUBLE:
 
507
  {
 
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);
 
512
    break;
 
513
  }
 
514
  case XMLRPC_TYPE_DATETIME:
 
515
  {
 
516
    const char *str;
 
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);
 
520
    break;
 
521
  }
 
522
  case XMLRPC_TYPE_STRING:
 
523
  {
 
524
    const char *str;
 
525
    size_t len;
 
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);
 
529
    break;
 
530
  }
 
531
  case XMLRPC_TYPE_BASE64:
 
532
  {
 
533
    unsigned char buffer[sizeof(longlong)];
 
534
    const unsigned char *ptr;
 
535
    size_t len;
 
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);
 
541
    free((void*) ptr);
 
542
    break;
 
543
  }
 
544
  default:
 
545
  cleanup:
 
546
    bzero(p_time, sizeof(*p_time));
 
547
    break;
 
548
  }
 
549
}
 
550
 
 
551
 
 
552
static const char *get_value_string(xmlrpc_env *env, xmlrpc_value *result,
 
553
                                    char *buf, int *len, CHARSET_INFO **cs)
 
554
{
 
555
  switch (xmlrpc_value_type(result)) {
 
556
  case XMLRPC_TYPE_INT:
 
557
  {
 
558
    int intvalue;
 
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;
 
563
    return buf;
 
564
  }
 
565
  case XMLRPC_TYPE_BOOL:
 
566
  {
 
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;
 
572
    return buf;
 
573
  }
 
574
  case XMLRPC_TYPE_DOUBLE:
 
575
  {
 
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;
 
581
    return buf;
 
582
  }
 
583
  case XMLRPC_TYPE_DATETIME:
 
584
  {
 
585
    const char *str;
 
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;
 
590
    return buf;
 
591
  }
 
592
  case XMLRPC_TYPE_STRING:
 
593
  {
 
594
    const char *str;
 
595
    size_t length;
 
596
    int dummy;
 
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;
 
603
    return buf;
 
604
  }
 
605
  case XMLRPC_TYPE_BASE64:
 
606
  {
 
607
    const unsigned char *ptr;
 
608
    size_t length;
 
609
    xmlrpc_read_base64(env, result, &length, &ptr);
 
610
    XMLRPC_FAIL_IF_FAULT(env);
 
611
    *len= length;
 
612
    *cs= &my_charset_bin;
 
613
    return (const char *) ptr;
 
614
  }
 
615
  default:
 
616
  cleanup:
 
617
    return NULL;
 
618
  }
 
619
}
 
620
 
 
621
 
 
622
static void store_value(xmlrpc_env *env, MYSQL_PSM_CONTEXT context,
 
623
                        xmlrpc_value *result, int type)
 
624
{
 
625
  if (xmlrpc_value_type(result) == XMLRPC_TYPE_NIL)
 
626
    type= MYSQL_TYPE_NULL;
 
627
 
 
628
  switch (type)
 
629
  {
 
630
  case MYSQL_TYPE_LONGLONG:
 
631
  {
 
632
    char is_unsigned;
 
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);
 
636
    break;
 
637
  }
 
638
  case MYSQL_TYPE_DOUBLE:
 
639
  {
 
640
    int precision;
 
641
    double val= get_value_double(env, result, &precision);
 
642
    XMLRPC_FAIL_IF_FAULT(env);
 
643
    context->cb->store_double(context, -1, val, precision);
 
644
    break;
 
645
  }
 
646
  case MYSQL_TYPE_DATETIME:
 
647
  {
 
648
    MYSQL_TIME l_time;
 
649
    get_value_time(env, result, &l_time);
 
650
    XMLRPC_FAIL_IF_FAULT(env);
 
651
    context->cb->store_time(context, -1, &l_time);
 
652
    break;
 
653
  }
 
654
  case MYSQL_TYPE_STRING:
 
655
  {
 
656
    char buffer[512];
 
657
    int len= sizeof(buffer);
 
658
    CHARSET_INFO *cs;
 
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);
 
662
    if (str != buffer)
 
663
      my_free((void*) str, MYF(0));
 
664
    break;
 
665
  }
 
666
  case MYSQL_TYPE_NULL:
 
667
  default:
 
668
  cleanup:
 
669
    context->cb->store_null(context, -1);
 
670
    break;
 
671
  }
 
672
}
 
673
 
 
674
 
 
675
static int
 
676
prepare_column_one_element(xmlrpc_env *env, xmlrpc_value *elem,
 
677
                           int mask, int *width, int *precision)
 
678
{
 
679
  const char *ptr;
 
680
  size_t size;
 
681
  
 
682
  switch (xmlrpc_value_type(elem)) {
 
683
  case XMLRPC_TYPE_INT:
 
684
    mask|= 1;
 
685
    if (*width < 7)
 
686
      *width= 7;
 
687
    break;
 
688
  case XMLRPC_TYPE_BOOL:
 
689
    mask|= 2;
 
690
    break;
 
691
  case XMLRPC_TYPE_DOUBLE:
 
692
    mask|= 4;
 
693
    if (*width < 12)
 
694
      *width= 12;
 
695
    if (*precision < 8)
 
696
      *precision= 8;
 
697
    break;
 
698
  case XMLRPC_TYPE_DATETIME:
 
699
    mask|= 8;
 
700
    xmlrpc_read_datetime_str(env, elem, &ptr);
 
701
    if ((int) (size= strlen(ptr)) > *width)
 
702
      *width= size;
 
703
    break;
 
704
  case XMLRPC_TYPE_STRING:
 
705
    mask|= 16;
 
706
    xmlrpc_read_string_lp(env, elem, &size, &ptr);
 
707
    if ((int) size > *width)
 
708
      *width= size;
 
709
    break;
 
710
  case XMLRPC_TYPE_BASE64:
 
711
    mask|= 32;
 
712
    xmlrpc_read_base64_size(env, elem, &size);
 
713
    if ((int) size > *width)
 
714
      *width= size;
 
715
    break;
 
716
  default:
 
717
    break;
 
718
  }
 
719
  return mask;
 
720
}
 
721
 
 
722
 
 
723
static int
 
724
mask_to_mysql_type(int mask)
 
725
{
 
726
  if (mask & 32)
 
727
    return MYSQL_TYPE_STRING;
 
728
  if (mask & 16 || ((mask & 8) && (mask & ~8)))
 
729
    return MYSQL_TYPE_STRING;
 
730
  if (mask & 8)
 
731
    return MYSQL_TYPE_DATETIME;
 
732
  if (mask & 4)
 
733
    return MYSQL_TYPE_DOUBLE;
 
734
  if (mask & 1)
 
735
    return MYSQL_TYPE_LONGLONG;
 
736
  if (mask & 2)
 
737
    return MYSQL_TYPE_LONGLONG;    
 
738
  return MYSQL_TYPE_NULL;
 
739
}
 
740
 
 
741
 
 
742
static int
 
743
prepare_column_type(xmlrpc_env *env, xmlrpc_value *result,
 
744
                    int *type, int *width, int *precision)
 
745
{
 
746
  int max_rows= xmlrpc_array_size(env, result), row, mask= 0;
 
747
 
 
748
  *type= MYSQL_TYPE_STRING;
 
749
  *precision= 0;
 
750
  *width= 4;
 
751
  
 
752
  for (row= 0; row < max_rows; row++)
 
753
  {
 
754
    xmlrpc_value *elem;
 
755
    
 
756
    xmlrpc_array_read_item(env, result, row, &elem);
 
757
 
 
758
    mask= prepare_column_one_element(env, elem, mask, width, precision);
 
759
  }
 
760
  
 
761
  *type= mask_to_mysql_type(mask);
 
762
 
 
763
  return max_rows;
 
764
}
 
765
 
 
766
 
 
767
static void store_struct(xmlrpc_env *env, MYSQL_PSM_CONTEXT context,
 
768
                         xmlrpc_value *result)
 
769
{
 
770
  xmlrpc_value *key, *value;
 
771
  int columns= xmlrpc_struct_size(env, result), i;
 
772
  int *types, *widths, *precision;
 
773
  xmlrpc_value **names, **column;
 
774
  
 
775
  char *ptr= (char*) 
 
776
             my_alloca(columns * (3*sizeof(int) + 2*sizeof(xmlrpc_value*)));
 
777
  
 
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*);
 
783
 
 
784
 
 
785
  xmlrpc_struct_read_member(env, result, 0, &key, &value);
 
786
 
 
787
  if (xmlrpc_value_type(value) == XMLRPC_TYPE_ARRAY)
 
788
  {
 
789
    int row, max_rows;
 
790
    int *rows= (int*) my_alloca(columns * sizeof(int));
 
791
 
 
792
 
 
793
    names[0]= key;
 
794
    column[0]= value;
 
795
    max_rows= rows[0]= 
 
796
    prepare_column_type(env, value, types, widths, precision);
 
797
    for (i= 1; i < columns; i++)
 
798
    {
 
799
      xmlrpc_struct_read_member(env, result, i, &key, &value);
 
800
      
 
801
      rows[i]= prepare_column_type(env, value, 
 
802
                                   &types[i], &widths[i], &precision[i]);
 
803
      if (rows[i] > max_rows)
 
804
        max_rows= rows[i];
 
805
 
 
806
      column[i]= value;
 
807
      names[i]= key;
 
808
    }
 
809
 
 
810
    
 
811
    for (i= 0; i < columns; i++)
 
812
    {
 
813
      const char *name;
 
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");
 
818
    } 
 
819
 
 
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++)
 
823
    {
 
824
      if (row && context->cb->row_prepare(context))
 
825
        XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
 
826
 
 
827
      for (i= 0; i < columns; i++)
 
828
      {
 
829
        if (types[i] == MYSQL_TYPE_NULL || row >= rows[i])
 
830
          context->cb->store_null(context, -1);
 
831
        else
 
832
        {
 
833
          xmlrpc_value *elem;
 
834
          xmlrpc_array_read_item(env, column[i], row, &elem);
 
835
          store_value(env, context, elem, types[i]);
 
836
        }
 
837
      }      
 
838
      context->cb->row_send(context);
 
839
    }
 
840
    context->cb->row_send_eof(context);
 
841
  }
 
842
  else
 
843
  {
 
844
    names[0]= key;
 
845
    column[0]= value;
 
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++)
 
850
    {
 
851
      xmlrpc_struct_read_member(env, result, i, &key, &value);
 
852
      
 
853
      types[i]= mask_to_mysql_type(
 
854
                prepare_column_one_element(env, value, 0, 
 
855
                                           &widths[i], &precision[i]));
 
856
      names[i]= key;
 
857
      column[i]= value;
 
858
    }
 
859
 
 
860
    for (i= 0; i < columns; i++)
 
861
    {
 
862
      const char *name;
 
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");
 
867
    } 
 
868
 
 
869
    if (context->cb->row_prepare(context))
 
870
      XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
 
871
 
 
872
    for (i= 0; i < columns; i++)
 
873
    {
 
874
      store_value(env, context, column[i], types[i]);
 
875
    }      
 
876
    context->cb->row_send(context);
 
877
    context->cb->row_send_eof(context);
 
878
  }
 
879
 
 
880
cleanup:
 
881
  my_afree((void*) types);
 
882
}
 
883
 
 
884
 
 
885
static void store_array(xmlrpc_env *env, MYSQL_PSM_CONTEXT context,
 
886
                        xmlrpc_value *result)
 
887
{
 
888
  int max_rows= xmlrpc_array_size(env, result);
 
889
  xmlrpc_value *first= NULL, *new_results= NULL;
 
890
 
 
891
  if (max_rows)
 
892
  {
 
893
    xmlrpc_array_read_item(env, result, 0, &first);
 
894
    XMLRPC_FAIL_IF_FAULT(env);
 
895
  }
 
896
 
 
897
  if (first && xmlrpc_value_type(first) == XMLRPC_TYPE_STRUCT)
 
898
  {
 
899
    /*
 
900
      transform this resultset into a struct of arrays and call store_struct
 
901
    */
 
902
    int columns= xmlrpc_struct_size(env, first), i;
 
903
  
 
904
    new_results= xmlrpc_struct_new(env);
 
905
    XMLRPC_FAIL_IF_FAULT(env);
 
906
 
 
907
    for (i= 0; i < columns; i++)
 
908
    {
 
909
      xmlrpc_value *key, *value, *column;
 
910
      int row;
 
911
 
 
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);
 
918
 
 
919
      for (row= 0; row < max_rows; row++)
 
920
      {
 
921
        xmlrpc_value *cell;
 
922
        
 
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);
 
927
        if (cell)
 
928
          xmlrpc_array_append_item(env, column, cell);
 
929
        else
 
930
          xmlrpc_array_append_item(env, column, xmlrpc_nil_new(env));
 
931
        XMLRPC_FAIL_IF_FAULT(env);
 
932
      }
 
933
    }
 
934
    store_struct(env, context, new_results);
 
935
  }
 
936
  else
 
937
  {
 
938
    int type= MYSQL_TYPE_NULL, width=4, precision=0, row;
 
939
    
 
940
    if (first)
 
941
      prepare_column_type(env, result, &type, &width, &precision);
 
942
 
 
943
    if (context->cb->row_field(context, "ARRAY",
 
944
                               type, width, precision))
 
945
      XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
 
946
 
 
947
    if (context->cb->row_prepare(context))
 
948
      XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR, "out of memory");
 
949
 
 
950
    for (row= 0; row < max_rows; row++)
 
951
    {
 
952
      xmlrpc_value *elem;
 
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);
 
958
    }
 
959
    context->cb->row_send_eof(context);
 
960
  }
 
961
 
 
962
cleanup:
 
963
  if (new_results)
 
964
    xmlrpc_DECREF(new_results);
 
965
  return;
 
966
}
 
967
 
 
968
 
 
969
static void store_result(xmlrpc_env *env, MYSQL_PSM_CONTEXT context,
 
970
                         xmlrpc_value *result)
 
971
{
 
972
  switch (xmlrpc_value_type(result))
 
973
  {
 
974
  case XMLRPC_TYPE_INT:
 
975
  {
 
976
    int value;
 
977
    xmlrpc_read_int(env, result, &value);
 
978
    XMLRPC_FAIL_IF_FAULT(env);
 
979
    context->cb->store_integer(context, -1, value, 0);
 
980
    break;
 
981
  }
 
982
  case XMLRPC_TYPE_BOOL:
 
983
  {
 
984
    xmlrpc_bool value;
 
985
    xmlrpc_read_bool(env, result, &value);
 
986
    XMLRPC_FAIL_IF_FAULT(env);
 
987
    context->cb->store_integer(context, -1, value ? 1 : 0, 0);
 
988
    break;
 
989
  }      
 
990
  case XMLRPC_TYPE_DOUBLE:
 
991
  {
 
992
    double value;
 
993
    xmlrpc_read_double(env, result, &value);
 
994
    XMLRPC_FAIL_IF_FAULT(env);
 
995
    context->cb->store_double(context, -1, value, 53);
 
996
    break;
 
997
  }      
 
998
  case XMLRPC_TYPE_DATETIME:
 
999
  {
 
1000
    const char *str;
 
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);
 
1005
    break;
 
1006
  }
 
1007
  case XMLRPC_TYPE_STRING:
 
1008
  {
 
1009
    const char *str;
 
1010
    size_t len;
 
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);
 
1015
    break;
 
1016
  }
 
1017
  case XMLRPC_TYPE_BASE64:
 
1018
  {
 
1019
    const unsigned char *ptr;
 
1020
    size_t len;
 
1021
    xmlrpc_read_base64(env, result, &len, &ptr);
 
1022
    XMLRPC_FAIL_IF_FAULT(env);
 
1023
    context->cb->store_string(context, -1, ptr, len,
 
1024
                              &my_charset_bin);
 
1025
    free((void*) ptr);
 
1026
    break;
 
1027
  }
 
1028
 
 
1029
  case XMLRPC_TYPE_ARRAY:
 
1030
    /*
 
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
 
1034
    */
 
1035
    store_array(env, context, result);
 
1036
    break;
 
1037
    
 
1038
  case XMLRPC_TYPE_STRUCT:
 
1039
    /*
 
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
 
1043
    */
 
1044
    store_struct(env, context, result);
 
1045
    break;
 
1046
    
 
1047
  default:
 
1048
  cleanup:
 
1049
    context->cb->store_null(context, -1);
 
1050
    break;
 
1051
  }
 
1052
}
 
1053
 
 
1054
 
 
1055
static xmlrpc_value *
 
1056
val_field(xmlrpc_env *env, MYSQL_PSM_CONTEXT context, int i)
 
1057
{
 
1058
  CHARSET_INFO * const utf8= &my_charset_utf8_general_ci;
 
1059
  xmlrpc_value *value= NULL;
 
1060
  int field_type, length, cut;
 
1061
  void *ptr;
 
1062
 
 
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;
 
1066
 
 
1067
  switch (field_type)
 
1068
  {
 
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));
 
1074
    break;
 
1075
#endif
 
1076
 
 
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));
 
1081
    break;
 
1082
 
 
1083
  case MYSQL_TYPE_FLOAT:
 
1084
  case MYSQL_TYPE_DOUBLE:
 
1085
    value= xmlrpc_double_new(env, context->cb->val_double(context, i));
 
1086
    break;
 
1087
 
 
1088
  case MYSQL_TYPE_YEAR:
 
1089
  {
 
1090
    char buf[8];
 
1091
    my_snprintf(buf, sizeof(buf)-1, "%04d", 
 
1092
                (int) context->cb->val_integer(context, i));
 
1093
    value= xmlrpc_datetime_new_str(env, buf);
 
1094
    break;
 
1095
  }
 
1096
 
 
1097
  case MYSQL_TYPE_DATE:
 
1098
  case MYSQL_TYPE_NEWDATE:
 
1099
  {
 
1100
    char buf[64];
 
1101
    CHARSET_INFO *cs;
 
1102
    MYSQL_TIME l_time;
 
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)
 
1106
      goto cleanup;
 
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);
 
1110
    break;
 
1111
  }
 
1112
 
 
1113
  case MYSQL_TYPE_TIME:
 
1114
  {
 
1115
    char buf[64];
 
1116
    CHARSET_INFO *cs;
 
1117
    MYSQL_TIME l_time;
 
1118
    if (!context->cb->val_string(context, i, buf, &length, &cs) ||
 
1119
        str_to_time(buf, length, &l_time, &cut))
 
1120
      goto cleanup;
 
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);
 
1124
    break;
 
1125
  }
 
1126
 
 
1127
  case MYSQL_TYPE_DATETIME:
 
1128
  {
 
1129
    char buf[64];
 
1130
    CHARSET_INFO *cs;
 
1131
    MYSQL_TIME l_time;
 
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)
 
1135
      goto cleanup;
 
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);
 
1140
    break;
 
1141
  }
 
1142
 
 
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:
 
1149
    do {
 
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)
 
1155
      {
 
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);
 
1160
        tgtstr[tgtlen]= 0;
 
1161
        value= xmlrpc_string_new_lp(env, tgtlen, tgtstr);
 
1162
        my_afree((void*) tgtstr);
 
1163
      }
 
1164
      else
 
1165
      if (res && length < alloc_length)
 
1166
      {
 
1167
        int addlen= length / cs->mbminlen * utf8->mbmaxlen, tgtlen;
 
1168
        char *tgtstr= (char*) my_malloc(addlen+1, MYF(MY_WME));
 
1169
        if (!tgtstr)
 
1170
      goto cleanup;
 
1171
        tgtlen= copy_and_convert(tgtstr, addlen, utf8,
 
1172
                                 res, length, cs, &cut);
 
1173
        tgtstr[tgtlen]= 0;
 
1174
        value= xmlrpc_string_new_lp(env, tgtlen, tgtstr);
 
1175
        my_free((void*) tgtstr, MYF(0));
 
1176
      }
 
1177
      my_afree((void*) str);
 
1178
    } while (!value);
 
1179
    break;
 
1180
 
 
1181
  case MYSQL_TYPE_BIT:
 
1182
  case MYSQL_TYPE_GEOMETRY:    
 
1183
  case MYSQL_TYPE_NEWDECIMAL:
 
1184
    value= xmlrpc_base64_new(env, length, ptr);
 
1185
    break;
 
1186
 
 
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);
 
1192
    break;
 
1193
 
 
1194
  case MYSQL_TYPE_NULL:
 
1195
  default:
 
1196
  cleanup:
 
1197
    value= xmlrpc_nil_new(env);
 
1198
    break;
 
1199
  }
 
1200
  return value;
 
1201
}
 
1202
 
 
1203
 
 
1204
static xmlrpc_value *
 
1205
build_parameter(xmlrpc_env *env, MYSQL_PSM_CONTEXT context)
 
1206
{
 
1207
  xmlrpc_value *parameters;
 
1208
  int i;
 
1209
  
 
1210
  parameters= xmlrpc_array_new(env);
 
1211
  XMLRPC_FAIL_IF_FAULT(env);
 
1212
  
 
1213
  for (i= 0; i < context->arg_count; i++)
 
1214
  {
 
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);
 
1219
  }
 
1220
  return parameters;
 
1221
 
 
1222
cleanup:
 
1223
  xmlrpc_DECREF(parameters);
 
1224
  return NULL;
 
1225
}
 
1226
 
 
1227
 
 
1228
static int xmlrpc_plugin_execute(MYSQL_PSM_ROUTINE handle,
 
1229
                                 MYSQL_PSM_CONTEXT context)
 
1230
{
 
1231
  xmlrpc_env env;
 
1232
  xmlrpc_value *parameters, *result;
 
1233
  struct xmlrpc_client *client;
 
1234
 
 
1235
  xmlrpc_env_init(&env);
 
1236
  
 
1237
  client= acquire_session(&env, context->thd);
 
1238
  
 
1239
  parameters= build_parameter(&env, context);
 
1240
  
 
1241
  XMLRPC_FAIL_IF_FAULT(&env);
 
1242
  
 
1243
  xmlrpc_client_call2(&env, client, handle->server, handle->method_name,
 
1244
                      parameters, &result);
 
1245
 
 
1246
  XMLRPC_FAIL_IF_FAULT(&env);
 
1247
 
 
1248
  store_result(&env, context, result);
 
1249
 
 
1250
  xmlrpc_DECREF(result);
 
1251
 
 
1252
  release_session(context->thd);
 
1253
 
 
1254
  xmlrpc_env_clean(&env);
 
1255
  return 0;
 
1256
 
 
1257
cleanup:
 
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);
 
1262
  return -1;
 
1263
}
 
1264
 
 
1265
 
 
1266
static int xmlrpc_plugin_release(MYSQL_PSM_ROUTINE handle)
 
1267
{
 
1268
  if (handle && handle->server)
 
1269
    xmlrpc_server_info_free(handle->server);
 
1270
  my_free(handle, MYF(MY_ALLOW_ZERO_PTR));
 
1271
  return 0;
 
1272
};
 
1273
 
 
1274
 
 
1275
/*
 
1276
  Plugin type-specific descriptor
 
1277
*/
 
1278
 
 
1279
static struct st_mysql_psmlanguage xmlrpc_plugin_descriptor=
 
1280
{
 
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 */
 
1285
};
 
1286
 
 
1287
 
 
1288
/*
 
1289
  Plugin system variables.
 
1290
*/
 
1291
 
 
1292
static struct st_mysql_sys_var* xmlrpc_plugin_variables[]= {
 
1293
  MYSQL_SYSVAR(session),
 
1294
  NULL
 
1295
};
 
1296
 
 
1297
 
 
1298
/*
 
1299
  Plugin library descriptor
 
1300
*/
 
1301
 
 
1302
mysql_declare_plugin(xmlrpc)
 
1303
{
 
1304
  MYSQL_PSMLANGUAGE_PLUGIN,   /* type                            */
 
1305
  &xmlrpc_plugin_descriptor,  /* descriptor                      */
 
1306
  "XMLRPC",                   /* name                            */
 
1307
  "MySQL AB",                 /* author                          */
 
1308
  "XML-RPC Language Demo",    /* description                     */
 
1309
  PLUGIN_LICENSE_GPL,
 
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                */
 
1315
  NULL
 
1316
}
 
1317
mysql_declare_plugin_end;
 
1318