1/* BEGIN LICENSE BLOCK 2 * Version: CMPL 1.1 3 * 4 * The contents of this file are subject to the Cisco-style Mozilla Public 5 * License Version 1.1 (the "License"); you may not use this file except 6 * in compliance with the License. You may obtain a copy of the License 7 * at www.eclipse-clp.org/license. 8 * 9 * Software distributed under the License is distributed on an "AS IS" 10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 11 * the License for the specific language governing rights and limitations 12 * under the License. 13 * 14 * The Original Code is The ECLiPSe Constraint Logic Programming System. 15 * The Initial Developer of the Original Code is Cisco Systems, Inc. 16 * Portions created by the Initial Developer are 17 * Copyright (C) 1997 - 2006 Cisco Systems, Inc. All Rights Reserved. 18 * 19 * 20 * Contributor(s): Joachim Schimpf, Stefano Novello, IC-Parc 21 * Kish Shen, CrossCore Optimization 22 * 23 * END LICENSE BLOCK */ 24 25/* 26 * ECLiPSe LIBRARY MODULE 27 * 28 * $Header: /cvsroot/eclipse-clp/Eclipse/Oci/mysql.c,v 1.9 2015/10/29 01:04:21 kish_shen Exp $ 29 * 30 * 31 * IDENTIFICATION: mysql.c 32 * 33 * AUTHOR: Joachim Schimpf 34 * AUTHOR: Stefano Novello 35 * AUTHOR: Kish Shen 36 * 37 */ 38 39/* 40 * char *sccsid = "%W% %E%"; 41 * 42 * Contents: Prolog wrappers around Oracle Call Interface 43 * 44 * Author: Stefano Novello 45 * Author: Kish Shen, Converted to MySQL from original oracle.c 46 * Jan - Feb, 2006. 47 * 48 * 49 * TODO General header for contents of this file 50 */ 51 52#ifdef _WIN32 53#include <windows.h> 54#endif 55#include <stdio.h> 56#include <stdlib.h> 57/*#include <malloc.h>*/ 58#include <string.h> 59#include <mysql/mysql.h> 60#include "external.h" /* ECLiPSe definitions */ 61#include "dbi.h" /* Oracle call interface */ 62 63 64/* ---------------------------------------------------------------------- 65 * Definitions 66 * ---------------------------------------------------------------------- */ 67 68/* these must correspond to their named structure positions in the ECLiPSe 69 option code 70*/ 71#define SESSION_OPT_DBNAME 1 72#define SESSION_OPT_STORAGE 2 73#define CURSOR_OPT_BUFFER 3 74#define CURSOR_OPT_TYPE 4 75 76#define NoErrors {err_code = 0 ; err_msg = "\0"; } 77 78#define DBI_TYPE_CONV 1 79#define DBI_BAD_CURSOR 2 80#define DBI_BAD_SESSION 3 81#define DBI_BAD_FIELD 4 82#define DBI_BAD_TEMPLATE 5 83#define DBI_NOT_QUERY 6 84#define DBI_CANCELLED 7 85#define DBI_NOT_PREPARED 8 86#define DBI_NO_PARAM 9 87#define DBI_NYI 10 88#define DBI_MEMORY 11 89#define DBI_BUFFER_OVER 12 90#define DBI_DATA_TRUNC 13 91 92#ifdef HAVE_LONG_LONG 93 94#define BUFINT long long int 95 96typedef long long long_long; 97 98#define HAVE_MYSQLBIGINT 99 100#elif defined(HAVE__INT64) 101 102typedef __int64 long_long; 103 104#define BUFINT __int64 105 106#define HAVE_MYSQLBIGINT 107 108#else 109 110#define BUFINT int 111 112#undef HAVE_MYSQLBIGINT 113 114#endif 115 116/* ---------------------------------------------------------------------- 117 * Global data 118 * ---------------------------------------------------------------------- */ 119 120int err_code; 121const char *err_msg; 122char *dbi_error[] = 123{ 124/* DBI_TYPE_CONV */ "DBI-001: type conversion failure" , 125/* DBI_BAD_CURSOR */ "DBI-002: bad cursor state" , 126/* DBI_BAD_SESSION */ "DBI-003: bad session state", 127/* DBI_BAD_FIELD */ "DBI-004: bad field name", 128/* DBI_BAD_TEMPLATE */ "DBI-005: bad template", 129/* DBI_NOT_QUERY */ "DBI-006: not a query", 130/* DBI_CANCELLED */ "DBI-007: cursor was cancelled", 131/* DBI_NOT_PREPARED */ "DBI-008: cursor was not a prepared SQL", 132/* DBI_NO_PARAM */ "DBI-009: input parameters not supplied", 133/* DBI_NYI */ "DBI-010: not implemented" , 134/* DBI_MEMORY */ "DBI-011: memory allocation problem", 135/* DBI_BUFFER_OVER */ "BBI-012: buffer overflow", 136/* DBI_DATA_TRUNC */ "BBI-013: result data truncated" 137}; 138 139/* ---------------------------------------------------------------------- 140 * Internally used procedures 141 * ---------------------------------------------------------------------- */ 142 143void 144raise_dbi_error(int code) 145{ 146 err_code= - code; 147 err_msg = dbi_error[code - 1]; 148#ifdef DEBUG 149 fprintf(stderr,"DEBUG DBI: %d %s\n",err_code,err_msg); 150#endif 151} 152 153 154void 155raise_mysql_error(MYSQL * mysql) 156{ 157 158 err_code = mysql_errno(mysql); 159 err_msg = mysql_error(mysql); 160#ifdef DEBUG 161 fprintf(stderr,"DEBUG SQL: %d %s\n",err_code,err_msg); 162#endif 163} 164 165void 166raise_mysql_stmt_error(MYSQL_STMT * stmt) 167{ 168 169 err_code = mysql_stmt_errno(stmt); 170 err_msg = mysql_stmt_error(stmt); 171#ifdef DEBUG 172 fprintf(stderr,"DEBUG OSQL: %d %s\n",err_code,err_msg); 173#endif 174} 175/* ---------------------------------------------------------------------- 176 * Auxiliary functions 177 * ---------------------------------------------------------------------- */ 178 179#define RoundupSize(s) (sizeof(word) * (1 + (s)/sizeof(word))) 180 181/* initialise the data structures associated with a template from the 182 information supplied from Prolog. This should be followed, for prepared 183 statements, by allocation of the data buffers, and the binding of the DB 184 cursor's parameter/result to the data buffers. Finally the actual values 185 of parameters are loaded into the data buffers by template_bind, or the 186 result values are extracted from the DB's return result with template_put 187 Direct statements have no parameters, and the result row do not need 188 user-supplied buffers, so only template_put has to be called. 189*/ 190int 191template_get(value v,type t,template_t * * template_out) 192{ 193 dident did; 194 char argtag; 195 word arity; 196 word i; 197 word size; 198 template_t * template; 199 pword * arg; 200 201 if (IsNil(t)) 202 { 203 *template_out = NULL; 204 return 0; 205 } 206 Check_Structure(t); 207 208 did = v.ptr->val.did; 209 arity = DidArity(did); 210 211 if (!(template = (template_t *) malloc(sizeof(template_t)))) 212 { 213 raise_dbi_error(DBI_MEMORY); 214 return -1; 215 } 216 memset(template, 0, sizeof(template_t)); 217 218 template->did = did; 219 template->arity = arity; 220 if (!(template->map = (map_t *) malloc(arity * sizeof(map_t)))) 221 { 222 raise_dbi_error(DBI_MEMORY); 223 return -1; 224 } 225 memset(template->map, 0, arity * sizeof(map_t)); 226 227 for( i = 0 ; i < arity ; i ++) 228 { 229 arg = v.ptr+i+1; 230 Dereference_(arg); 231 argtag = TagType(arg->tag) ; 232 template->map[i].prolog_tag = argtag; 233 switch (argtag) { 234 case TDICT: 235 /* LONG VARCHAR */ 236 template->map[i].ext_type = MYSQL_TYPE_VAR_STRING; 237 size = atoi( DidName(arg->val.did) ); 238 if ( size && size > 0) 239 { 240 template->map[i].size = RoundupSize(size); 241 } 242 else 243 { 244 template->map[i].size = DEFAULT_BUFFER_SIZE; 245 } 246 break; 247 case TSTRG: 248 /* LONG VARCHAR */ 249 template->map[i].ext_type = MYSQL_TYPE_VAR_STRING; 250 size = atoi( StringStart(arg->val) ); 251 if ( size && size > 0 ) 252 { 253 template->map[i].size = RoundupSize(size); 254 } 255 else 256 { 257 template->map[i].size = DEFAULT_BUFFER_SIZE; 258 } 259 break; 260 case TINT: 261 /* signed integer */ 262#ifdef HAVE_MYSQLBIGINT /* buffer for 64 bit integers if available */ 263 template->map[i].ext_type = MYSQL_TYPE_LONGLONG; 264#else 265 template->map[i].ext_type = MYSQL_TYPE_LONG; 266#endif 267 template->map[i].size = sizeof(BUFINT); 268 break; 269 case TDBL: 270 template->map[i].ext_type = MYSQL_TYPE_DOUBLE; 271 template->map[i].size = sizeof(double); 272 break; 273 default: 274 /* disable typechecking */ 275 template->map[i].prolog_tag = 0; 276 277 template->map[i].ext_type = MYSQL_TYPE_BLOB; 278 if (argtag == TCOMP && 279 TagType((arg->val.ptr + 1)->tag) == TINT 280 ) 281 template->map[i].size = 282 RoundupSize((arg->val.ptr + 1)->val.nint); 283 else 284 template->map[i].size = DEFAULT_BUFFER_SIZE*2; 285 break; 286 } 287 } 288#ifdef DEBUG 289 for( i = 0 ; i < arity ; i ++) 290 { 291 fprintf(stderr,"DEBUG template i %d size %d etype %d\n", 292 i, template->map[i].size, template->map[i].ext_type); 293 } 294 fprintf(stderr, "DEBUG template_get template=0x%x m=0x%x\n", 295 template,template->map); 296#endif 297 298 *template_out = template; 299 Succeed; 300} 301 302/* Construct a Prolog structure for a row of tuple results, copying the data 303 from the tuple buffer. For tuple (output) templates only 304 tuple_num is for compatibility for the Oracle code only and is not used 305 For MySQL, tuple_num must be 0. 306*/ 307int 308template_put(int tuple_num, template_t * template,sql_t sql_type, 309 void * buffer, void * lengths, pword * tuple) 310{ 311 word i; 312 word arg; 313 map_t * argmap; 314 char * argbuf; 315 pword *pw; 316 char *s; 317 double d; 318 pword * res; 319 extern pword * dbformat_to_term(char *, dident, type); 320 321 pw = TG; 322 Make_Struct(tuple , pw); 323 Push_Struct_Frame(template->did); 324 for (arg = 0 ; arg < template->arity ; arg++) 325 { 326 /* For prepared statements, buffers with sizes specified by the 327 results tuple template is used to receive the results. A 328 MYSQL_DATA_TRUNCATED result code is returned by 329 mysql_stmt_fetch() if the returned results are truncated. 330 */ 331 argmap = &(template->map[arg]); 332 if (sql_type == prepared) 333 { 334 if (argmap->is_null) 335 {/* NULL value */ 336 Make_Var(&pw[arg+1]); 337 continue; 338 } 339 argbuf = ((char *)buffer) + argmap->offset; 340 341 } else /* if (sql_type == direct) */ 342 { 343 /* For direct statements, the buffer sizes specified 344 by the results tuple template can be ignored, because the 345 results are returned as a byte stream by MySQL, which is then 346 converted to ECLiPSe data structure, using the global stack 347 as needed 348 */ 349 argbuf = (char *) ((MYSQL_ROW)buffer)[arg]; 350 if (argbuf == NULL) 351 {/* NULL value */ 352 Make_Var(&pw[arg+1]); 353 continue; 354 } 355 } 356 switch(argmap->prolog_tag) 357 { 358 case TDICT: 359 /* lengths is a unsigned long * rather than uword *, as defined 360 in MySQL. 361 */ 362 argbuf[((unsigned long *)lengths)[arg] ] = '\0'; 363 Make_Atom(&pw[arg+1], Did(argbuf, 0)); 364 break; 365 case TSTRG: 366 pw[arg+1].tag.kernel = TSTRG; 367 Make_Stack_String(((unsigned long *)lengths)[arg] , pw[arg+1].val, s); 368 Copy_Bytes(s, argbuf, ((unsigned long *)lengths)[arg]); 369 s[ ((unsigned long *)lengths)[arg] ] = '\0'; 370 break; 371 case TINT: 372 /* signed integer */ 373 if (sql_type == prepared) 374 { 375#if defined(HAVE_MYSQLBIGINT) 376 /* may convert to ECLiPSe TBIG if required */ 377 tag_desc[TBIG].arith_op[ARITH_BOXLONGLONG](*(long_long *)argbuf, &pw[arg+1]); 378#else 379 Make_Integer( &pw[arg+1], *(word *)argbuf); 380#endif 381 } else 382 { 383#if defined(HAVE_MYSQLBIGINT) 384 long_long i; 385#ifdef _WIN32 386 if (sscanf(((MYSQL_ROW)buffer)[arg],"%I64d",&i) == 0) { 387#else 388 if (sscanf(((MYSQL_ROW)buffer)[arg],"%lld",&i) == 0) { 389#endif 390 raise_dbi_error(DBI_TYPE_CONV); /* no integer read */ 391 return -1; 392 } 393 394 /* may convert to ECLiPSe TBIG if required */ 395 tag_desc[TBIG].arith_op[ARITH_BOXLONGLONG](i, &pw[arg+1]); 396#else 397 word i; 398 if (sscanf(((MYSQL_ROW)buffer)[arg],"%ld",&i) == 0) { 399 raise_dbi_error(DBI_TYPE_CONV); 400 return -1; 401 } 402 403 Make_Integer(&pw[arg+1], i); 404#endif 405 } 406 break; 407 case TDBL: 408 if (sql_type == prepared) 409 { 410 Make_Float( &pw[arg+1], *(double *)argbuf); 411 } else 412 { 413 double f; 414 if (sscanf(((MYSQL_ROW)buffer)[arg],"%lf",&f) == 0) { 415 raise_dbi_error(DBI_TYPE_CONV); 416 return -1; 417 } 418 419 Make_Float(&pw[arg+1], f); 420 } 421 422 break; 423/* no longer supported 424 case TFLOAT: 425 d = *(float *)argbuf; 426 Make_Float( &pw[arg+1], d); 427 break; 428*/ 429 default: 430 /* RAW -- check for dbformat header, assume rest is 431 in dbformat 432 */ 433 for (i=0; i<DBF_HEADER_LEN; i++) 434 { 435 if (argbuf[i] != dbformat_header[i]) 436 { 437 TG = pw; 438 Bip_Error(TYPE_ERROR); 439 } 440 } 441 res = dbformat_to_term( argbuf+DBF_HEADER_LEN, 0, tdict); 442 if (NULL == res) 443 { 444 /* bad error but probably won't happen since, if the 445 * string is bad we will probably overflow 446 */ 447 TG = pw; 448 Bip_Error(TYPE_ERROR); 449 } 450/* if(IsMut(res->tag)) 451 { 452 Make_Ref( &(pw[arg+1]) , res); 453 } 454 else */ 455 { 456 pw[arg+1] = *res; 457 } 458 break; 459 } 460 } 461 462 Succeed; 463} 464 465#define BindLong(lbuf, buf, max, start, len)\ 466 {\ 467 *(lbuf) = (len);\ 468 if ( *(lbuf) > (max) ) {\ 469 raise_dbi_error(DBI_BUFFER_OVER);\ 470 return -1;\ 471 }\ 472 Copy_Bytes((buf),(start),(len));\ 473 } 474 475/* based on BindLong, the header for the dbformat is placed at the start 476 of the buffer before the dbformatted string is copied 477*/ 478#define BindDbFormat(lbuf, buf, max, start, len) \ 479 {\ 480 *(lbuf) = (len)+DBF_HEADER_LEN;\ 481 if ( *(lbuf) > (max) ) {\ 482 raise_dbi_error(DBI_BUFFER_OVER);\ 483 return -1;\ 484 }\ 485 Copy_Bytes((buf),dbformat_header,DBF_HEADER_LEN);\ 486 Copy_Bytes((buf)+DBF_HEADER_LEN,(start),(len));\ 487 } 488 489/* bind the actual data supplied in Prolog structure tuple to the buffers in 490 template (used for input (param) templates) 491*/ 492int 493template_bind(int tuple_num, template_t * template,char * buffer,void * lengths,pword * tuple) 494{ 495 word i; 496 word j; 497 pword * arg; 498 value argval; 499 map_t * m; 500 char * argbuf; 501 unsigned long * largbuf; 502 extern pword * term_to_dbformat(pword *,dident); 503 504#ifdef DEBUG 505 fprintf(stderr,"tuple_num=%d template=0x%x buffer=0x%x tuple=0x%x\n", 506 tuple_num, template, buffer, tuple); 507#endif 508 509 /* if there is no template */ 510 if (IsNil(tuple->tag) && template == NULL) { Succeed; } 511 512 Check_Structure(tuple->tag) 513 if (template->did != tuple->val.ptr->val.did) 514 Bip_Error(TYPE_ERROR); 515 516 for (i = 0 ; i < template->arity ; i++) 517 { 518 m = &(template->map[i]); 519 largbuf = &(((unsigned long *)lengths)[i]); 520 arg = tuple->val.ptr + i + 1; 521#ifdef DEBUG 522 fprintf(stderr,"m=0x%x arg=0x%x\n",m,arg); 523#endif 524 Dereference_(arg); 525 if (IsRef(arg->tag)) 526 { 527 m->is_null = 1; 528 continue; 529 } 530 m->is_null = 0; 531 532 argbuf = buffer + m->offset + tuple_num * m->increment; 533 *largbuf = m->size; /* maximum size (buffer size) */ 534 535 if (m->prolog_tag && (TagType(arg->tag) != m->prolog_tag)) 536 { 537#ifdef DEBUG 538 fprintf(stderr,"DEBUG m tag %d arg tag %d\n", 539 m->prolog_tag, TagType(arg->tag)); 540#endif 541#if defined(HAVE_LONG_LONG) && SIZEOF_LONG == 4 542 /* allow TBIG for integers between 32 and 64 bits */ 543 if (!(TagType(arg->tag) == TBIG && m->prolog_tag == TINT)) 544#endif 545 Bip_Error(TYPE_ERROR); 546 } 547 switch(m->prolog_tag) 548 { 549 case TDICT: 550 BindLong(largbuf, argbuf, m->size, 551 DidName(arg->val.did), DidLength(arg->val.did)); 552#ifdef DEBUG 553 for (j=0 ; j < *largbuf ; j++) 554 fprintf(stderr,"%02x ",argbuf[j]); 555 fprintf(stderr,"\n"); 556#endif 557 break; 558 case TSTRG: 559 /* 560 * Build up a LONG VARCHAR which consists of a 32 bit 561 * string length + chars in non null terminated string 562 */ 563 BindLong(largbuf, argbuf, m->size, 564 StringStart(arg->val), StringLength(arg->val)); 565#ifdef DEBUG 566 for (j=0 ; j < *largbuf ; j++) 567 fprintf(stderr,"%02x ",argbuf[j]); 568 fprintf(stderr,"\n"); 569#endif 570 break; 571 case TINT: 572#ifdef DEBUG 573 fprintf(stderr,"DEBUG bind int argbuf 0x%x int %d\n", 574 argbuf, arg->val.nint); 575#endif 576#if defined(HAVE_MYSQLLONGLONG) && SIZEOF_LONG == 4 577 if (TagType(arg->tag) == TBIG) 578 {/* convert TBIG integers of between 33 and 64 bits to long long */ 579 int res; 580 res = tag_desc[TBIG].arith_op[ARITH_TOCLONGLONG](arg->val.ptr, argbuf); 581 if (res != PSUCCEED) Bip_Error(res); 582 break; 583 } else 584#endif 585 /* BUFINT sized signed integer */ 586 *(BUFINT *) argbuf = (BUFINT) arg->val.nint; 587 break; 588 case TDBL: 589 *(double *) argbuf = Dbl(arg->val); 590 break; 591 default: 592 { 593 pword * old_tg = TG; 594 pword * ext; 595 596 ext = term_to_dbformat(arg,NULL); 597 if (NULL == ext) 598 Bip_Error(TYPE_ERROR); 599 BindDbFormat(largbuf, argbuf, m->size, 600 (char *) BufferStart(ext), BufferSize(ext)); 601 TG = old_tg; 602 } 603 } 604 } 605 Succeed; 606} 607 608/* ---------------------------------------------------------------------- 609 * Stubs 610 * ---------------------------------------------------------------------- */ 611void 612session_init(session_t ** session) 613{ 614 session_t * s; 615 616 *session = NULL; 617 618 if (!(s = (session_t *) malloc(sizeof(session_t)))) 619 { 620 raise_dbi_error(DBI_BAD_SESSION); 621 return; 622 } 623 memset(s, 0, sizeof(session_t)); 624 s->mysql = mysql_init(NULL); 625 626 if (s->mysql == NULL) /* init failed */ 627 {/* cannot raise mysql error here -- no mysql handle! */ 628 raise_dbi_error(DBI_BAD_SESSION); 629 free(s); 630 return; 631 } 632 633 NoErrors; 634 *session = s; 635 return; 636 637} 638 639int 640session_start(session_t * s, char * username, char * host, char * password, value v_opts) 641{ 642 char * dbname = NULL; 643 pword * optarg; 644 char * engine = NULL; 645 dident optdid = v_opts.ptr->val.did; 646 647 if (host[0] == '\0') host = NULL; /* emptry string -> no hostname */ 648 649 /* processing options */ 650 if (strcmp(DidName(optdid), "options") != 0) 651 { 652 raise_dbi_error(DBI_BAD_FIELD); 653 return -1; 654 } 655 656 optarg = v_opts.ptr+SESSION_OPT_DBNAME; 657 Dereference_(optarg); 658 if (!IsRef(optarg->tag)) 659 { 660 switch (TagType(optarg->tag)) 661 { 662 case TSTRG: 663 dbname = StringStart(optarg->val); 664 break; 665 case TDICT: 666 dbname = DidName(optarg->val.did); 667 break; 668 default: 669 raise_dbi_error(DBI_BAD_FIELD); 670 return -1; /* incompatible type */ 671 break; 672 } 673 } 674 675 optarg = v_opts.ptr+SESSION_OPT_STORAGE; 676 Dereference_(optarg); 677 if (!IsRef(optarg->tag)) 678 { 679 char * trans_type; 680 switch (TagType(optarg->tag)) 681 { 682 case TDICT: 683 trans_type = DidName(optarg->val.did); 684 break; 685 case TSTRG: 686 trans_type = StringStart(optarg->val); 687 break; 688 default: 689 raise_dbi_error(DBI_BAD_FIELD); 690 return -1; 691 } 692 if (strcmp(trans_type, "transactional") == 0) 693 { 694 engine = "innodb"; 695 } 696 else if (strcmp(trans_type, "nontransactional") == 0) 697 { 698 engine = "myisam"; 699 } 700 } 701 702 if (!mysql_real_connect(s->mysql, host, username, password, dbname, 0, NULL, CLIENT_MULTI_STATEMENTS)) 703 { 704 raise_mysql_error(s->mysql); 705 return -1; 706 } 707 mysql_autocommit(s->mysql, 0); 708 /* select @@storage_engine */ 709 if (engine) 710 { 711 char sql_set[50] = "set @@storage_engine="; 712 713 strcat(sql_set, engine); 714 if (!mysql_query(s->mysql, sql_set)) 715 { 716 raise_mysql_error(s->mysql); 717 return -1; 718 } 719 } 720 721 NoErrors; 722 return 0; 723} 724 725void 726session_error_value( session_t * session, int * code, char ** msg) 727{ 728 *code = err_code; 729 *msg = (char*) err_msg; 730 731} 732 733int 734session_commit(session_t * session) 735{ 736 737 if (mysql_commit(session->mysql)) 738 { 739 raise_mysql_error(session->mysql); 740 return -1; 741 } 742 743 return 0; 744} 745 746int 747session_rollback(session_t * session) 748{ 749 if (mysql_rollback(session->mysql)) 750 { 751 raise_mysql_error(session->mysql); 752 return -1; 753 } 754 755 return 0; 756} 757 758/* initialise and prepare a cursor (no bindings) */ 759cursor_t * 760session_sql_prepare(session_t * session, char * SQL, word length, char use_prepared) 761{ 762 cursor_t * cursor; 763 764 765 if (!(cursor = (cursor_t *) malloc(sizeof(cursor_t)))) 766 { 767 raise_dbi_error(DBI_MEMORY); 768 return NULL; 769 } 770 memset(cursor, 0, sizeof(cursor_t)); 771 772 cursor->session = session; 773 cursor->state = closed; 774 cursor->sql_type = (use_prepared ? prepared : direct); 775 776 if (use_prepared) 777 {/* prepared statement */ 778 cursor->sql_length = 0; 779 cursor->s.stmt = mysql_stmt_init(session->mysql); 780 if (cursor->s.stmt == NULL) 781 { 782 raise_mysql_error(session->mysql); 783 free(cursor); 784 return NULL; 785 } 786 787 session->refs++; /* incremented before cursor_free() can be called */ 788 if (mysql_stmt_prepare(cursor->s.stmt, SQL, (unsigned long)length) != 0) 789 { 790 raise_mysql_stmt_error(cursor->s.stmt); 791 cursor_free(cursor); 792 return NULL; 793 } 794 } else 795 {/* interprete SQL as string */ 796 cursor->sql_length = length; 797 if (!(cursor->s.sql = (char *)malloc(length))) 798 { 799 raise_dbi_error(DBI_MEMORY); 800 free(cursor); 801 return NULL; 802 } 803 memcpy(cursor->s.sql, SQL, length); 804 session->refs++; 805 } 806 807 cursor->state = opened; 808 809 NoErrors; 810 return cursor; 811} 812 813/* ready the cursor for the SQL statement SQL for both prepared and direct 814 statements. Does not execute or bind the parameters for the statement 815*/ 816cursor_t * 817ready_session_sql_cursor(session_t *session, template_t *params, template_t *query, 818 char *SQL, word length, word N, char use_prepared) 819{ 820 cursor_t * cursor; 821 MYSQL_STMT * c; 822 MYSQL_BIND * bind = NULL; 823 MYSQL_RES *resdata = NULL; 824 MYSQL_FIELD *field; 825 char * b; 826 map_t * m; 827 word free_off; 828 word size; 829 unsigned long *tlengths; 830 my_bool * errors; 831#ifdef DEBUG 832 int * mytype; 833#endif 834 835 /* params != NULL only for prepared statements which have (input) parameters */ 836 if (params) 837 cursor = session_sql_prep(session, params, SQL, length, 1); 838 else 839 cursor = session_sql_prepare(session,SQL,length,use_prepared); 840 841 if (NULL == cursor) 842 return NULL; 843 844 if (query == NULL) 845 {/* query template cannot be NULL for a query */ 846 raise_dbi_error(DBI_NOT_QUERY); 847 return NULL; 848 } 849 850 cursor->tuple_template = query; 851 query->tuples = N; 852 query->from = 0; 853 query->to = 0; 854 855 if (!use_prepared) return cursor; 856 857 /* prepared statement only from here on */ 858 c = cursor->s.stmt; 859 860 free_off = 0; 861 862 resdata = mysql_stmt_result_metadata(c); 863 /* for prepared statement, we can catch the mismatch between template 864 and actual result columns early here. For direct statements, this 865 can only be done after the statement is executed 866 */ 867 if (mysql_num_fields(resdata) != query->arity) 868 { 869 TryFree(bind); 870 TryFree(resdata); 871 raise_dbi_error(DBI_BAD_TEMPLATE); 872 return NULL; 873 } 874 875 if (query->arity == 0) return cursor; 876 877 if (!(bind = (MYSQL_BIND *)malloc(sizeof(MYSQL_BIND)*query->arity))) 878 { 879 raise_dbi_error(DBI_MEMORY); 880 return NULL; 881 } 882 memset(bind, 0, sizeof(MYSQL_BIND)*query->arity); 883 if (!(tlengths = (unsigned long *) malloc(query->arity*sizeof(unsigned long)))) 884 { 885 raise_dbi_error(DBI_MEMORY); 886 return NULL; 887 } 888 if (!(errors = (my_bool *) malloc(query->arity*sizeof(my_bool)))) 889 { 890 raise_dbi_error(DBI_MEMORY); 891 return NULL; 892 } 893 894 unsigned int i; 895 for(i=0 ; i < query->arity ; i++) 896 { 897 m = &(query->map[i]); 898 if (!(field = mysql_fetch_field_direct(resdata, i))) 899 { 900#ifdef DEBUG 901 fprintf(stderr,"DEBUG error fetch field i=%d\n",i); 902#endif 903 goto mysql_error; 904 } 905 m->offset = free_off; 906 m->dbtype = field->type; 907 908 /* 909 * Make sure sizes are OK. 910 */ 911 switch(field->type) 912 { 913 case MYSQL_TYPE_TINY: 914 case MYSQL_TYPE_SHORT: 915 case MYSQL_TYPE_LONG: 916 case MYSQL_TYPE_INT24: 917 case MYSQL_TYPE_LONGLONG: 918 case MYSQL_TYPE_FLOAT: 919 case MYSQL_TYPE_DOUBLE: 920 case MYSQL_TYPE_YEAR: 921 case MYSQL_TYPE_SET: 922 case MYSQL_TYPE_ENUM: 923 case MYSQL_TYPE_NULL: 924 case MYSQL_TYPE_BIT: 925 case MYSQL_TYPE_DECIMAL: 926 case MYSQL_TYPE_NEWDECIMAL: 927 /* 928 * These are types whose string representation will never be 929 * very long so we can save a bit of buffer space in 930 * these cases 931 */ 932 if (m->size > 32) m->size = 32; 933 break; 934 case MYSQL_TYPE_TIME: 935 case MYSQL_TYPE_DATE: 936 case MYSQL_TYPE_DATETIME: 937 case MYSQL_TYPE_TIMESTAMP: 938 /* these are types which may require slightly more buffer space */ 939 if (m->size > 255) m->size = 255; 940 break; 941 case MYSQL_TYPE_STRING: 942 /* fixed length string, get the length (+1 for \0) */ 943 if (m->prolog_tag != TSTRG && m->prolog_tag != TDICT) 944 goto conversion_error; 945 946 m->size = field->length+1; 947 break; 948 949 /* last cases: no clue from DB type as to what size is needed */ 950 case MYSQL_TYPE_VAR_STRING: /* VARCHAR, BINARY data */ 951 if (m->prolog_tag != TSTRG && m->prolog_tag != TDICT) 952 goto conversion_error; 953 break; 954 case MYSQL_TYPE_BLOB: 955 if (m->prolog_tag != 0) goto conversion_error; 956 break; 957/* unsupported types - these should not occur in prepared statements 958 case MYSQL_TYPE_GEOMETRY: 959*/ 960 default: 961 goto conversion_error; 962 } 963 964 m->increment = m->size; 965 free_off += N * m->size; 966 } 967 968 if (!(b = (char *)malloc(free_off))) 969 { 970 raise_dbi_error(DBI_MEMORY); 971 return NULL; 972 } 973#ifdef DEBUG 974 fprintf(stderr,"DEBUG buffer = 0x%x\n",b); 975#endif 976 cursor->tuple_buffer = b; 977 cursor->tuple_datalengths = tlengths; 978 cursor->tuple_errors = errors; 979 980 for(i=0 ; i < query->arity ; i++) 981 { 982 m = &(query->map[i]); 983 bind[i].buffer_type = m->ext_type; 984 bind[i].buffer = (char *)b+m->offset; 985 bind[i].buffer_length = m->size; 986 bind[i].length = (unsigned long *) &(tlengths[i]); 987 bind[i].is_null = &(m->is_null); 988 m->is_null = 0; 989 bind[i].error = &(errors[i]); 990#ifdef DEBUG 991 for(i=0 ; i < query->arity ; i++) 992 fprintf(stderr,"DEBUG bind[%2d]\toff=%8d,size=%8d,ext_type=%8d,dbtype=%8d\n", 993 i, 994 query->map[i].offset, 995 bind[i].length, 996 bind[i].buffer_type, 997 query->map[i].dbtype); 998 999 fprintf(stderr,"DEBUG buffer size = %d\n",free_off); 1000#endif 1001 } 1002 if (mysql_stmt_bind_result(cursor->s.stmt, bind)) 1003 { 1004 goto mysql_error; 1005 } 1006 TryFree(bind); 1007 TryFree(resdata); 1008 return cursor; 1009 1010mysql_error: 1011 TryFree(bind); 1012 TryFree(resdata); 1013 raise_mysql_error(session->mysql); 1014 cursor_free(cursor); 1015 return NULL; 1016 1017conversion_error: 1018 TryFree(bind); 1019 TryFree(resdata); 1020 raise_dbi_error(DBI_TYPE_CONV); 1021 cursor_free(cursor); 1022 return NULL; 1023 1024} 1025 1026 1027/* prepare the param template's data buffer, and bind them to the DB */ 1028cursor_t * 1029session_sql_prep(session_t *session, 1030 template_t *template, char *SQL, word length, word N) 1031{ 1032 cursor_t * cursor; 1033 word i,j; 1034 map_t * m; 1035 word free_off, err; 1036 char * b; 1037 MYSQL_BIND *bind = NULL; 1038 1039 cursor = session_sql_prepare(session,SQL,length,1); 1040 if (NULL == cursor) 1041 return NULL; 1042 1043 cursor->param_template = template; 1044 cursor->tuple_template = NULL; 1045 if (template == NULL) return cursor; 1046 1047 template->tuples = N; 1048 template->from = 0; 1049 template->to = 0; 1050 1051 free_off = 0; 1052 1053 if (template->arity != mysql_stmt_param_count(cursor->s.stmt)) 1054 { 1055 raise_dbi_error(DBI_BAD_TEMPLATE); 1056 return NULL; 1057 } 1058 1059 for(i=0 ; i < template->arity ; i++) 1060 { 1061 unsigned long size = DEFAULT_BUFFER_SIZE; 1062 1063 m = &(template->map[i]); 1064 1065 m->offset = free_off; 1066 1067 1068 free_off += m->size * N; 1069 m->increment = m->size; 1070/* m->loffset = free_off;*/ 1071 free_off += sizeof(word) * N; 1072 1073 m->increment = m->size; 1074 /* m->lincrement = sizeof(word);*/ 1075 } 1076 1077 if (!(cursor->param_buffer = (char *)malloc(free_off))) 1078 { 1079 raise_dbi_error(DBI_MEMORY); 1080 return NULL; 1081 } 1082 b = cursor->param_buffer; 1083 1084 1085 if (!(bind = (MYSQL_BIND *)malloc(sizeof(MYSQL_BIND)*template->arity))) 1086 { 1087 raise_dbi_error(DBI_MEMORY); 1088 return NULL; 1089 } 1090 memset(bind, 0, sizeof(MYSQL_BIND)*template->arity); 1091 1092 if (!(cursor->param_datalengths = (unsigned long *) malloc(template->arity*sizeof(unsigned long)))) 1093 { 1094 raise_dbi_error(DBI_MEMORY); 1095 return NULL; 1096 } 1097 for(i=0 ; i < template->arity ; i++) 1098 { 1099 m = &(template->map[i]); 1100 1101 bind[i].length = &(cursor->param_datalengths[i]); 1102 bind[i].buffer_type = m->ext_type; 1103 bind[i].buffer = (char *) b + m->offset; 1104 bind[i].buffer_length = m->size; 1105 bind[i].is_null = &(m->is_null); 1106 } 1107 1108 if (err=mysql_stmt_bind_param(cursor->s.stmt, bind)) 1109 { 1110 TryFree(bind); 1111 raise_mysql_stmt_error(cursor->s.stmt); 1112 cursor_free(cursor); 1113 return NULL; 1114 } 1115 1116#ifdef DEBUG 1117 fprintf(stderr,"DEBUG buffer = 0x%x\n",cursor->param_buffer); 1118#endif 1119 return cursor; 1120} 1121 1122int 1123session_tostr(session_t * session, char *buf, int quoted) 1124{ 1125 sprintf(buf, "'MySQLS'(16'%x)", (word) session); 1126 return strlen(buf); /* size of actual string */ 1127} 1128 1129void 1130session_close(session_t * session) 1131{ 1132 mysql_close(session->mysql); 1133 session->mysql = NULL; 1134 session->closed = 1; 1135 return; 1136} 1137 1138/* sets MySQL specific options for cursor. opts must be a structure */ 1139int 1140cursor_set_options(cursor_t * cursor, value v_opts) 1141{ 1142 pword * optarg; 1143 char * option; 1144 dident optdid = v_opts.ptr->val.did; 1145 1146 /* processing options */ 1147 if (strcmp(DidName(optdid), "options") != 0) 1148 { 1149 raise_dbi_error(DBI_BAD_FIELD); 1150 return -1; 1151 } 1152 1153 optarg = v_opts.ptr+CURSOR_OPT_BUFFER; 1154 Dereference_(optarg); 1155 switch (TagType(optarg->tag)) 1156 { 1157 case TSTRG: 1158 option = StringStart(optarg->val); 1159 break; 1160 case TDICT: 1161 option = DidName(optarg->val.did); 1162 break; 1163 default: 1164 raise_dbi_error(DBI_BAD_FIELD); 1165 return -1; 1166 break; 1167 } 1168 cursor->server_cursor = (strcmp(option, "server") == 0 ? 1 : 0); 1169 1170 optarg = v_opts.ptr+CURSOR_OPT_TYPE; 1171 Dereference_(optarg); 1172 switch (TagType(optarg->tag)) 1173 { 1174 case TSTRG: 1175 option = StringStart(optarg->val); 1176 break; 1177 case TDICT: 1178 option = DidName(optarg->val.did); 1179 break; 1180 default: 1181 raise_dbi_error(DBI_BAD_FIELD); 1182 return -1; 1183 break; 1184 } 1185 if (strcmp(option, "no_cursor") == 0) 1186 { 1187 cursor->cursor_type = CURSOR_NO_CURSOR; 1188 } else if (strcmp(option, "read_only") == 0) 1189 { 1190 cursor->cursor_type = CURSOR_READ_ONLY; 1191 } else 1192 { 1193 raise_dbi_error(DBI_BAD_FIELD); 1194 return -1; 1195 } 1196 return 0; 1197} 1198 1199/* executes the statement in cursor. For prepared statements, input params 1200 must already be bound 1201*/ 1202int 1203cursor_sql_execute(cursor_t * cursor, int with_defaults) 1204{ 1205 unsigned int nfield = 0; 1206#ifdef DEBUG 1207 fprintf(stderr,"cursor_sql_execute\n"); 1208#endif 1209 1210 if (cursor->session->closed || 1211 cursor->state == closed || 1212 cursor->state == idle 1213 ) 1214 { 1215 raise_dbi_error(DBI_BAD_CURSOR); 1216 return -1; 1217 } 1218 1219 if (with_defaults) 1220 { 1221 cursor->server_cursor = 0; 1222 cursor->cursor_type = CURSOR_NO_CURSOR; 1223 } 1224 1225 if (cursor->sql_type == prepared) 1226 {/* prepared statememnt */ 1227 unsigned long type; 1228 1229 /* free any previous results */ 1230 if (cursor->state == executed) mysql_stmt_free_result(cursor->s.stmt); 1231 if (cursor->cursor_type == CURSOR_READ_ONLY) 1232 type = CURSOR_TYPE_READ_ONLY; 1233 else 1234 type = CURSOR_TYPE_NO_CURSOR; 1235 mysql_stmt_attr_set(cursor->s.stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); 1236 if (mysql_stmt_execute(cursor->s.stmt)) 1237 { 1238 raise_mysql_stmt_error(cursor->s.stmt); 1239 return -1; 1240 } 1241 cursor->prolog_processed_count = (word) mysql_stmt_affected_rows(cursor->s.stmt); 1242 if (!cursor->server_cursor && /* store result on client side */ 1243 mysql_stmt_store_result(cursor->s.stmt)) 1244 { 1245 raise_mysql_stmt_error(cursor->s.stmt); 1246 return -1; 1247 } 1248 nfield = mysql_stmt_field_count(cursor->s.stmt); 1249 } else /* if cursor->sql_type == direct */ 1250 { 1251 if (cursor->state != opened) 1252 {/* direct statements can only be executed once */ 1253 raise_dbi_error(DBI_NOT_PREPARED); 1254 return -1; 1255 } 1256 1257 if (mysql_real_query(cursor->session->mysql, cursor->s.sql, cursor->sql_length)) 1258 { 1259 raise_mysql_error(cursor->session->mysql); 1260 TryFree(cursor->s.sql); 1261 return -1; 1262 } 1263 TryFree(cursor->s.sql); 1264 cursor->prolog_processed_count = (word) mysql_affected_rows(cursor->session->mysql); 1265 if (cursor->server_cursor) 1266 {/* result on server side */ 1267 cursor->s.res = mysql_use_result(cursor->session->mysql); 1268 } else 1269 {/* result on client side */ 1270 cursor->s.res = mysql_store_result(cursor->session->mysql); 1271 } 1272 if (cursor->s.res == NULL) 1273 { 1274 nfield = mysql_field_count(cursor->session->mysql); 1275 if (nfield != 0) 1276 {/* error - should have returned results */ 1277 raise_mysql_error(cursor->session->mysql); 1278 return -1; 1279 } 1280 } else 1281 { 1282 nfield = mysql_num_fields(cursor->s.res); 1283 } 1284 } 1285 if (cursor->tuple_template == NULL) 1286 {/* no tuple template, should have no output columns */ 1287 if (nfield != 0) { 1288 raise_dbi_error(DBI_BAD_TEMPLATE); 1289 return -1; 1290 } 1291 } 1292 else if (cursor->tuple_template->arity != nfield) 1293 { 1294 raise_dbi_error(DBI_BAD_TEMPLATE); 1295 return -1; 1296 } 1297 1298 cursor->state = executed; 1299 return 0; 1300} 1301 1302 1303/* MySQL returns only 1 tuple at a time */ 1304int 1305cursor_one_tuple(cursor_t *cursor) 1306{ 1307 template_t * t; 1308 void * b; 1309 int err; 1310 1311 if (cursor->session->closed) 1312 { 1313 raise_dbi_error(DBI_BAD_CURSOR); 1314 return -1; 1315 } 1316 1317 if (! cursor->tuple_template) 1318 { 1319 raise_dbi_error(DBI_NOT_QUERY); 1320 return -1; 1321 } 1322 1323 t = cursor->tuple_template; 1324 b = cursor->tuple_buffer; 1325 1326#ifdef DEBUG 1327/* fprintf(stderr,"DEBUG: oexfet rpc = %d from = %d to = %d\n", 1328 cursor->cda.rpc, t->from, t->to);*/ 1329 fprintf(stderr,"DEBUG: state = %d\n",cursor->state); 1330#endif 1331 1332 if (cursor->state == nodata) 1333 { 1334 cursor->state = idle; 1335 return 0; 1336 } 1337 1338 if (cursor->state == idle) 1339 { 1340 /* 1341 * Application is trying to read on after it has already 1342 * been told the cursor is not giving any more data 1343 * or it has, itself cancelled the cursor 1344 */ 1345 raise_dbi_error(DBI_CANCELLED); 1346 return -1; 1347 } 1348 1349 if (cursor->state == opened) 1350 { 1351 if (cursor->param_template != NULL) 1352 {/* has parameters, but these are not yet bound to actual values */ 1353 raise_dbi_error(DBI_NO_PARAM); 1354 return -1; 1355 } 1356 if (err = cursor_sql_execute(cursor, 1)) return err; 1357 } 1358 1359 /* using from..to is for compatibility with Oracle oci */ 1360 t->to = t->from; 1361 if (cursor->state == executed) /* parameters set or */ 1362 { 1363#ifdef DEBUG 1364 fprintf(stderr,"DEBUG: tuples = %d\n",t->tuples); 1365#endif 1366 if (cursor->sql_type == prepared) 1367 { 1368 switch (mysql_stmt_fetch(cursor->s.stmt)) 1369 { 1370 case MYSQL_NO_DATA: 1371 mysql_stmt_free_result(cursor->s.stmt); 1372 cursor->state = nodata; 1373 return 0; 1374 break; 1375 case 1: /* error */ 1376 raise_mysql_stmt_error(cursor->s.stmt); 1377 return -1; 1378 break; 1379 case MYSQL_DATA_TRUNCATED: 1380 /* truncated - cinversion problems or buffer(s) too small */ 1381 raise_dbi_error(DBI_DATA_TRUNC); 1382 return -1; 1383 break; 1384 /* otherwise, there is no problem */ 1385 } 1386 1387 } else 1388 { 1389 /* note the results and lengths are stored in the s.res structure. 1390 this is freed when the result is freed 1391 */ 1392 if (cursor->s.res == NULL) 1393 {/* no result to return */ 1394 cursor->state = nodata; 1395 return 0; 1396 } 1397 if ((cursor->tuple_buffer = (void *) mysql_fetch_row(cursor->s.res)) == NULL) 1398 { 1399 mysql_free_result(cursor->s.res); 1400 cursor->tuple_datalengths = NULL; 1401 cursor->tuple_errors = NULL; 1402 cursor->state = nodata; 1403 return 0; 1404 } 1405 cursor->tuple_datalengths = mysql_fetch_lengths(cursor->s.res); 1406 } 1407 } 1408 1409 else 1410 { 1411 raise_dbi_error(DBI_BAD_CURSOR); 1412 return -1; 1413 } 1414 t->to = t->from + 1; 1415 1416 1417#ifdef DEBUG 1418/* fprintf(stderr,"DEBUG: oexfet rpc = %d from = %d to = %d\n", 1419 cursor->cda.rpc, t->from, t->to);*/ 1420#endif 1421 1422 return 0; 1423} 1424 1425int 1426cursor_N_tuples(cursor_t * cursor, word * n, pword * tuple_listp, pword ** tp) 1427{ 1428 pword * head; 1429 template_t * template; 1430 int res; 1431 1432 template = cursor->tuple_template; 1433 1434 *tp = tuple_listp; 1435 for (*n=0; ; (*n)++) 1436 { 1437 /* 1438 * At this point *cdr is a pointer to the cell being created 1439 * in this loop. I.e the cdr of the previous cell or the whole 1440 * list 1441 */ 1442 1443 if (cursor->state == nodata) break; /* exhausted data previously, just return */ 1444 if (cursor_one_tuple(cursor) == -1) return -1; /* error has occurred */ 1445 if (template->to == template->from) break; /* reached end */ 1446 1447 /* new cons cell */ 1448 head = TG; 1449 Push_List_Frame(); 1450 Make_List(*tp, head); 1451 if (res = template_put(*n, template, cursor->sql_type, 1452 cursor->tuple_buffer, cursor->tuple_datalengths, head)) 1453 { 1454 return res; 1455 } 1456 *tp = head + 1; 1457 } 1458 Make_Var(*tp); 1459 template->from = template->to; 1460 1461 return 0; 1462} 1463 1464int 1465cursor_N_execute(cursor_t * cursor, word * tuplep, value v_tuples, type t_tuples, pword ** cdrp) 1466{ 1467 int res; 1468 pword * car; 1469 1470 1471 for ( *tuplep = 0 ; 1472 IsList(t_tuples) ; 1473 (*tuplep)++) 1474 { 1475 car = v_tuples.ptr; 1476 *cdrp = car + 1; 1477 Dereference_(car); /* access the data */ 1478 1479 if (res = template_bind(0, cursor->param_template, 1480 cursor->param_buffer, cursor->param_datalengths, car)) 1481 { 1482#ifdef DEBUG 1483 fprintf(stderr,"DEBUG tuple=%d\n",tuplep); 1484#endif 1485 return res; 1486 } 1487 1488 if (cursor_sql_execute(cursor, 1)) 1489 { 1490 return -1; 1491 } 1492 1493 Dereference_((*cdrp)); /* proceed to next element */ 1494 t_tuples = (*cdrp)->tag; 1495 v_tuples = (*cdrp)->val; 1496 } 1497 1498 1499 return 0; 1500} 1501 1502int 1503cursor_tostr(cursor_t * cursor, char *buf, int quoted) 1504{ 1505 sprintf(buf, "'MySQLC'(16'%x)", (word) cursor); 1506 return strlen(buf); /* size of actual string */ 1507} 1508 1509void 1510cursor_free(cursor_t * cursor) 1511{ 1512 session_t * s; 1513 1514 if (cursor == NULL) return; 1515 s = cursor->session; 1516 1517 if (cursor->state != closed && ! s->closed ) 1518 { 1519 1520 if (cursor->sql_type == prepared) 1521 { 1522 /* mysql_stmt_free_result() need not be called -- 1523 results cancelled automatically 1524 */ 1525 if (mysql_stmt_close(cursor->s.stmt)!= 0 ) 1526 { 1527 raise_mysql_stmt_error(cursor->s.stmt); 1528 /* we can't return an error here because the copy method 1529 returns void. Just print the error and return 1530 */ 1531 fprintf(stderr, "MySQl error freeing cursor: %d %s\n", err_code,err_msg); 1532 NoErrors; 1533 return; 1534 } 1535 } else 1536 { /* direct SQL */ 1537 if (cursor->state == executed) 1538 { 1539 mysql_free_result(cursor->s.res); 1540 /* freeing the results free the tuple + tuple length 1541 buffers as well */ 1542 cursor->tuple_buffer = NULL; 1543 cursor->tuple_datalengths = NULL; 1544 } else if (cursor->state == opened) 1545 { 1546 TryFree(cursor->s.sql); 1547 } 1548 } 1549 } 1550 1551 /* 1552 * free extended cursor 1553 */ 1554 1555#ifdef DEBUG 1556 fprintf(stderr,"cursor free\n"); 1557#endif 1558 if (cursor->param_template) { 1559 TryFree(cursor->param_template->map); 1560 } 1561 TryFree(cursor->param_template); 1562 if (cursor->tuple_template) { 1563 TryFree(cursor->tuple_template->map); 1564 } 1565 TryFree(cursor->tuple_template); 1566 TryFree(cursor->param_buffer); 1567 TryFree(cursor->tuple_errors); 1568 TryFree(cursor->param_datalengths); 1569 if (cursor->sql_type == prepared) 1570 {/* these are malloc'ed only for prepared statements. 1571 If session has already been freed, then tuple_buffer etc. 1572 would be freed by MySQL already, even though they still have 1573 non-zero values 1574 */ 1575 TryFree(cursor->tuple_buffer); 1576 TryFree(cursor->tuple_datalengths); 1577 } 1578 1579 free(cursor); 1580 1581 /* 1582 * update session cursor count 1583 */ 1584 if (--(s->refs) == 0) 1585 { 1586 if (s->closed) free(s); 1587 else 1588 { 1589 /* this should not happen */ 1590 fprintf(stderr, "Dbi error: problem with session handle reference count. Please report problem.\n"); 1591 free(s); 1592 } 1593 } 1594} 1595 1596int 1597cursor_field_value(cursor_t * cursor, field_t field,void ** value) 1598{ 1599 if (cursor->session->closed) 1600 { 1601 raise_dbi_error(DBI_BAD_CURSOR); 1602 return -1; 1603 } 1604 switch(field) 1605 { 1606 case state : 1607 *value = &(cursor->state); 1608 break; 1609 case rows_processed_count : 1610 /* A coursor has 2 templates now so no 1 processed count. 1611 if (cursor->template) 1612 cursor->prolog_processed_count += 1613 cursor->template->to - cursor->template->from; 1614 */ 1615 *value = &(cursor->prolog_processed_count); 1616 break; 1617 case return_code : 1618 *value = &err_code; 1619 break; 1620 case return_code_as_string : 1621 *value = &err_msg; 1622 break; 1623 default : 1624 raise_dbi_error(DBI_BAD_FIELD); 1625 return -1; 1626 } 1627 1628 return 0; 1629} 1630 1631/* these initilization and finalization calls does not seem to be strictly 1632 needed, and were introduced only in MySQL 5.0.3, but they are recommended 1633 in the manual 1634*/ 1635void 1636dbi_init() 1637{ 1638 mysql_library_init(-1, NULL, NULL); 1639} 1640 1641void 1642dbi_final() 1643{ 1644 mysql_library_end(); 1645} 1646