mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1098 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1098 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/************** MyConn C++ Program Source Code File (.CPP) **************/
 | 
						|
/* PROGRAM NAME: MYCONN                                                 */
 | 
						|
/* -------------                                                        */
 | 
						|
/*  Version 1.9                                                         */
 | 
						|
/*                                                                      */
 | 
						|
/* COPYRIGHT:                                                           */
 | 
						|
/* ----------                                                           */
 | 
						|
/*  (C) Copyright to the author Olivier BERTRAND          2007-2017     */
 | 
						|
/*                                                                      */
 | 
						|
/* WHAT THIS PROGRAM DOES:                                              */
 | 
						|
/* -----------------------                                              */
 | 
						|
/*  Implements a connection to MySQL.                                   */
 | 
						|
/*  It can optionally use the embedded MySQL library.                   */
 | 
						|
/*                                                                      */
 | 
						|
/* WHAT YOU NEED TO COMPILE THIS PROGRAM:                               */
 | 
						|
/* --------------------------------------                               */
 | 
						|
/*                                                                      */
 | 
						|
/*  REQUIRED FILES:                                                     */
 | 
						|
/*  ---------------                                                     */
 | 
						|
/*    MYCONN.CPP     - Source code                                      */
 | 
						|
/*    MYCONN.H       - MYCONN class declaration file                    */
 | 
						|
/*    GLOBAL.H       - Global declaration file                          */
 | 
						|
/*                                                                      */
 | 
						|
/*  REQUIRED LIBRARIES:                                                 */
 | 
						|
/*  -------------------                                                 */
 | 
						|
/*    Large model C library                                             */
 | 
						|
/*                                                                      */
 | 
						|
/*  REQUIRED PROGRAMS:                                                  */
 | 
						|
/*  ------------------                                                  */
 | 
						|
/*    IBM, Borland, GNU or Microsoft C++ Compiler and Linker            */
 | 
						|
/*                                                                      */
 | 
						|
/************************************************************************/
 | 
						|
#include "my_global.h"
 | 
						|
#if !defined(MYSQL_PREPARED_STATEMENTS)
 | 
						|
#include "my_sys.h"
 | 
						|
#include "mysqld_error.h"
 | 
						|
#endif   // !MYSQL_PREPARED_STATEMENTS
 | 
						|
#if defined(_WIN32)
 | 
						|
//#include <windows.h>
 | 
						|
#else   // !_WIN32
 | 
						|
#include "osutil.h"
 | 
						|
#endif  // !_WIN32
 | 
						|
 | 
						|
#include "global.h"
 | 
						|
#include "plgdbsem.h"
 | 
						|
#include "plgcnx.h"                       // For DB types
 | 
						|
#include "resource.h"
 | 
						|
//#include "value.h"
 | 
						|
//#include "valblk.h"
 | 
						|
#include "xobject.h"
 | 
						|
#define  DLL_EXPORT            // Items are exported from this DLL
 | 
						|
#include "myconn.h"
 | 
						|
 | 
						|
//extern "C" int   zconv;
 | 
						|
int GetConvSize(void);
 | 
						|
extern MYSQL_PLUGIN_IMPORT uint  mysqld_port;
 | 
						|
extern MYSQL_PLUGIN_IMPORT char *mysqld_unix_port;
 | 
						|
 | 
						|
DllExport void PushWarning(PGLOBAL, THD*, int level = 1);
 | 
						|
 | 
						|
// Returns the current used port
 | 
						|
uint GetDefaultPort(void)
 | 
						|
{
 | 
						|
  return mysqld_port;
 | 
						|
} // end of GetDefaultPort
 | 
						|
 | 
						|
#if !defined(MYSQL_PREPARED_STATEMENTS)
 | 
						|
/**************************************************************************
 | 
						|
  Alloc struct for use with unbuffered reads. Data is fetched by domand
 | 
						|
  when calling to mysql_fetch_row.
 | 
						|
  mysql_data_seek is a noop.
 | 
						|
 | 
						|
  No other queries may be specified with the same MYSQL handle.
 | 
						|
  There shouldn't be much processing per row because mysql server shouldn't
 | 
						|
  have to wait for the client (and will not wait more than 30 sec/packet).
 | 
						|
  NOTE: copied from client.c cli_use_result
 | 
						|
**************************************************************************/
 | 
						|
static MYSQL_RES *connect_use_result(MYSQL *mysql)
 | 
						|
{
 | 
						|
  MYSQL_RES *result;
 | 
						|
  DBUG_ENTER("connect_use_result");
 | 
						|
 | 
						|
  if (!mysql->fields)
 | 
						|
    DBUG_RETURN(NULL);
 | 
						|
 | 
						|
  if (mysql->status != MYSQL_STATUS_GET_RESULT) {
 | 
						|
    my_message(ER_UNKNOWN_ERROR, "Command out of sync", MYF(0));
 | 
						|
    DBUG_RETURN(NULL);
 | 
						|
    } // endif status
 | 
						|
 | 
						|
  if (!(result = (MYSQL_RES*) my_malloc(PSI_NOT_INSTRUMENTED,
 | 
						|
                  sizeof(*result) + sizeof(ulong) * mysql->field_count,
 | 
						|
				          MYF(MY_WME | MY_ZEROFILL))))
 | 
						|
    DBUG_RETURN(NULL);
 | 
						|
 | 
						|
  result->lengths = (ulong*)(result+1);
 | 
						|
  result->methods = mysql->methods;
 | 
						|
 | 
						|
  /* Ptrs: to one row */
 | 
						|
  if (!(result->row = (MYSQL_ROW)my_malloc(PSI_NOT_INSTRUMENTED,
 | 
						|
                sizeof(result->row[0]) * (mysql->field_count+1), MYF(MY_WME)))) {
 | 
						|
    my_free(result);
 | 
						|
    DBUG_RETURN(NULL);
 | 
						|
    }  // endif row
 | 
						|
 | 
						|
  result->fields =	mysql->fields;
 | 
						|
  result->field_alloc =	mysql->field_alloc;
 | 
						|
  result->field_count =	mysql->field_count;
 | 
						|
  result->current_field = 0;
 | 
						|
  result->handle =	mysql;
 | 
						|
  result->current_row =	0;
 | 
						|
  mysql->fields = 0;			/* fields is now in result */
 | 
						|
  clear_alloc_root(&mysql->field_alloc);
 | 
						|
  mysql->status = MYSQL_STATUS_USE_RESULT;
 | 
						|
  mysql->unbuffered_fetch_owner = &result->unbuffered_fetch_cancelled;
 | 
						|
  DBUG_RETURN(result);			/* Data is ready to be fetched */
 | 
						|
} // end of connect_use_result
 | 
						|
#endif   // !MYSQL_PREPARED_STATEMENTS
 | 
						|
 | 
						|
/************************************************************************/
 | 
						|
/*  MyColumns: constructs the result blocks containing all columns      */
 | 
						|
/*  of a MySQL table or view.                                           */
 | 
						|
/*  info = TRUE to get catalog column information.                     */
 | 
						|
/************************************************************************/
 | 
						|
PQRYRES MyColumns(PGLOBAL g, THD *thd, const char *host, const char *db,
 | 
						|
                  const char *user, const char *pwd,
 | 
						|
                  const char *table, const char *colpat,
 | 
						|
                  int port, bool info)
 | 
						|
  {
 | 
						|
  int  buftyp[] = {TYPE_STRING, TYPE_SHORT,  TYPE_STRING, TYPE_INT,
 | 
						|
                   TYPE_STRING, TYPE_SHORT,  TYPE_SHORT,  TYPE_SHORT,
 | 
						|
                   TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING,
 | 
						|
                   TYPE_STRING};
 | 
						|
  XFLD fldtyp[] = {FLD_NAME, FLD_TYPE,  FLD_TYPENAME, FLD_PREC,
 | 
						|
                   FLD_KEY,  FLD_SCALE, FLD_RADIX,    FLD_NULL,
 | 
						|
                   FLD_REM,  FLD_NO,    FLD_DEFAULT,  FLD_EXTRA,
 | 
						|
                   FLD_CHARSET};
 | 
						|
  //unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0};
 | 
						|
	unsigned int length[] = {0, 4, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0};
 | 
						|
	PCSZ    fmt;
 | 
						|
	char   *fld, *colname, *chset, v, buf[128], uns[16], zero[16];
 | 
						|
  int     i, n, nf = 0, ncol = sizeof(buftyp) / sizeof(int);
 | 
						|
  int     len, type, prec, rc;
 | 
						|
	bool    b;
 | 
						|
  PQRYRES qrp;
 | 
						|
  PCOLRES crp;
 | 
						|
  MYSQLC  myc;
 | 
						|
 | 
						|
  if (!port)
 | 
						|
    port = mysqld_port;
 | 
						|
 | 
						|
  if (!info) {
 | 
						|
    /********************************************************************/
 | 
						|
    /*  Open the connection with the MySQL server.                      */
 | 
						|
    /********************************************************************/
 | 
						|
    if (myc.Open(g, host, db, user, pwd, port))
 | 
						|
      return NULL;
 | 
						|
 | 
						|
    /********************************************************************/
 | 
						|
    /*  Do an evaluation of the result size.                            */
 | 
						|
    /********************************************************************/
 | 
						|
    STRING cmd(g, 64, "SHOW FULL COLUMNS FROM ");
 | 
						|
		b = cmd.Append('`');
 | 
						|
    b |= cmd.Append((PSZ)table);
 | 
						|
		b |= cmd.Append('`');
 | 
						|
 | 
						|
    b |= cmd.Append(" FROM ");
 | 
						|
    b |= cmd.Append((PSZ)(db ? db : PlgGetUser(g)->DBName));
 | 
						|
 | 
						|
    if (colpat) {
 | 
						|
      b |= cmd.Append(" LIKE ");
 | 
						|
      b |= cmd.Append((PSZ)colpat);
 | 
						|
      } // endif colpat
 | 
						|
 | 
						|
    if (b) {
 | 
						|
      strcpy(g->Message, "Out of memory");
 | 
						|
      return NULL;
 | 
						|
      } // endif b
 | 
						|
 | 
						|
    if (trace(1))
 | 
						|
      htrc("MyColumns: cmd='%s'\n", cmd.GetStr());
 | 
						|
 | 
						|
    if ((n = myc.GetResultSize(g, cmd.GetStr())) < 0) {
 | 
						|
      myc.Close();
 | 
						|
      return NULL;
 | 
						|
      } // endif n
 | 
						|
 | 
						|
    /********************************************************************/
 | 
						|
    /*  Get the size of the name and default columns.                   */
 | 
						|
    /********************************************************************/
 | 
						|
    length[0] = myc.GetFieldLength(0);
 | 
						|
//  length[10] = myc.GetFieldLength(5);
 | 
						|
  } else {
 | 
						|
    n = 0;
 | 
						|
    length[0] = 128;
 | 
						|
  } // endif info
 | 
						|
 | 
						|
  /**********************************************************************/
 | 
						|
  /*  Allocate the structures used to refer to the result set.          */
 | 
						|
  /**********************************************************************/
 | 
						|
  if (!(qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
 | 
						|
                             buftyp, fldtyp, length, false, true)))
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  // Some columns must be renamed
 | 
						|
  for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
 | 
						|
    switch (++i) {
 | 
						|
      case  2: crp->Nulls = (char*)PlugSubAlloc(g, NULL, n); break;
 | 
						|
      case  4: crp->Name = "Length";    break;
 | 
						|
      case  5: crp->Name = "Key";       break;
 | 
						|
      case 10: crp->Name = "Date_fmt";  break;
 | 
						|
      case 11: crp->Name = "Default";   break;
 | 
						|
      case 12: crp->Name = "Extra";     break;
 | 
						|
      case 13: crp->Name = "Collation"; break;
 | 
						|
      } // endswitch i
 | 
						|
 | 
						|
  if (info)
 | 
						|
    return qrp;
 | 
						|
 | 
						|
  /**********************************************************************/
 | 
						|
  /*  Now get the results into blocks.                                  */
 | 
						|
  /**********************************************************************/
 | 
						|
  for (i = 0; i < n; /*i++*/) {
 | 
						|
    if ((rc = myc.Fetch(g, -1)) == RC_FX) {
 | 
						|
      myc.Close();
 | 
						|
      return NULL;
 | 
						|
    } else if (rc == RC_EF)
 | 
						|
      break;
 | 
						|
 | 
						|
    // Get column name
 | 
						|
    colname = myc.GetCharField(0);
 | 
						|
    crp = qrp->Colresp;                    // Column_Name
 | 
						|
    crp->Kdata->SetValue(colname, i);
 | 
						|
 | 
						|
    // Get type, type name, precision, unsigned and zerofill
 | 
						|
    chset = myc.GetCharField(2);
 | 
						|
    fld = myc.GetCharField(1);
 | 
						|
    prec = 0;
 | 
						|
    len = 0;
 | 
						|
//  v = (chset && !strcmp(chset, "binary")) ? 'B' : 0;
 | 
						|
		v = 0;
 | 
						|
    *uns = 0;
 | 
						|
    *zero = 0;
 | 
						|
		b = false;
 | 
						|
 | 
						|
		if (!strnicmp(fld, "enum", 4)) {
 | 
						|
			char *p2, *p1 = fld + 6;            // to skip enum('
 | 
						|
 | 
						|
			while (true) {
 | 
						|
				p2 = strchr(p1, '\'');
 | 
						|
				len = MY_MAX(len, (int)(p2 - p1));
 | 
						|
				if (*++p2 != ',') break;
 | 
						|
				p1 = p2 + 2;
 | 
						|
			} // endwhile
 | 
						|
 | 
						|
			v = (len > 255) ? 'V' : 0;
 | 
						|
			strcpy(buf, "enum");
 | 
						|
			b = true;
 | 
						|
		} else if (!strnicmp(fld, "set", 3)) {
 | 
						|
			len = (int)strlen(fld) - 2;
 | 
						|
			v = 'V';
 | 
						|
			strcpy(buf, "set");
 | 
						|
			b = true;
 | 
						|
		} else switch ((nf = sscanf(fld, "%[^(](%d,%d", buf, &len, &prec))) {
 | 
						|
      case 3:
 | 
						|
        nf = sscanf(fld, "%[^(](%d,%d) %s %s", buf, &len, &prec, uns, zero);
 | 
						|
        break;
 | 
						|
      case 2:
 | 
						|
        nf = sscanf(fld, "%[^(](%d) %s %s", buf, &len, uns, zero) + 1;
 | 
						|
        break;
 | 
						|
      case 1:
 | 
						|
        nf = sscanf(fld, "%s %s %s", buf, uns, zero) + 2;
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        snprintf(g->Message, sizeof(g->Message), MSG(BAD_FIELD_TYPE), fld);
 | 
						|
        myc.Close();
 | 
						|
        return NULL;
 | 
						|
      } // endswitch nf
 | 
						|
 | 
						|
    if ((type = MYSQLtoPLG(buf, &v)) == TYPE_ERROR) {
 | 
						|
      if (v == 'K') {
 | 
						|
        // Skip this column
 | 
						|
        snprintf(g->Message, sizeof(g->Message), "Column %s skipped (unsupported type %s)",
 | 
						|
                colname, buf);
 | 
						|
        PushWarning(g, thd);
 | 
						|
        continue;
 | 
						|
        } // endif v
 | 
						|
 | 
						|
      snprintf(g->Message, sizeof(g->Message), "Column %s unsupported type %s", colname, buf);
 | 
						|
      myc.Close();
 | 
						|
      return NULL;
 | 
						|
    } else if (type == TYPE_STRING) {
 | 
						|
      if (v == 'X') {
 | 
						|
        len = GetConvSize();
 | 
						|
        snprintf(g->Message, sizeof(g->Message), "Column %s converted to varchar(%d)",
 | 
						|
                colname, len);
 | 
						|
        PushWarning(g, thd);
 | 
						|
        v = 'V';
 | 
						|
			} else
 | 
						|
        len = MY_MIN(len, 4096);
 | 
						|
 | 
						|
    } // endif type
 | 
						|
 | 
						|
    qrp->Nblin++;
 | 
						|
    crp = crp->Next;                       // Data_Type
 | 
						|
    crp->Kdata->SetValue(type, i);
 | 
						|
 | 
						|
    switch (nf) {
 | 
						|
      case 5:  crp->Nulls[i] = 'Z'; break;
 | 
						|
      case 4:  crp->Nulls[i] = 'U'; break;
 | 
						|
      default: crp->Nulls[i] = v;   break;
 | 
						|
      } // endswitch nf
 | 
						|
 | 
						|
		if (b)																 // enum or set
 | 
						|
  		nf = sscanf(fld, "%s ", buf);				 // get values
 | 
						|
 | 
						|
    crp = crp->Next;                       // Type_Name
 | 
						|
    crp->Kdata->SetValue(buf, i);
 | 
						|
 | 
						|
    if (type == TYPE_DATE) {
 | 
						|
      // When creating tables we do need info about date columns
 | 
						|
      fmt = MyDateFmt(buf);
 | 
						|
      len = strlen(fmt);
 | 
						|
    } else
 | 
						|
      fmt = NULL;
 | 
						|
 | 
						|
    crp = crp->Next;                       // Precision
 | 
						|
    crp->Kdata->SetValue(len, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // key (was Length)
 | 
						|
    fld = myc.GetCharField(4);
 | 
						|
    crp->Kdata->SetValue(fld, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // Scale
 | 
						|
    crp->Kdata->SetValue(prec, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // Radix
 | 
						|
    crp->Kdata->SetValue(0, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // Nullable
 | 
						|
    fld = myc.GetCharField(3);
 | 
						|
    crp->Kdata->SetValue((toupper(*fld) == 'Y') ? 1 : 0, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // Remark
 | 
						|
    fld = myc.GetCharField(8);
 | 
						|
    crp->Kdata->SetValue(fld, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // Date format
 | 
						|
//  crp->Kdata->SetValue((fmt) ? fmt : (char*) "", i);
 | 
						|
    crp->Kdata->SetValue(fmt, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // New (default)
 | 
						|
    fld = myc.GetCharField(5);
 | 
						|
    crp->Kdata->SetValue(fld, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // New (extra)
 | 
						|
    fld = myc.GetCharField(6);
 | 
						|
    crp->Kdata->SetValue(fld, i);
 | 
						|
 | 
						|
    crp = crp->Next;                       // New (charset)
 | 
						|
    fld = chset;
 | 
						|
    crp->Kdata->SetValue(fld, i);
 | 
						|
 | 
						|
    i++;                                   // Can be skipped
 | 
						|
    } // endfor i
 | 
						|
 | 
						|
#if 0
 | 
						|
  if (k > 1) {
 | 
						|
    // Multicolumn primary key
 | 
						|
    PVBLK vbp = qrp->Colresp->Next->Next->Next->Next->Kdata;
 | 
						|
 | 
						|
    for (i = 0; i < n; i++)
 | 
						|
      if (vbp->GetIntValue(i))
 | 
						|
        vbp->SetValue(k, i);
 | 
						|
 | 
						|
    } // endif k
 | 
						|
#endif // 0
 | 
						|
 | 
						|
  /**********************************************************************/
 | 
						|
  /*  Close MySQL connection.                                           */
 | 
						|
  /**********************************************************************/
 | 
						|
  myc.Close();
 | 
						|
 | 
						|
  /**********************************************************************/
 | 
						|
  /*  Return the result pointer for use by GetData routines.            */
 | 
						|
  /**********************************************************************/
 | 
						|
  return qrp;
 | 
						|
  } // end of MyColumns
 | 
						|
 | 
						|
/************************************************************************/
 | 
						|
/*  SrcColumns: constructs the result blocks containing all columns     */
 | 
						|
/*  resulting from an SQL source definition query execution.            */
 | 
						|
/************************************************************************/
 | 
						|
PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db,
 | 
						|
                   const char *user, const char *pwd,
 | 
						|
                   const char *srcdef, int port)
 | 
						|
  {
 | 
						|
  char   *query;
 | 
						|
  int     w;
 | 
						|
  MYSQLC  myc;
 | 
						|
  PQRYRES qrp = NULL;
 | 
						|
  const char *p;
 | 
						|
 | 
						|
  if (!port)
 | 
						|
    port = mysqld_port;
 | 
						|
 | 
						|
	if (!strnicmp(srcdef, "select ", 7) || strstr(srcdef, "%s")) {
 | 
						|
		size_t query_sz = strlen(srcdef) + 10;
 | 
						|
		query = (char *)PlugSubAlloc(g, NULL, query_sz);
 | 
						|
 | 
						|
		if ((p= strstr(srcdef, "%s")))
 | 
						|
		{
 | 
						|
			/* Replace %s with 1=1 */
 | 
						|
			snprintf(query, query_sz, "%.*s1=1%s",
 | 
						|
			         (int) (p - srcdef), srcdef, p + 2); // dummy where clause
 | 
						|
		}
 | 
						|
		else
 | 
						|
			safe_strcpy(query, query_sz, srcdef);
 | 
						|
 | 
						|
		if (!strnicmp(srcdef, "select ", 7))
 | 
						|
			safe_strcat(query, query_sz, " LIMIT 0");
 | 
						|
 | 
						|
	} else
 | 
						|
    query = (char *)srcdef;
 | 
						|
 | 
						|
  // Open a MySQL connection for this table
 | 
						|
  if (myc.Open(g, host, db, user, pwd, port))
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  // Send the source command to MySQL
 | 
						|
  if (myc.ExecSQL(g, query, &w) == RC_OK)
 | 
						|
    qrp = myc.GetResult(g, true);
 | 
						|
 | 
						|
  myc.Close();
 | 
						|
  return qrp;
 | 
						|
  } // end of SrcColumns
 | 
						|
 | 
						|
/* -------------------------- Class MYSQLC --------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Implementation of the MYSQLC class.                                */
 | 
						|
/***********************************************************************/
 | 
						|
MYSQLC::MYSQLC(void)
 | 
						|
  {
 | 
						|
  m_DB = NULL;
 | 
						|
#if defined (MYSQL_PREPARED_STATEMENTS)
 | 
						|
	m_Stmt = NULL;
 | 
						|
#endif    // MYSQL_PREPARED_STATEMENTS
 | 
						|
	m_Res = NULL;
 | 
						|
  m_Rows = -1;
 | 
						|
  m_Row = NULL;
 | 
						|
  m_Fields = -1;
 | 
						|
  N = 0;
 | 
						|
  m_Use = false;
 | 
						|
  } // end of MYSQLC constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Get the number of lines of the result set.                         */
 | 
						|
/*  Currently we send the Select command and return m_Rows             */
 | 
						|
/*  Perhaps should we use Select count(*) ... (?????)                  */
 | 
						|
/*  No because here we execute only one query instead of two           */
 | 
						|
/*  (the select count(*) plus the normal query)                        */
 | 
						|
/***********************************************************************/
 | 
						|
int MYSQLC::GetResultSize(PGLOBAL g, PSZ sql)
 | 
						|
  {
 | 
						|
  if (m_Rows < 0)
 | 
						|
    if (ExecSQL(g, sql) != RC_OK)
 | 
						|
      return -1;
 | 
						|
 | 
						|
  return m_Rows;
 | 
						|
  } // end of GetResultSize
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Open a MySQL (remote) connection.                                  */
 | 
						|
/***********************************************************************/
 | 
						|
int MYSQLC::Open(PGLOBAL g, const char *host, const char *db,
 | 
						|
                            const char *user, const char *pwd,
 | 
						|
                            int pt, const char *csname)
 | 
						|
  {
 | 
						|
  const char *pipe = NULL;
 | 
						|
  //uint      cto = 10, nrt = 20;
 | 
						|
  my_bool     my_true= 1;
 | 
						|
 | 
						|
  m_DB = mysql_init(NULL);
 | 
						|
 | 
						|
  if (!m_DB) {
 | 
						|
    strcpy(g->Message, "mysql_init failed: no memory");
 | 
						|
    return RC_FX;
 | 
						|
    } // endif m_DB
 | 
						|
 | 
						|
	if (trace(1))
 | 
						|
		htrc("MYSQLC Open: m_DB=%.4X size=%d\n", m_DB, (int)sizeof(*m_DB));
 | 
						|
 | 
						|
	// Removed to do like FEDERATED does
 | 
						|
//mysql_options(m_DB, MYSQL_READ_DEFAULT_GROUP, "client-mariadb");
 | 
						|
//mysql_options(m_DB, MYSQL_OPT_USE_REMOTE_CONNECTION, NULL);
 | 
						|
//mysql_options(m_DB, MYSQL_OPT_CONNECT_TIMEOUT, &cto);
 | 
						|
//mysql_options(m_DB, MYSQL_OPT_READ_TIMEOUT, &nrt);
 | 
						|
//mysql_options(m_DB, MYSQL_OPT_WRITE_TIMEOUT, ...);
 | 
						|
 | 
						|
#if defined(_WIN32)
 | 
						|
  if (!strcmp(host, ".")) {
 | 
						|
    mysql_options(m_DB, MYSQL_OPT_NAMED_PIPE, NULL);
 | 
						|
    pipe = mysqld_unix_port;
 | 
						|
    } // endif host
 | 
						|
#else   // !_WIN32
 | 
						|
  if (!strcmp(host, "localhost"))
 | 
						|
    pipe = mysqld_unix_port;
 | 
						|
#endif  // !_WIN32
 | 
						|
 | 
						|
#if 0
 | 
						|
  if (pwd && !strcmp(pwd, "*")) {
 | 
						|
    if (GetPromptAnswer(g, "*Enter password:")) {
 | 
						|
      m_DB = NULL;
 | 
						|
      return RC_FX;
 | 
						|
    } else
 | 
						|
      pwd = g->Message;
 | 
						|
 | 
						|
    } // endif pwd
 | 
						|
#endif // 0
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*	BUG# 17044 Federated Storage Engine is not UTF8 clean              */
 | 
						|
/*	Add set names to whatever charset the table is at open of table    */
 | 
						|
/*  this sets the csname like 'set names utf8'.                        */
 | 
						|
/***********************************************************************/
 | 
						|
  if (csname)
 | 
						|
    mysql_options(m_DB, MYSQL_SET_CHARSET_NAME, csname);
 | 
						|
 | 
						|
  // Don't know what this one do but FEDERATED does it
 | 
						|
  mysql_options(m_DB, MYSQL_OPT_USE_THREAD_SPECIFIC_MEMORY,
 | 
						|
                  (char*)&my_true);
 | 
						|
 | 
						|
  if (!mysql_real_connect(m_DB, host, user, pwd, db, pt, pipe,
 | 
						|
		CLIENT_MULTI_RESULTS | CLIENT_REMEMBER_OPTIONS)) {
 | 
						|
#if defined(_DEBUG)
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "mysql_real_connect failed: (%d) %s",
 | 
						|
                        mysql_errno(m_DB), mysql_error(m_DB));
 | 
						|
#else   // !_DEBUG
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "(%d) %s", mysql_errno(m_DB), mysql_error(m_DB));
 | 
						|
#endif  // !_DEBUG
 | 
						|
    mysql_close(m_DB);
 | 
						|
    m_DB = NULL;
 | 
						|
    return RC_FX;
 | 
						|
    } // endif mysql_real_connect
 | 
						|
 | 
						|
  return RC_OK;
 | 
						|
  } // end of Open
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Returns true if the connection is still alive.                     */
 | 
						|
/***********************************************************************/
 | 
						|
bool MYSQLC::Connected(void)
 | 
						|
  {
 | 
						|
//int rc;
 | 
						|
 | 
						|
  if (!m_DB)
 | 
						|
    return FALSE;
 | 
						|
//else if ((rc = mysql_ping(m_DB)) == CR_SERVER_GONE_ERROR)
 | 
						|
//  return FALSE;
 | 
						|
  else
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
  } // end of Connected
 | 
						|
 | 
						|
#if 0                         // Not used
 | 
						|
/***********************************************************************/
 | 
						|
/*  Returns the thread ID of the current MySQL connection.             */
 | 
						|
/***********************************************************************/
 | 
						|
ulong MYSQLC::GetThreadID(void)
 | 
						|
  {
 | 
						|
  return (m_DB) ? mysql_thread_id(m_DB) : 0;
 | 
						|
  } // end of GetThreadID
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Returns a string that represents the server version number.        */
 | 
						|
/***********************************************************************/
 | 
						|
const char *MYSQLC::ServerInfo(void)
 | 
						|
  {
 | 
						|
  return (m_DB) ? mysql_get_server_info(m_DB) : NULL;
 | 
						|
  } // end of ServerInfo
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Returns the version number of the server as a number that          */
 | 
						|
/*  represents the MySQL server version in this format:                */
 | 
						|
/*  major_version*10000 + minor_version *100 + sub_version             */
 | 
						|
/***********************************************************************/
 | 
						|
ulong MYSQLC::ServerVersion(void)
 | 
						|
  {
 | 
						|
  return (m_DB) ? mysql_get_server_version(m_DB) : 0;
 | 
						|
  } // end of ServerVersion
 | 
						|
#endif // 0
 | 
						|
 | 
						|
/**************************************************************************/
 | 
						|
/*  KillQuery: Send MySQL a Kill Query command.                           */
 | 
						|
/**************************************************************************/
 | 
						|
int MYSQLC::KillQuery(ulong id)
 | 
						|
  {
 | 
						|
  char kill[20];
 | 
						|
 | 
						|
  sprintf(kill, "KILL QUERY %u", (unsigned int) id);
 | 
						|
//return (m_DB) ? mysql_query(m_DB, kill) : 1;
 | 
						|
  return (m_DB) ? mysql_real_query(m_DB, kill, strlen(kill)) : 1;
 | 
						|
  } // end of KillQuery
 | 
						|
 | 
						|
#if defined (MYSQL_PREPARED_STATEMENTS)
 | 
						|
/***********************************************************************/
 | 
						|
/*  Prepare the SQL statement used to insert into a MySQL table.       */
 | 
						|
/***********************************************************************/
 | 
						|
int MYSQLC::PrepareSQL(PGLOBAL g, const char *stmt)
 | 
						|
  {
 | 
						|
  if (!m_DB) {
 | 
						|
    strcpy(g->Message, "MySQL not connected");
 | 
						|
    return -4;
 | 
						|
  } else if (m_Stmt)
 | 
						|
    return -1;              // should not append
 | 
						|
 | 
						|
#if defined(ALPHA)
 | 
						|
  if (!(m_Stmt = mysql_prepare(m_DB, stmt, strlen(stmt)))) {
 | 
						|
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "mysql_prepare failed: %s [%s]",
 | 
						|
                         mysql_error(m_DB), stmt);
 | 
						|
    return -1;
 | 
						|
    } // endif m_Stmt
 | 
						|
 | 
						|
  // Return the parameter count from the statement
 | 
						|
  return mysql_param_count(m_Stmt);
 | 
						|
#else   // !ALPHA
 | 
						|
  if (!(m_Stmt = mysql_stmt_init(m_DB))) {
 | 
						|
    strcpy(g->Message, "mysql_stmt_init(), out of memory");
 | 
						|
    return -2;
 | 
						|
    } // endif m_Stmt
 | 
						|
 | 
						|
  if (mysql_stmt_prepare(m_Stmt, stmt, strlen(stmt))) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "mysql_stmt_prepare() failed: (%d) %s",
 | 
						|
            mysql_stmt_errno(m_Stmt), mysql_stmt_error(m_Stmt));
 | 
						|
    return -3;
 | 
						|
    } // endif prepare
 | 
						|
 | 
						|
  // Return the parameter count from the statement
 | 
						|
  return mysql_stmt_param_count(m_Stmt);
 | 
						|
#endif   // !ALPHA
 | 
						|
  } // end of PrepareSQL
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Bind the parameter buffers.                                        */
 | 
						|
/***********************************************************************/
 | 
						|
int MYSQLC::BindParams(PGLOBAL g, MYSQL_BIND *bind)
 | 
						|
  {
 | 
						|
  if (!m_DB) {
 | 
						|
    strcpy(g->Message, "MariaDB not connected");
 | 
						|
    return RC_FX;
 | 
						|
  } else
 | 
						|
    assert(m_Stmt);
 | 
						|
 | 
						|
#if defined(ALPHA)
 | 
						|
  if (mysql_bind_param(m_Stmt, bind)) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "mysql_bind_param() failed: %s",
 | 
						|
                        mysql_stmt_error(m_Stmt));
 | 
						|
#else   // !ALPHA
 | 
						|
  if (mysql_stmt_bind_param(m_Stmt, bind)) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "mysql_stmt_bind_param() failed: %s",
 | 
						|
                        mysql_stmt_error(m_Stmt));
 | 
						|
#endif  // !ALPHA
 | 
						|
    return RC_FX;
 | 
						|
    } // endif bind
 | 
						|
 | 
						|
  return RC_OK;
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Execute a prepared statement.                                      */
 | 
						|
/***********************************************************************/
 | 
						|
int MYSQLC::ExecStmt(PGLOBAL g)
 | 
						|
  {
 | 
						|
  if (!m_DB) {
 | 
						|
    strcpy(g->Message, "MySQL not connected");
 | 
						|
    return RC_FX;
 | 
						|
    } // endif m_DB
 | 
						|
 | 
						|
#if defined(ALPHA)
 | 
						|
  if (mysql_execute(m_Stmt)) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "mysql_execute() failed: %s",
 | 
						|
                        mysql_stmt_error(m_Stmt));
 | 
						|
    return RC_FX;
 | 
						|
    } // endif execute
 | 
						|
#else   // !ALPHA
 | 
						|
  if (mysql_stmt_execute(m_Stmt)) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "mysql_stmt_execute() failed: %s",
 | 
						|
                        mysql_stmt_error(m_Stmt));
 | 
						|
    return RC_FX;
 | 
						|
    } // endif execute
 | 
						|
#endif  // !ALPHA
 | 
						|
 | 
						|
  // Check the total number of affected rows
 | 
						|
  if (mysql_stmt_affected_rows(m_Stmt) != 1) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "Invalid affected rows by MySQL");
 | 
						|
    return RC_FX;
 | 
						|
    } // endif affected_rows
 | 
						|
 | 
						|
  return RC_OK;
 | 
						|
  } // end of ExecStmt
 | 
						|
#endif   // MYSQL_PREPARED_STATEMENTS
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Exec the Select SQL command and get back the result size in rows.  */
 | 
						|
/***********************************************************************/
 | 
						|
int MYSQLC::ExecSQL(PGLOBAL g, const char *query, int *w)
 | 
						|
  {
 | 
						|
  int rc = RC_OK;
 | 
						|
 | 
						|
  if (!m_DB) {
 | 
						|
    strcpy(g->Message, "MySQL not connected");
 | 
						|
    return RC_FX;
 | 
						|
    } // endif m_DB
 | 
						|
 | 
						|
  if (w)
 | 
						|
    *w = 0;
 | 
						|
 | 
						|
  if (m_Rows >= 0)
 | 
						|
    return RC_OK;                  // Already done
 | 
						|
 | 
						|
//if (mysql_query(m_DB, query) != 0) {
 | 
						|
  if (mysql_real_query(m_DB, query, strlen(query))) {
 | 
						|
    char *msg = (char*)PlugSubAlloc(g, NULL, 512 + strlen(query));
 | 
						|
 | 
						|
    sprintf(msg, "(%d) %s [%s]", mysql_errno(m_DB),
 | 
						|
                                 mysql_error(m_DB), query);
 | 
						|
    strncpy(g->Message, msg, sizeof(g->Message) - 1);
 | 
						|
    g->Message[sizeof(g->Message) - 1] = 0;
 | 
						|
    rc = RC_FX;
 | 
						|
//} else if (mysql_field_count(m_DB) > 0) {
 | 
						|
  } else if (m_DB->field_count > 0) {
 | 
						|
    if (m_Use)
 | 
						|
#if defined(MYSQL_PREPARED_STATEMENTS)
 | 
						|
      m_Res = mysql_use_result(m_DB);
 | 
						|
#else   // !MYSQL_PREPARED_STATEMENTS)
 | 
						|
      m_Res = connect_use_result(m_DB);
 | 
						|
#endif  // !MYSQL_PREPARED_STATEMENTS
 | 
						|
    else
 | 
						|
      m_Res = mysql_store_result(m_DB);
 | 
						|
 | 
						|
    if (!m_Res) {
 | 
						|
      char *msg = (char*)PlugSubAlloc(g, NULL, 512 + strlen(query));
 | 
						|
 | 
						|
      sprintf(msg, "mysql_store_result failed: %s", mysql_error(m_DB));
 | 
						|
      strncpy(g->Message, msg, sizeof(g->Message) - 1);
 | 
						|
      g->Message[sizeof(g->Message) - 1] = 0;
 | 
						|
      rc = RC_FX;
 | 
						|
    } else {
 | 
						|
      m_Fields = mysql_num_fields(m_Res);
 | 
						|
      m_Rows = (!m_Use) ? (int)mysql_num_rows(m_Res) : 0;
 | 
						|
 | 
						|
			if (trace(1))
 | 
						|
				htrc("ExecSQL: m_Res=%.4X size=%d m_Fields=%d m_Rows=%d\n",
 | 
						|
				               m_Res, sizeof(*m_Res), m_Fields, m_Rows);
 | 
						|
 | 
						|
    } // endif m_Res
 | 
						|
 | 
						|
  } else {
 | 
						|
//  m_Rows = (int)mysql_affected_rows(m_DB);
 | 
						|
    m_Rows = (int)m_DB->affected_rows;
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "Affected rows: %d\n", m_Rows);
 | 
						|
    rc = RC_NF;
 | 
						|
  } // endif field count
 | 
						|
 | 
						|
  if (w)
 | 
						|
//  *w = mysql_warning_count(m_DB);
 | 
						|
    *w = m_DB->warning_count;
 | 
						|
 | 
						|
  return rc;
 | 
						|
  } // end of ExecSQL
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Get table size by executing "select count(*) from table_name".     */
 | 
						|
/***********************************************************************/
 | 
						|
int MYSQLC::GetTableSize(PGLOBAL g __attribute__((unused)), PSZ query)
 | 
						|
  {
 | 
						|
  if (mysql_real_query(m_DB, query, strlen(query))) {
 | 
						|
#if defined(_DEBUG)
 | 
						|
    char *msg = (char*)PlugSubAlloc(g, NULL, 512 + strlen(query));
 | 
						|
 | 
						|
    sprintf(msg, "(%d) %s [%s]", mysql_errno(m_DB),
 | 
						|
                                 mysql_error(m_DB), query);
 | 
						|
    strncpy(g->Message, msg, sizeof(g->Message) - 1);
 | 
						|
    g->Message[sizeof(g->Message) - 1] = 0;
 | 
						|
#endif   // _DEBUG
 | 
						|
    return -2;
 | 
						|
    } // endif mysql_real_query
 | 
						|
 | 
						|
  if (!(m_Res = mysql_store_result(m_DB)))
 | 
						|
    return -3;
 | 
						|
 | 
						|
  // Get the resulting count value
 | 
						|
  m_Rows = (int)mysql_num_rows(m_Res);     // Should be 1
 | 
						|
 | 
						|
  if (m_Rows && (m_Row = mysql_fetch_row(m_Res)))
 | 
						|
    return atoi(*m_Row);
 | 
						|
 | 
						|
  return -4;
 | 
						|
  } // end of GetTableSize
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Move to a specific row and column                                  */
 | 
						|
/***********************************************************************/
 | 
						|
void MYSQLC::DataSeek(my_ulonglong row)
 | 
						|
  {
 | 
						|
  MYSQL_ROWS *tmp = 0;
 | 
						|
//DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
 | 
						|
 | 
						|
  if (m_Res->data)
 | 
						|
    for (tmp = m_Res->data->data; row-- && tmp; tmp = tmp->next) ;
 | 
						|
 | 
						|
  m_Res->current_row = 0;
 | 
						|
  m_Res->data_cursor = tmp;
 | 
						|
  } // end of DataSeek
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Fetch one result line from the query result set.                   */
 | 
						|
/***********************************************************************/
 | 
						|
int MYSQLC::Fetch(PGLOBAL g, int pos)
 | 
						|
  {
 | 
						|
  if (!m_DB) {
 | 
						|
    strcpy(g->Message, "MySQL not connected");
 | 
						|
    return RC_FX;
 | 
						|
    } // endif m_DB
 | 
						|
 | 
						|
  if (!m_Res) {
 | 
						|
    // Result set was not initialized
 | 
						|
    strcpy(g->Message, MSG(FETCH_NO_RES));
 | 
						|
    return RC_FX;
 | 
						|
  } else
 | 
						|
    N++;
 | 
						|
 | 
						|
  if (pos >= 0)
 | 
						|
//  mysql_data_seek(m_Res, (my_ulonglong)pos);
 | 
						|
    DataSeek((my_ulonglong)pos);
 | 
						|
 | 
						|
  m_Row = mysql_fetch_row(m_Res);
 | 
						|
  return (m_Row) ? RC_OK : RC_EF;
 | 
						|
  } // end of Fetch
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Get one field of the current row.                                  */
 | 
						|
/***********************************************************************/
 | 
						|
char *MYSQLC::GetCharField(int i)
 | 
						|
  {
 | 
						|
  if (m_Res && m_Row) {
 | 
						|
#if defined(_DEBUG)
 | 
						|
//  MYSQL_FIELD *fld = mysql_fetch_field_direct(m_Res, i);
 | 
						|
#endif   // _DEBUG
 | 
						|
    MYSQL_ROW row = m_Row + i;
 | 
						|
 | 
						|
    return (row) ? (char*)*row : (char*)"<null>";
 | 
						|
  } else
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  } // end of GetCharField
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Get the max length of the field.                                   */
 | 
						|
/***********************************************************************/
 | 
						|
int MYSQLC::GetFieldLength(int i)
 | 
						|
  {
 | 
						|
  if (m_Res) {
 | 
						|
//  MYSQL_FIELD *fld = mysql_fetch_field_direct(m_Res, i);
 | 
						|
//  return fld->max_length;
 | 
						|
    return (m_Res)->fields[i].max_length;
 | 
						|
  } else
 | 
						|
    return 0;
 | 
						|
 | 
						|
  } // end of GetFieldLength
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Return next field of the query results.                            */
 | 
						|
/***********************************************************************/
 | 
						|
MYSQL_FIELD *MYSQLC::GetNextField(void)
 | 
						|
  {
 | 
						|
  return (m_Res->current_field >= m_Res->field_count) ? NULL
 | 
						|
       : &m_Res->fields[m_Res->current_field++];
 | 
						|
  } // end of GetNextField
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Make a CONNECT result structure from the MySQL result.             */
 | 
						|
/***********************************************************************/
 | 
						|
PQRYRES MYSQLC::GetResult(PGLOBAL g, bool pdb)
 | 
						|
  {
 | 
						|
	PCSZ         fmt;
 | 
						|
  char        *name, v= 0;
 | 
						|
  int          n;
 | 
						|
  bool         uns;
 | 
						|
  PCOLRES     *pcrp, crp;
 | 
						|
  PQRYRES      qrp;
 | 
						|
  MYSQL_FIELD *fld;
 | 
						|
  MYSQL_ROW    row;
 | 
						|
 | 
						|
  if (!m_Res || !m_Fields) {
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "%s result", (m_Res) ? "Void" : "No");
 | 
						|
    return NULL;
 | 
						|
    } // endif m_Res
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Put the result in storage for future retrieval.                  */
 | 
						|
  /*********************************************************************/
 | 
						|
  qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
 | 
						|
  pcrp = &qrp->Colresp;
 | 
						|
  qrp->Continued = FALSE;
 | 
						|
  qrp->Truncated = FALSE;
 | 
						|
  qrp->Info = FALSE;
 | 
						|
  qrp->Suball = TRUE;
 | 
						|
  qrp->BadLines = 0;
 | 
						|
  qrp->Maxsize = m_Rows;
 | 
						|
  qrp->Maxres = m_Rows;
 | 
						|
  qrp->Nbcol = 0;
 | 
						|
  qrp->Nblin = 0;
 | 
						|
  qrp->Cursor = 0;
 | 
						|
 | 
						|
//for (fld = mysql_fetch_field(m_Res); fld;
 | 
						|
//     fld = mysql_fetch_field(m_Res)) {
 | 
						|
  for (fld = GetNextField(); fld; fld = GetNextField()) {
 | 
						|
    *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
 | 
						|
    crp = *pcrp;
 | 
						|
    pcrp = &crp->Next;
 | 
						|
    memset(crp, 0, sizeof(COLRES));
 | 
						|
    crp->Ncol = ++qrp->Nbcol;
 | 
						|
 | 
						|
    name = (char*)PlugSubAlloc(g, NULL, fld->name_length + 1);
 | 
						|
    strcpy(name, fld->name);
 | 
						|
		crp->Name = name;
 | 
						|
 | 
						|
    if ((crp->Type = MYSQLtoPLG(fld->type, &v)) == TYPE_ERROR) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), "Type %d not supported for column %s",
 | 
						|
                          fld->type, crp->Name);
 | 
						|
      return NULL;
 | 
						|
    } else if (crp->Type == TYPE_DATE && !pdb)
 | 
						|
      // For direct MySQL connection, display the MySQL date string
 | 
						|
      crp->Type = TYPE_STRING;
 | 
						|
    else
 | 
						|
      crp->Var = v;
 | 
						|
 | 
						|
    crp->Prec = (crp->Type == TYPE_DOUBLE || crp->Type == TYPE_DECIM)
 | 
						|
              ? fld->decimals : 0;
 | 
						|
    CHARSET_INFO *cs= get_charset(fld->charsetnr, MYF(0));
 | 
						|
    crp->Clen = GetTypeSize(crp->Type, fld->length);
 | 
						|
    crp->Length = fld->length / (cs ? cs->mbmaxlen : 1);
 | 
						|
    uns = (fld->flags & (UNSIGNED_FLAG | ZEROFILL_FLAG)) ? true : false;
 | 
						|
 | 
						|
    if (!(crp->Kdata = AllocValBlock(g, NULL, crp->Type, m_Rows,
 | 
						|
                                     crp->Clen, 0, FALSE, TRUE, uns))) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), MSG(INV_RESULT_TYPE),
 | 
						|
                          GetFormatType(crp->Type));
 | 
						|
      return NULL;
 | 
						|
    } else if (crp->Type == TYPE_DATE) {
 | 
						|
      fmt = MyDateFmt(fld->type);
 | 
						|
      crp->Kdata->SetFormat(g, fmt, strlen(fmt));
 | 
						|
    } // endif's
 | 
						|
 | 
						|
    if (fld->flags & NOT_NULL_FLAG)
 | 
						|
      crp->Nulls = NULL;
 | 
						|
    else {
 | 
						|
			if (m_Rows) {
 | 
						|
				crp->Nulls = (char*)PlugSubAlloc(g, NULL, m_Rows);
 | 
						|
				memset(crp->Nulls, ' ', m_Rows);
 | 
						|
			} // endif m_Rows
 | 
						|
 | 
						|
			crp->Kdata->SetNullable(true);
 | 
						|
    } // endelse fld->flags
 | 
						|
 | 
						|
    } // endfor fld
 | 
						|
 | 
						|
  *pcrp = NULL;
 | 
						|
  assert(qrp->Nbcol == m_Fields);
 | 
						|
 | 
						|
  /*********************************************************************/
 | 
						|
  /*  Now fill the allocated result structure.                         */
 | 
						|
  /*********************************************************************/
 | 
						|
  for (n = 0; n < m_Rows; n++) {
 | 
						|
    if (!(m_Row = mysql_fetch_row(m_Res))) {
 | 
						|
      snprintf(g->Message, sizeof(g->Message), "Missing row %d from result", n + 1);
 | 
						|
      return NULL;
 | 
						|
      } // endif m_Row
 | 
						|
 | 
						|
    for (crp = qrp->Colresp; crp; crp = crp->Next) {
 | 
						|
      if ((row = m_Row + (crp->Ncol - 1))) {
 | 
						|
        if (*row)
 | 
						|
          crp->Kdata->SetValue((PSZ)*row, n);
 | 
						|
        else {
 | 
						|
          if (!*row && crp->Nulls)
 | 
						|
            crp->Nulls[n] = '*';           // Null value
 | 
						|
 | 
						|
          crp->Kdata->Reset(n);
 | 
						|
        } // endelse *row
 | 
						|
      }
 | 
						|
 | 
						|
    } // endfor crp
 | 
						|
 | 
						|
  } // endfor n
 | 
						|
 | 
						|
  qrp->Nblin = n;
 | 
						|
  return qrp;
 | 
						|
  } // end of GetResult
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Free the current result.                                           */
 | 
						|
/***********************************************************************/
 | 
						|
void MYSQLC::FreeResult(void)
 | 
						|
  {
 | 
						|
  if (m_Res) {
 | 
						|
    mysql_free_result(m_Res);
 | 
						|
    m_Res = NULL;
 | 
						|
    } // endif m_Res
 | 
						|
 | 
						|
  // Reset the connection
 | 
						|
  m_Row = NULL;
 | 
						|
  m_Rows = -1;
 | 
						|
  m_Fields = -1;
 | 
						|
  N = 0;
 | 
						|
  } // end of FreeResult
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Place the cursor at the beginning of the result set.               */
 | 
						|
/***********************************************************************/
 | 
						|
int MYSQLC::Rewind(PGLOBAL g, PSZ sql)
 | 
						|
  {
 | 
						|
		int rc = RC_OK;
 | 
						|
 | 
						|
		if (m_Res)
 | 
						|
			DataSeek(0);
 | 
						|
		else if (sql)
 | 
						|
			rc = ExecSQL(g, sql);
 | 
						|
 | 
						|
		return rc;
 | 
						|
  } // end of Rewind
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Exec the Select SQL command and return ncol or afrws (TDBMYEXC).   */
 | 
						|
/***********************************************************************/
 | 
						|
int MYSQLC::ExecSQLcmd(PGLOBAL g, const char *query, int *w)
 | 
						|
  {
 | 
						|
  int rc = RC_OK;
 | 
						|
 | 
						|
  if (!m_DB) {
 | 
						|
    strcpy(g->Message, "MySQL not connected");
 | 
						|
    return RC_FX;
 | 
						|
  } else
 | 
						|
    *w = 0;
 | 
						|
 | 
						|
  if (!stricmp(query, "Warning") || !stricmp(query, "Note")
 | 
						|
                                 || !stricmp(query, "Error"))
 | 
						|
    return RC_INFO;
 | 
						|
  else
 | 
						|
    m_Afrw = 0;
 | 
						|
 | 
						|
//if (mysql_query(m_DB, query) != 0) {
 | 
						|
  if (mysql_real_query(m_DB, query, strlen(query))) {
 | 
						|
    m_Afrw = (int)mysql_errno(m_DB);
 | 
						|
    snprintf(g->Message, sizeof(g->Message), "Remote: %s", mysql_error(m_DB));
 | 
						|
    rc = RC_FX;
 | 
						|
//} else if (!(m_Fields = mysql_field_count(m_DB))) {
 | 
						|
  } else if (!(m_Fields = (int)m_DB->field_count)) {
 | 
						|
//  m_Afrw = (int)mysql_affected_rows(m_DB);
 | 
						|
    m_Afrw = (int)m_DB->affected_rows;
 | 
						|
    rc = RC_NF;
 | 
						|
  } // endif's
 | 
						|
 | 
						|
//*w = mysql_warning_count(m_DB);
 | 
						|
  *w = m_DB->warning_count;
 | 
						|
  return rc;
 | 
						|
  } // end of ExecSQLcmd
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Close the connection.                                              */
 | 
						|
/***********************************************************************/
 | 
						|
void MYSQLC::Close(void)
 | 
						|
  {
 | 
						|
  FreeResult();
 | 
						|
 | 
						|
	if (trace(1))
 | 
						|
		htrc("MYSQLC Close: m_DB=%.4X\n", m_DB);
 | 
						|
 | 
						|
	mysql_close(m_DB);
 | 
						|
  m_DB = NULL;
 | 
						|
  } // end of Close
 | 
						|
 | 
						|
#if 0                       // not used yet
 | 
						|
/***********************************************************************/
 | 
						|
/*  Discard additional results from a stored procedure.                */
 | 
						|
/***********************************************************************/
 | 
						|
void MYSQLC::DiscardResults(void)
 | 
						|
  {
 | 
						|
  MYSQL_RES *res;
 | 
						|
 | 
						|
  while (!mysql_next_result(m_DB)) {
 | 
						|
    res = mysql_store_result(m_DB);
 | 
						|
    mysql_free_result(res);
 | 
						|
    } // endwhile next result
 | 
						|
 | 
						|
  } // end of DiscardResults
 | 
						|
#endif // 0
 |