20000724-22:45 GMT+2 Maurilio Longo <maurilio.longo@libero.it>
This commit is contained in:
@@ -1,3 +1,19 @@
|
||||
20000724-22:45 GMT+2 Maurilio Longo <maurilio.longo@libero.it>
|
||||
|
||||
+ contrib/mysql
|
||||
+ contrib/mysql/mysql.c
|
||||
+ contrib/mysql/mysql.h
|
||||
+ contrib/mysql/mysql_com.h
|
||||
+ contrib/mysql/mysql_version.h
|
||||
+ contrib/mysql/mysql.ch
|
||||
+ contrib/mysql/tmysql.prg
|
||||
+ contrib/mysql/dbf2mysql.prg
|
||||
+ contrib/mysql/test.prg
|
||||
+ contrib/mysql/readme.txt
|
||||
I've ported mSQL access classes to MySQL. There is a lot of work to do to finish them, but, nonetheless,
|
||||
in their present state I've been able to use them to port to MySQL a couple of programs written for
|
||||
mSQL.
|
||||
|
||||
2000-07-24 22:28 UTC+0100 Victor Szakats <info@szelvesz.hu>
|
||||
|
||||
* rdd/dbcmd.c
|
||||
@@ -18,7 +34,7 @@
|
||||
* source/rtl/errorapi.c
|
||||
* source/rtl/tobject.prg
|
||||
* source/vm/classes.c
|
||||
* TOBJECT_ERROR() implemented in Clipper/Harbour instead of C to keep it
|
||||
* TOBJECT_ERROR() implemented in Clipper/Harbour instead of C to keep it
|
||||
clean.
|
||||
+ __errRT_SBASE() internal function added to throw a substitutable (?)
|
||||
runtime error.
|
||||
|
||||
168
harbour/contrib/mysql/dbf2mysql.prg
Normal file
168
harbour/contrib/mysql/dbf2mysql.prg
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Harbour Project source code:
|
||||
* dbf2mysql.prg - converts a .dbf file into a MySQL table
|
||||
*
|
||||
* Copyright 2000 Maurilio Longo <maurilio.longo@libero.it>
|
||||
* www - http://www.harbour-project.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version, with one exception:
|
||||
*
|
||||
* The exception is that if you link the Harbour Runtime Library (HRL)
|
||||
* and/or the Harbour Virtual Machine (HVM) with other files to produce
|
||||
* an executable, this does not by itself cause the resulting executable
|
||||
* to be covered by the GNU General Public License. Your use of that
|
||||
* executable is in no way restricted on account of linking the HRL
|
||||
* and/or HVM code into it.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
|
||||
* their web site at http://www.gnu.org/).
|
||||
*
|
||||
*/
|
||||
|
||||
#include "inkey.ch"
|
||||
|
||||
procedure main(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14)
|
||||
|
||||
local cTok, nTok := 1
|
||||
local cHostName := "localhost"
|
||||
local cUser := "root"
|
||||
local cPassWord := ""
|
||||
local cDataBase, cTable, cFile
|
||||
local aDbfStruct, i
|
||||
local lCreateTable := .F.
|
||||
local oServer, oTable, oRecord
|
||||
|
||||
SET CENTURY ON
|
||||
SET EPOCH TO 1960
|
||||
|
||||
if PCount() < 6
|
||||
help()
|
||||
quit
|
||||
endif
|
||||
|
||||
i := 1
|
||||
// Scan parameters and setup workings
|
||||
while (i <= PCount())
|
||||
|
||||
cTok := hb_PValue(i++)
|
||||
|
||||
do case
|
||||
case cTok == "-h"
|
||||
cHostName := hb_PValue(i++)
|
||||
|
||||
case cTok == "-d"
|
||||
cDataBase := hb_PValue(i++)
|
||||
|
||||
case cTok == "-t"
|
||||
cTable := hb_PValue(i++)
|
||||
|
||||
case cTok == "-f"
|
||||
cFile := hb_PValue(i++)
|
||||
|
||||
case cTok == "-u"
|
||||
cUser := hb_PValue(i++)
|
||||
|
||||
case cTok == "-p"
|
||||
cPassWord := hb_PValue(i++)
|
||||
|
||||
case cTok == "-c"
|
||||
lCreateTable := .T.
|
||||
|
||||
otherwise
|
||||
help()
|
||||
quit
|
||||
endcase
|
||||
enddo
|
||||
|
||||
dbUseArea(.T.,, cFile, "dbffile",, .T.)
|
||||
aDbfStruct := dbffile->(dbStruct())
|
||||
|
||||
oServer := TMySQLServer():New(cHostName, cUser, cPassWord)
|
||||
if oServer:NetErr()
|
||||
? oServer:Error()
|
||||
quit
|
||||
endif
|
||||
|
||||
oServer:SelectDB(cDataBase)
|
||||
if oServer:NetErr()
|
||||
? oServer:Error()
|
||||
quit
|
||||
endif
|
||||
|
||||
if lCreateTable
|
||||
if Ascan(oServer:ListTables(), cTable) > 0
|
||||
oServer:DeleteTable(cTable)
|
||||
if oServer:NetErr()
|
||||
? oServer:Error()
|
||||
quit
|
||||
endif
|
||||
endif
|
||||
oServer:CreateTable(cTable, aDbfStruct)
|
||||
if oServer:NetErr()
|
||||
? oServer:Error()
|
||||
quit
|
||||
endif
|
||||
endif
|
||||
|
||||
// Initialize MySQL table
|
||||
oTable := oServer:Query("SELECT * FROM " + cTable + " LIMIT 1")
|
||||
if oTable:NetErr()
|
||||
Alert(oTable:Error())
|
||||
quit
|
||||
endif
|
||||
|
||||
while !dbffile->(eof()) .AND. Inkey() <> K_ESC
|
||||
|
||||
oRecord := oTable:GetBlankRow()
|
||||
|
||||
for i := 1 to dbffile->(FCount())
|
||||
oRecord:FieldPut(i, dbffile->(FieldGet(i)))
|
||||
next
|
||||
|
||||
oTable:Append(oRecord)
|
||||
if oTable:NetErr()
|
||||
Alert(oTable:Error())
|
||||
endif
|
||||
|
||||
dbffile->(dbSkip())
|
||||
|
||||
DevPos(Row(), 1)
|
||||
if (dbffile->(RecNo()) % 100) == 0
|
||||
DevOut("imported recs: " + Str(dbffile->(RecNo())))
|
||||
endif
|
||||
enddo
|
||||
|
||||
dbffile->(dbCloseArea())
|
||||
oTable:Destroy()
|
||||
oServer:Destroy()
|
||||
return
|
||||
|
||||
|
||||
procedure Help()
|
||||
|
||||
? "dbf2MySQL - dbf file to MySQL table conversion utility"
|
||||
? "-h hostname (default: localhost)"
|
||||
? "-u user (default: root)"
|
||||
? "-p password (default no password)"
|
||||
? "-d name of database to use"
|
||||
? "-t name of table to add records to"
|
||||
? "-c delete existing table and create a new one"
|
||||
? "-f name of .dbf file to import"
|
||||
? "all parameters but -h -u -p -c are mandatory"
|
||||
? ""
|
||||
|
||||
return
|
||||
268
harbour/contrib/mysql/mysql.c
Normal file
268
harbour/contrib/mysql/mysql.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Harbour Project source code:
|
||||
* MySQL DBMS low level (client api) interface code.
|
||||
*
|
||||
* Copyright 2000 Maurilio Longo <maurilio.longo@libero.it>
|
||||
* www - http://www.harbour-project.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version, with one exception:
|
||||
*
|
||||
* The exception is that if you link the Harbour Runtime Library (HRL)
|
||||
* and/or the Harbour Virtual Machine (HVM) with other files to produce
|
||||
* an executable, this does not by itself cause the resulting executable
|
||||
* to be covered by the GNU General Public License. Your use of that
|
||||
* executable is in no way restricted on account of linking the HRL
|
||||
* and/or HVM code into it.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
|
||||
* their web site at http://www.gnu.org/).
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* NOTE: we need this to prevent base types redefinition */
|
||||
#define _CLIPDEFS_H
|
||||
|
||||
#include "extend.api"
|
||||
#include "item.api"
|
||||
#include "mysql.h"
|
||||
|
||||
|
||||
/* NOTE: OS/2 EMX port of MySQL needs libmysqlclient.a from 3.21.33b build which has st and mt
|
||||
versions of client library. I'm using ST version since harbour is single threaded. You need
|
||||
also .h files from same distribution
|
||||
*/
|
||||
|
||||
HB_FUNC(SQLCONNECT) // MYSQL *mysql_real_connect(MYSQL*, char * host, char * user, char * password, char * db, uint port, char *, uint flags)
|
||||
{
|
||||
MYSQL * mysql = NULL;
|
||||
|
||||
mysql = mysql_real_connect(NULL, _parc(1), _parc(2), _parc(3), 0, NULL, 0);
|
||||
_retnl((long) mysql);
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLCLOSE) // void mysql_close(MYSQL *mysql)
|
||||
{
|
||||
mysql_close((MYSQL *)_parnl(1));
|
||||
_ret();
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLSELECTD) // int mysql_select_db(MYSQL *, char *)
|
||||
{
|
||||
_retnl(mysql_select_db((MYSQL *)_parnl(1), _parc(2)));
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLQUERY) // int mysql_query(MYSQL *, char *)
|
||||
{
|
||||
_retnl((long) mysql_query((MYSQL *)_parnl(1), _parc(2)));
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLSTORER) // MYSQL_RES *mysql_store_result(MYSQL *)
|
||||
{
|
||||
_retnl((long) mysql_store_result((MYSQL *)_parnl(1)));
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLFREER) // void mysql_free_result(MYSQL_RES *)
|
||||
{
|
||||
mysql_free_result((MYSQL_RES *)_parnl(1));
|
||||
_ret();
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLFETCHR) // MYSQL_ROW *mysql_fetch_row(MYSQL_RES *)
|
||||
{
|
||||
MYSQL_RES *mresult = (MYSQL_RES *)_parnl(1);
|
||||
int num_fields = mysql_num_fields(mresult);
|
||||
ITEM aRow = _itemArrayNew(num_fields);
|
||||
ITEM temp;
|
||||
MYSQL_ROW mrow;
|
||||
int i;
|
||||
|
||||
mrow = mysql_fetch_row(mresult);
|
||||
|
||||
for (i = 0; i < num_fields; i++) {
|
||||
/* if field is not empty */
|
||||
if (mrow[i] != NULL) {
|
||||
temp = _itemPutC(NULL, mrow[i]);
|
||||
} else {
|
||||
temp = _itemPutC(NULL, "");
|
||||
}
|
||||
|
||||
_itemArrayPut(aRow, i + 1, temp);
|
||||
_itemRelease(temp);
|
||||
}
|
||||
_itemReturn(aRow);
|
||||
_itemRelease(aRow);
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLDATAS) // void mysql_data_seek(MYSQL_RES *, unsigned int)
|
||||
{
|
||||
mysql_data_seek((MYSQL_RES *)_parnl(1), (unsigned int)_parni(2));
|
||||
_ret();
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLNROWS) // my_ulongulong mysql_num_rows(MYSQL_RES *)
|
||||
{
|
||||
/* NOTE: I receive a my_ulongulong which I convert to a long, so I could lose precision */
|
||||
_retnl((long)mysql_num_rows(((MYSQL_RES *)_parnl(1))));
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLFETCHF) // MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *)
|
||||
{
|
||||
/* NOTE: field structure of MySQL has 8 members as of MySQL 3.22.x */
|
||||
ITEM aField = _itemArrayNew(8);
|
||||
|
||||
ITEM temp;
|
||||
MYSQL_FIELD *mfield;
|
||||
|
||||
mfield = mysql_fetch_field((MYSQL_RES *)_parnl(1));
|
||||
|
||||
if (!(mfield == NULL)) {
|
||||
temp = _itemPutC(NULL, mfield->name);
|
||||
_itemArrayPut(aField, 1, temp);
|
||||
_itemRelease(temp);
|
||||
|
||||
temp = _itemPutC(NULL, mfield->table);
|
||||
_itemArrayPut(aField, 2, temp);
|
||||
_itemRelease(temp);
|
||||
|
||||
temp = _itemPutC(NULL, mfield->def);
|
||||
_itemArrayPut(aField, 3, temp);
|
||||
_itemRelease(temp);
|
||||
|
||||
temp = _itemPutNL(NULL, (long)mfield->type);
|
||||
_itemArrayPut(aField, 4, temp);
|
||||
_itemRelease(temp);
|
||||
|
||||
temp = _itemPutNL(NULL, mfield->length);
|
||||
_itemArrayPut(aField, 5, temp);
|
||||
_itemRelease(temp);
|
||||
|
||||
temp = _itemPutNL(NULL, mfield->max_length);
|
||||
_itemArrayPut(aField, 6, temp);
|
||||
_itemRelease(temp);
|
||||
|
||||
temp = _itemPutNL(NULL, mfield->flags);
|
||||
_itemArrayPut(aField, 7, temp);
|
||||
_itemRelease(temp);
|
||||
|
||||
temp = _itemPutNL(NULL, mfield->decimals);
|
||||
_itemArrayPut(aField, 8, temp);
|
||||
_itemRelease(temp);
|
||||
|
||||
}
|
||||
_itemReturn(aField);
|
||||
_itemRelease(aField);
|
||||
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLFSEEK) // MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *, MYSQL_FIELD_OFFSET)
|
||||
{
|
||||
mysql_field_seek((MYSQL_RES *)_parnl(1), (MYSQL_FIELD_OFFSET)_parni(2));
|
||||
_ret();
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLNUMFI) // unsigned int mysql_num_fields(MYSQL_RES *)
|
||||
{
|
||||
_retnl(mysql_num_fields(((MYSQL_RES *)_parnl(1))));
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLLISTF) // MYSQL_RES *mysql_list_fields(MYSQL *, char *);
|
||||
{
|
||||
_retnl((long) mysql_list_fields((MYSQL *)_parnl(1), _parc(2), NULL));
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLGETERR) // char *mysql_error(MYSQL *);
|
||||
{
|
||||
_retc(mysql_error((MYSQL *)_parnl(1)));
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLLISTDB) // MYSQL_RES * mysql_list_dbs(MYSQL *, char * wild);
|
||||
{
|
||||
MYSQL * mysql = (MYSQL *)_parnl(1);
|
||||
MYSQL_RES * mresult;
|
||||
MYSQL_ROW mrow;
|
||||
long nr, i;
|
||||
ITEM aDBs;
|
||||
ITEM temp;
|
||||
|
||||
mresult = mysql_list_dbs(mysql, NULL);
|
||||
nr = mysql_num_rows(mresult);
|
||||
aDBs = _itemArrayNew(nr);
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
mrow = mysql_fetch_row(mresult);
|
||||
temp = _itemPutC(NULL, mrow[0]);
|
||||
|
||||
_itemArrayPut(aDBs, i + 1, temp);
|
||||
_itemRelease(temp);
|
||||
}
|
||||
|
||||
mysql_free_result(mresult);
|
||||
_itemReturn(aDBs);
|
||||
_itemRelease(aDBs);
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC(SQLLISTTBL) // MYSQL_RES * mysql_list_tables(MYSQL *, char * wild);
|
||||
{
|
||||
MYSQL * mysql = (MYSQL *)_parnl(1);
|
||||
MYSQL_RES * mresult;
|
||||
MYSQL_ROW mrow;
|
||||
long nr, i;
|
||||
ITEM aTables;
|
||||
ITEM temp;
|
||||
|
||||
mresult = mysql_list_tables(mysql, NULL);
|
||||
nr = mysql_num_rows(mresult);
|
||||
aTables = _itemArrayNew(nr);
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
|
||||
mrow = mysql_fetch_row(mresult);
|
||||
temp = _itemPutC(NULL, mrow[0]);
|
||||
|
||||
_itemArrayPut(aTables, i + 1, temp);
|
||||
_itemRelease(temp);
|
||||
}
|
||||
|
||||
mysql_free_result(mresult);
|
||||
_itemReturn(aTables);
|
||||
_itemRelease(aTables);
|
||||
}
|
||||
|
||||
|
||||
// returns bitwise and of first parameter with second
|
||||
HB_FUNC(SQLAND)
|
||||
{
|
||||
_retnl(_parnl(1) & _parnl(2));
|
||||
}
|
||||
|
||||
102
harbour/contrib/mysql/mysql.ch
Normal file
102
harbour/contrib/mysql/mysql.ch
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Harbour Project source code:
|
||||
* MySQL DBMS defines
|
||||
* These defines are clipper code level equivalent of mysql.h and mysql_com.h
|
||||
*
|
||||
* Copyright 2000 Maurilio Longo <maurilio.longo@libero.it>
|
||||
* www - http://www.harbour-project.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version, with one exception:
|
||||
*
|
||||
* The exception is that if you link the Harbour Runtime Library (HRL)
|
||||
* and/or the Harbour Virtual Machine (HVM) with other files to produce
|
||||
* an executable, this does not by itself cause the resulting executable
|
||||
* to be covered by the GNU General Public License. Your use of that
|
||||
* executable is in no way restricted on account of linking the HRL
|
||||
* and/or HVM code into it.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
|
||||
* their web site at http://www.gnu.org/).
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// MySQL field types
|
||||
|
||||
#define MYSQL_DECIMAL_TYPE 0
|
||||
// NOTE: TINY is used to map clipper logical values to MySQL tables, so 0 == .F., 1 == .T.
|
||||
#define MYSQL_TINY_TYPE 1
|
||||
#define MYSQL_SHORT_TYPE 2
|
||||
#define MYSQL_LONG_TYPE 3
|
||||
#define MYSQL_FLOAT_TYPE 4
|
||||
#define MYSQL_DOUBLE_TYPE 5
|
||||
#define MYSQL_NULL_TYPE 6
|
||||
#define MYSQL_TIMESTAMP_TYPE 7
|
||||
#define MYSQL_LONGLONG_TYPE 8
|
||||
#define MYSQL_INT24_TYPE 9
|
||||
#define MYSQL_DATE_TYPE 10
|
||||
#define MYSQL_TIME_TYPE 11
|
||||
#define MYSQL_DATETIME_TYPE 12
|
||||
#define MYSQL_YEAR_TYPE 13
|
||||
#define MYSQL_NEWDATE_TYPE 14
|
||||
#define MYSQL_ENUMTYPE 247
|
||||
#define MYSQL_SET_TYPE 248
|
||||
#define MYSQL_TINY_BLOB_TYPE 249
|
||||
#define MYSQL_MEDIUM_BLOB_TYPE 250
|
||||
#define MYSQL_LONG_BLOB_TYPE 251
|
||||
#define MYSQL_BLOB_TYPE 252
|
||||
#define MYSQL_VAR_STRING_TYPE 253
|
||||
#define MYSQL_STRING_TYPE 254
|
||||
|
||||
|
||||
|
||||
// MySQL field structure item number (C level structure is translated
|
||||
// to a clipper array)
|
||||
|
||||
#define MYSQL_FS_NAME 1 /* Name of column */
|
||||
#define MYSQL_FS_TABLE 2 /* Table of column if column was a field */
|
||||
#define MYSQL_FS_DEF 3 /* Default value (set by mysql_list_fields) */
|
||||
#define MYSQL_FS_TYPE 4 /* Type of field. Se mysql_com.h for types */
|
||||
#define MYSQL_FS_LENGTH 5 /* Width of column */
|
||||
#define MYSQL_FS_MAXLEN 6 /* Max width of selected set */
|
||||
#define MYSQL_FS_FLAGS 7 /* Div flags */
|
||||
#define MYSQL_FS_DECIMALS 8 /* Number of decimals in field */
|
||||
|
||||
|
||||
// MySQL field flags
|
||||
|
||||
#define NOT_NULL_FLAG 1 /* Field can't be NULL */
|
||||
#define PRI_KEY_FLAG 2 /* Field is part of a primary key */
|
||||
#define UNIQUE_KEY_FLAG 4 /* Field is part of a unique key */
|
||||
#define MULTIPLE_KEY_FLAG 8 /* Field is part of a key */
|
||||
#define BLOB_FLAG 16 /* Field is a blob */
|
||||
#define UNSIGNED_FLAG 32 /* Field is unsigned */
|
||||
#define ZEROFILL_FLAG 64 /* Field is zerofill */
|
||||
#define BINARY_FLAG 128
|
||||
/* The following are only sent to new clients */
|
||||
#define ENUM_FLAG 256 /* field is an enum */
|
||||
#define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */
|
||||
#define TIMESTAMP_FLAG 1024 /* Field is a timestamp */
|
||||
#define PART_KEY_FLAG 16384 /* Intern; Part of some key */
|
||||
#define GROUP_FLAG 32768 /* Intern group field */
|
||||
|
||||
|
||||
// Extension to DBS_xxx defines to encompass NOT NULL fields, needed by indexes
|
||||
#define DBS_NOTNULL 5 /* True if field has to be NOT NULL */
|
||||
|
||||
205
harbour/contrib/mysql/mysql.h
Normal file
205
harbour/contrib/mysql/mysql.h
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
|
||||
This file is public domain and comes with NO WARRANTY of any kind */
|
||||
|
||||
/* defines for libmysql */
|
||||
|
||||
#ifndef _mysql_h
|
||||
#define _mysql_h
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _global_h /* If not standard header */
|
||||
#include <sys/types.h>
|
||||
typedef char my_bool;
|
||||
#if !defined(__WIN32__) && !defined(WIN32)
|
||||
#define STDCALL
|
||||
typedef char byte;
|
||||
#else
|
||||
#define STDCALL __stdcall
|
||||
#endif
|
||||
typedef char * gptr;
|
||||
|
||||
#ifndef ST_USED_MEM_DEFINED
|
||||
#define ST_USED_MEM_DEFINED
|
||||
typedef struct st_used_mem { /* struct for once_alloc */
|
||||
struct st_used_mem *next; /* Next block in use */
|
||||
unsigned int left; /* memory left in block */
|
||||
unsigned int size; /* size of block */
|
||||
} USED_MEM;
|
||||
typedef struct st_mem_root {
|
||||
USED_MEM *free;
|
||||
USED_MEM *used;
|
||||
unsigned int min_malloc;
|
||||
unsigned int block_size;
|
||||
void (*error_handler)(void);
|
||||
} MEM_ROOT;
|
||||
#endif
|
||||
|
||||
#ifndef Socket_defined
|
||||
#ifdef __WIN32__
|
||||
#define Socket SOCKET
|
||||
#else
|
||||
typedef int Socket;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#include "mysql_com.h"
|
||||
#include "mysql_version.h"
|
||||
|
||||
extern unsigned int mysql_port;
|
||||
extern char *mysql_unix_port;
|
||||
|
||||
#define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG)
|
||||
#define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG)
|
||||
#define IS_BLOB(n) ((n) & BLOB_FLAG)
|
||||
#define IS_NUM(t) ((t) <= FIELD_TYPE_INT24 || (t) == FIELD_TYPE_YEAR)
|
||||
|
||||
typedef struct st_mysql_field {
|
||||
char *name; /* Name of column */
|
||||
char *table; /* Table of column if column was a field */
|
||||
char *def; /* Default value (set by mysql_list_fields) */
|
||||
enum enum_field_types type; /* Type of field. Se mysql_com.h for types */
|
||||
unsigned int length; /* Width of column */
|
||||
unsigned int max_length; /* Max width of selected set */
|
||||
unsigned int flags; /* Div flags */
|
||||
unsigned int decimals; /* Number of decimals in field */
|
||||
} MYSQL_FIELD;
|
||||
|
||||
typedef byte **MYSQL_ROW; /* return data as array of strings */
|
||||
typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */
|
||||
|
||||
typedef struct st_mysql_rows {
|
||||
struct st_mysql_rows *next; /* list of rows */
|
||||
MYSQL_ROW data;
|
||||
} MYSQL_ROWS;
|
||||
|
||||
typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */
|
||||
|
||||
typedef struct st_mysql_data {
|
||||
unsigned int rows;
|
||||
unsigned int fields;
|
||||
MYSQL_ROWS *data;
|
||||
MEM_ROOT alloc;
|
||||
} MYSQL_DATA;
|
||||
|
||||
enum mysql_status { MYSQL_STATUS_READY,MYSQL_STATUS_GET_RESULT,
|
||||
MYSQL_STATUS_USE_RESULT};
|
||||
|
||||
typedef struct st_mysql {
|
||||
NET net; /* Communication parameters */
|
||||
char *host,*user,*passwd,*unix_socket,*server_version,*host_info,
|
||||
*info,*db;
|
||||
unsigned int port,client_flag,server_capabilities;
|
||||
unsigned int protocol_version;
|
||||
unsigned int field_count;
|
||||
unsigned long thread_id; /* Id for connection in server */
|
||||
unsigned long affected_rows;
|
||||
unsigned long insert_id; /* id if insert on table with NEXTNR */
|
||||
unsigned long extra_info; /* Used by mysqlshow */
|
||||
enum mysql_status status;
|
||||
MYSQL_FIELD *fields;
|
||||
MEM_ROOT field_alloc;
|
||||
my_bool free_me; /* If free in mysql_close */
|
||||
my_bool reconnect; /* set to 1 if automatic reconnect */
|
||||
} MYSQL;
|
||||
|
||||
|
||||
typedef struct st_mysql_res {
|
||||
unsigned long row_count;
|
||||
unsigned int field_count, current_field;
|
||||
MYSQL_FIELD *fields;
|
||||
MYSQL_DATA *data;
|
||||
MYSQL_ROWS *data_cursor;
|
||||
MEM_ROOT field_alloc;
|
||||
MYSQL_ROW row; /* If unbuffered read */
|
||||
MYSQL_ROW current_row; /* buffer to current row */
|
||||
unsigned int *lengths; /* column lengths of current row */
|
||||
MYSQL *handle; /* for unbuffered reads */
|
||||
my_bool eof; /* Used my mysql_fetch_row */
|
||||
} MYSQL_RES;
|
||||
|
||||
|
||||
#define mysql_num_rows(res) (res)->row_count
|
||||
#define mysql_num_fields(res) (res)->field_count
|
||||
#define mysql_eof(res) (res)->eof
|
||||
#define mysql_fetch_field_direct(res,fieldnr) ((res)->fields[fieldnr])
|
||||
#define mysql_fetch_fields(res) (res)->fields
|
||||
#define mysql_row_tell(res) (res)->data_cursor
|
||||
#define mysql_field_tell(res) (res)->current_field
|
||||
|
||||
#define mysql_affected_rows(mysql) (mysql)->affected_rows
|
||||
#define mysql_insert_id(mysql) (mysql)->insert_id
|
||||
#define mysql_error(mysql) (mysql)->net.last_error
|
||||
#define mysql_errno(mysql) (mysql)->net.last_errno
|
||||
#define mysql_info(mysql) (mysql)->info
|
||||
#define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT)
|
||||
#define mysql_thread_id(mysql) (mysql)->thread_id
|
||||
|
||||
/* void STDCALL mysql_init(MYSQL *mysql); */
|
||||
MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host,
|
||||
const char *user, const char *passwd);
|
||||
#if MYSQL_VERSION_ID >= 32200
|
||||
MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
|
||||
const char *user,
|
||||
const char *passwd,
|
||||
const char *db,
|
||||
unsigned int port,
|
||||
const char *unix_socket,
|
||||
unsigned int clientflag);
|
||||
#else
|
||||
MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
|
||||
const char *user,
|
||||
const char *passwd,
|
||||
unsigned int port,
|
||||
const char *unix_socket,
|
||||
unsigned int clientflag);
|
||||
#endif
|
||||
void STDCALL mysql_close(MYSQL *sock);
|
||||
int STDCALL mysql_select_db(MYSQL *mysql, const char *db);
|
||||
int STDCALL mysql_query(MYSQL *mysql, const char *q);
|
||||
int STDCALL mysql_real_query(MYSQL *mysql, const char *q,
|
||||
unsigned int length);
|
||||
int STDCALL mysql_create_db(MYSQL *mysql, const char *DB);
|
||||
int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB);
|
||||
int STDCALL mysql_shutdown(MYSQL *mysql);
|
||||
int STDCALL mysql_dump_debug_info(MYSQL *mysql);
|
||||
int STDCALL mysql_refresh(MYSQL *mysql,
|
||||
unsigned int refresh_options);
|
||||
int STDCALL mysql_kill(MYSQL *mysql,unsigned long pid);
|
||||
char * STDCALL mysql_stat(MYSQL *mysql);
|
||||
char * STDCALL mysql_get_server_info(MYSQL *mysql);
|
||||
char * STDCALL mysql_get_client_info(void);
|
||||
char * STDCALL mysql_get_host_info(MYSQL *mysql);
|
||||
unsigned int STDCALL mysql_get_proto_info(MYSQL *mysql);
|
||||
MYSQL_RES * STDCALL mysql_list_dbs(MYSQL *mysql,const char *wild);
|
||||
MYSQL_RES * STDCALL mysql_list_tables(MYSQL *mysql,const char *wild);
|
||||
MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table,
|
||||
const char *wild);
|
||||
MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql);
|
||||
MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql);
|
||||
MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql);
|
||||
void STDCALL mysql_free_result(MYSQL_RES *result);
|
||||
void STDCALL mysql_data_seek(MYSQL_RES *mysql,unsigned int offset);
|
||||
MYSQL_ROW_OFFSET STDCALL mysql_row_seek(MYSQL_RES *mysql, MYSQL_ROW_OFFSET);
|
||||
MYSQL_FIELD_OFFSET STDCALL mysql_field_seek(MYSQL_RES *mysql,
|
||||
MYSQL_FIELD_OFFSET offset);
|
||||
MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *mysql);
|
||||
unsigned int * STDCALL mysql_fetch_lengths(MYSQL_RES *mysql);
|
||||
MYSQL_FIELD * STDCALL mysql_fetch_field(MYSQL_RES *handle);
|
||||
unsigned int STDCALL mysql_escape_string(char *to,const char *from,
|
||||
unsigned int from_length);
|
||||
void STDCALL mysql_debug(char *debug);
|
||||
|
||||
/* new api functions */
|
||||
|
||||
#define HAVE_MYSQL_REAL_CONNECT
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
160
harbour/contrib/mysql/mysql_com.h
Normal file
160
harbour/contrib/mysql/mysql_com.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
|
||||
This file is public domain and comes with NO WARRANTY of any kind */
|
||||
|
||||
/*
|
||||
** Common definition between mysql server & client
|
||||
*/
|
||||
|
||||
#ifndef _mysql_com_h
|
||||
#define _mysql_com_h
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NAME_LEN 64 /* Field/table name length */
|
||||
#define LOCAL_HOST "localhost"
|
||||
|
||||
#define MYSQL_PORT 3306 /* Alloced by ISI for MySQL */
|
||||
#define MYSQL_UNIX_ADDR "\\socket\\mysql.sock"
|
||||
|
||||
enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY,
|
||||
COM_FIELD_LIST,COM_CREATE_DB,COM_DROP_DB,COM_REFRESH,
|
||||
COM_SHUTDOWN,COM_STATISTICS,
|
||||
COM_PROCESS_INFO,COM_CONNECT,COM_PROCESS_KILL,
|
||||
COM_DEBUG};
|
||||
|
||||
#define NOT_NULL_FLAG 1 /* Field can't be NULL */
|
||||
#define PRI_KEY_FLAG 2 /* Field is part of a primary key */
|
||||
#define UNIQUE_KEY_FLAG 4 /* Field is part of a unique key */
|
||||
#define MULTIPLE_KEY_FLAG 8 /* Field is part of a key */
|
||||
#define BLOB_FLAG 16 /* Field is a blob */
|
||||
#define UNSIGNED_FLAG 32 /* Field is unsigned */
|
||||
#define ZEROFILL_FLAG 64 /* Field is zerofill */
|
||||
#define BINARY_FLAG 128
|
||||
/* The following are only sent to new clients */
|
||||
#define ENUM_FLAG 256 /* field is an enum */
|
||||
#define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */
|
||||
#define TIMESTAMP_FLAG 1024 /* Field is a timestamp */
|
||||
#define PART_KEY_FLAG 16384 /* Intern; Part of some key */
|
||||
#define GROUP_FLAG 32768 /* Intern group field */
|
||||
|
||||
#define REFRESH_GRANT 1 /* Refresh grant tables */
|
||||
#define REFRESH_LOG 2 /* Start on new log file */
|
||||
#define REFRESH_TABLES 4 /* close all tables */
|
||||
#define REFRESH_HOSTS 8 /* Flush host cache */
|
||||
#define REFRESH_FAST 32768 /* Intern flag */
|
||||
|
||||
#define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */
|
||||
#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */
|
||||
#define CLIENT_LONG_FLAG 4 /* Get all column flags */
|
||||
#define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */
|
||||
#define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */
|
||||
|
||||
#define MYSQL_ERRMSG_SIZE 200
|
||||
#define NET_READ_TIMEOUT 30 /* Timeout on read */
|
||||
#define NET_WRITE_TIMEOUT 60 /* Timeout on write */
|
||||
#define NET_WAIT_TIMEOUT 8*60*60 /* Wait for new query */
|
||||
|
||||
typedef struct st_net {
|
||||
Socket fd;
|
||||
int fcntl;
|
||||
unsigned char *buff,*buff_end,*write_pos;
|
||||
char last_error[MYSQL_ERRMSG_SIZE];
|
||||
unsigned int last_errno,max_packet,timeout,pkt_nr;
|
||||
my_bool error,return_errno;
|
||||
} NET;
|
||||
|
||||
#define packet_error ((unsigned int) -1)
|
||||
|
||||
enum enum_field_types { FIELD_TYPE_DECIMAL, FIELD_TYPE_TINY,
|
||||
FIELD_TYPE_SHORT, FIELD_TYPE_LONG,
|
||||
FIELD_TYPE_FLOAT, FIELD_TYPE_DOUBLE,
|
||||
FIELD_TYPE_NULL, FIELD_TYPE_TIMESTAMP,
|
||||
FIELD_TYPE_LONGLONG,FIELD_TYPE_INT24,
|
||||
FIELD_TYPE_DATE, FIELD_TYPE_TIME,
|
||||
FIELD_TYPE_DATETIME, FIELD_TYPE_YEAR,
|
||||
FIELD_TYPE_NEWDATE,
|
||||
FIELD_TYPE_ENUM=247,
|
||||
FIELD_TYPE_SET=248,
|
||||
FIELD_TYPE_TINY_BLOB=249,
|
||||
FIELD_TYPE_MEDIUM_BLOB=250,
|
||||
FIELD_TYPE_LONG_BLOB=251,
|
||||
FIELD_TYPE_BLOB=252,
|
||||
FIELD_TYPE_VAR_STRING=253,
|
||||
FIELD_TYPE_STRING=254
|
||||
};
|
||||
|
||||
#define FIELD_TYPE_CHAR FIELD_TYPE_TINY /* For compability */
|
||||
#define FIELD_TYPE_INTERVAL FIELD_TYPE_ENUM /* For compability */
|
||||
|
||||
extern unsigned long max_allowed_packet;
|
||||
extern unsigned long net_buffer_length;
|
||||
|
||||
#define net_new_transaction(net) ((net)->pkt_nr=0)
|
||||
int my_net_init(NET *net,Socket fd);
|
||||
void net_end(NET *net);
|
||||
void net_clear(NET *net);
|
||||
int net_flush(NET *net);
|
||||
int my_net_write(NET *net,const byte *packet,unsigned int len);
|
||||
int net_write_command(NET *net,unsigned char command,const byte *packet,
|
||||
unsigned int len);
|
||||
int net_real_write(NET *net,const byte *packet,unsigned int len);
|
||||
unsigned int my_net_read(NET *net);
|
||||
|
||||
struct rand_struct {
|
||||
unsigned long seed,seed2,max_value;
|
||||
double max_value_dbl;
|
||||
};
|
||||
|
||||
/* The following is for user defined functions */
|
||||
|
||||
enum Item_result {STRING_RESULT,REAL_RESULT,INT_RESULT};
|
||||
|
||||
typedef struct st_udf_args
|
||||
{
|
||||
unsigned int arg_count; /* Number of arguments */
|
||||
enum Item_result *arg_type; /* Pointer to item_results */
|
||||
char **args; /* Pointer to argument */
|
||||
unsigned long *lengths; /* Length of string arguments */
|
||||
} UDF_ARGS;
|
||||
|
||||
/* This holds information about the result */
|
||||
|
||||
typedef struct st_udf_init
|
||||
{
|
||||
my_bool maybe_null; /* 1 if function can return NULL */
|
||||
unsigned int decimals; /* for real functions */
|
||||
unsigned int max_length; /* For string functions */
|
||||
char *ptr; /* free pointer for function data */
|
||||
} UDF_INIT;
|
||||
|
||||
/* Prototypes to password functions */
|
||||
|
||||
void randominit(struct rand_struct *rand,unsigned long seed1,
|
||||
unsigned long seed2);
|
||||
double rnd(struct rand_struct *rand);
|
||||
void make_scrambled_password(char *to,const char *password);
|
||||
void get_salt_from_password(unsigned long *res,const char *password);
|
||||
char *scramble(char *to,const char *message,const char *password,
|
||||
my_bool old_ver);
|
||||
my_bool check_scramble(const char *scramble,const char *message,
|
||||
unsigned long *salt,my_bool old_ver);
|
||||
char *get_tty_password(char *opt_message);
|
||||
|
||||
#define NULL_LENGTH ((unsigned long) ~0) /* For net_store_length */
|
||||
|
||||
#ifdef __WIN32__
|
||||
#define socket_errno WSAGetLastError()
|
||||
#else
|
||||
#define socket_errno errno
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
13
harbour/contrib/mysql/mysql_version.h
Normal file
13
harbour/contrib/mysql/mysql_version.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
|
||||
This file is public domain and comes with NO WARRANTY of any kind */
|
||||
|
||||
/* Version numbers for protocol & mysqld */
|
||||
|
||||
#define MYSQL_SERVER_VERSION "3.21.33b"
|
||||
#define FRM_VER 6
|
||||
#define MYSQL_VERSION_ID 32133
|
||||
55
harbour/contrib/mysql/readme.txt
Normal file
55
harbour/contrib/mysql/readme.txt
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
24/july/2000 - Harbour MySQL access classes - readme file
|
||||
|
||||
|
||||
|
||||
This is work in progress, so it has to be fully tested and needs a few more methods to cover MySQL possibilities.
|
||||
|
||||
|
||||
This set of files gives you a mean to access a MySQL server, I've developed and tested them on a OS/2 platform,
|
||||
so changes to Makefile and import library for different platforms are not present.
|
||||
|
||||
In their present state MySQL classes are made up of these files:
|
||||
|
||||
mysql.c: low level wrapper around MySQL client API. It requires libmysqlclient.a library
|
||||
mysql.h,
|
||||
mysql_com.h,
|
||||
mysql_version.h: from MySQL distribution, type and defines of MySQL client api (under OS/2 with OS/2 port of
|
||||
MySql you need to use the one from 3.21.33b build which is the only one with a single
|
||||
threaded libmysqlclient.a client library and works ok even with latest MySQL/2 availble).
|
||||
mysql.ch: clipper level defines of MySQL types
|
||||
tmysql.prg: MySQL access classes
|
||||
test.prg: a little test program which wont work for you :-) since it uses a .dbf file not
|
||||
provided. Use it as a small tutorial of tmysql.prg provided functions.
|
||||
Makefile: my makefile for OS/2 gcc, you'll surely need to change it to adapt to your needs/platform.
|
||||
|
||||
|
||||
tmysql.prg defines four classes:
|
||||
|
||||
TMySQLServer: manages access to a MySQL server and returns an oServer object to which you'll send all your
|
||||
queries;
|
||||
TMySQLQuery: a standard query to an oServer with joins. Every query has a GetRow() method
|
||||
which on every call returns a TMySQLRow object which, in turn, contains requested fields.
|
||||
Query objects convert MySQL answers (which is an array of strings) to clipper level types.
|
||||
At present time N (with decimals), L, D, and C clipper types are supported.
|
||||
TMySQLTable: It's a descendant of a TMySQLQuery and you'll receive it when your query has no joins.
|
||||
It adds Update(), Append() and Delete() methods which receive a TMySQLRow object and
|
||||
reflect changes to the MySQL table from which they come.
|
||||
Please note that TMySQLQuery objects don't have these methods, so, if you want to change
|
||||
a row received from a TMySQLQuery object you need to construct a valid SQL query and submit
|
||||
it to an oServer object.
|
||||
TMySQLRow: Every row returned by a SELECT is converted to a TMySQLRow object. This object handles
|
||||
fields and has methods to access fields given a field name or position.
|
||||
|
||||
I'm aware that this brief document doesn't explain a lot about MySQL access classes and I'm sorry for that.
|
||||
I'll try to update it as work on these classes goes by and I'll like to receive feedbak and suggestions
|
||||
from users (if any :-))
|
||||
|
||||
Excuse my poor english and happy selecting :-)
|
||||
|
||||
Maurilio Longo - maurilio.longo@libero.it
|
||||
|
||||
117
harbour/contrib/mysql/test.prg
Normal file
117
harbour/contrib/mysql/test.prg
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Harbour Project source code:
|
||||
* MySQL DBMS test program
|
||||
*
|
||||
* Copyright 2000 Maurilio Longo <maurilio.longo@libero.it>
|
||||
* www - http://www.harbour-project.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version, with one exception:
|
||||
*
|
||||
* The exception is that if you link the Harbour Runtime Library (HRL)
|
||||
* and/or the Harbour Virtual Machine (HVM) with other files to produce
|
||||
* an executable, this does not by itself cause the resulting executable
|
||||
* to be covered by the GNU General Public License. Your use of that
|
||||
* executable is in no way restricted on account of linking the HRL
|
||||
* and/or HVM code into it.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
|
||||
* their web site at http://www.gnu.org/).
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dbstruct.ch"
|
||||
|
||||
procedure main(cArg)
|
||||
|
||||
local oServer, oQuery, oQuery2, oRow, i, aStru
|
||||
|
||||
SET CENTURY ON
|
||||
SET EPOCH TO 1960
|
||||
|
||||
oServer := TMySQLServer():New("localhost", "root", "")
|
||||
if oServer:NetErr()
|
||||
Alert(oServer:Error())
|
||||
endif
|
||||
|
||||
oServer:SelectDB("ims")
|
||||
oQuery:=oServer:Query("SELECT * from maga limit 10")
|
||||
oRow := oQuery:GetRow()
|
||||
|
||||
dbUseArea(.T.,, cArg, "wn", .F.)
|
||||
|
||||
if !oServer:DeleteTable("test")
|
||||
Alert(oServer:Error())
|
||||
endif
|
||||
|
||||
aStru := dbStruct()
|
||||
if oServer:CreateTable("test", aStru)
|
||||
Alert("test created successfully")
|
||||
else
|
||||
Alert(oServer:Error())
|
||||
endif
|
||||
|
||||
oQuery:=oServer:Query("SELECT C111, C116, C134 from maga limit 10")
|
||||
oRow := oQuery:GetRow()
|
||||
|
||||
oServer:Destroy()
|
||||
|
||||
while !wn->(eof())
|
||||
|
||||
oQuery2 := oServer:Query("SELECT * from test where CODF='" + wn->CODF + "' and CODP='" + wn->CODP + "'")
|
||||
|
||||
if oQuery2:LastRec() > 0
|
||||
|
||||
? "found "
|
||||
|
||||
oRow := oQuery2:GetRow()
|
||||
|
||||
oRow:FieldPut(oRow:FieldPos("GIACENZA"), oRow:FieldGet(oRow:FieldPos("GIACENZA")) + wn->GIACENZA)
|
||||
oRow:FieldPut(oRow:FieldPos("ACQGR"), oRow:FieldGet(oRow:FieldPos("ACQGR")) + wn->ACQGR)
|
||||
oRow:FieldPut(oRow:FieldPos("ACQDI"), oRow:FieldGet(oRow:FieldPos("ACQDI")) + wn->ACQDI)
|
||||
|
||||
if !oQuery2:Update(oRow)
|
||||
Alert(oQuery2:Error())
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
? wn->CODF + " " + wn->CODP
|
||||
|
||||
oRow := oQuery:GetBlankRow()
|
||||
|
||||
oRow:FieldPut(oRow:FieldPos("CODF"), wn->CODF)
|
||||
oRow:FieldPut(oRow:FieldPos("CODP"), wn->CODP)
|
||||
oRow:FieldPut(oRow:FieldPos("GIACENZA"), wn->GIACENZA)
|
||||
oRow:FieldPut(oRow:FieldPos("DATA"), wn->DATA + 365 * 100)
|
||||
oRow:FieldPut(oRow:FieldPos("ACQGR"), wn->ACQGR)
|
||||
oRow:FieldPut(oRow:FieldPos("ACQDI"), wn->ACQDI)
|
||||
|
||||
if !oQuery:Append(oRow)
|
||||
Alert(oQuery:Error())
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
wn->(dbSkip())
|
||||
|
||||
enddo
|
||||
|
||||
|
||||
wn->(dbCloseArea())
|
||||
|
||||
return
|
||||
|
||||
835
harbour/contrib/mysql/tmysql.prg
Normal file
835
harbour/contrib/mysql/tmysql.prg
Normal file
@@ -0,0 +1,835 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Harbour Project source code:
|
||||
* MySQL DBMS classes.
|
||||
* These classes try to emulate clipper dbXXXX functions on a SQL query
|
||||
*
|
||||
* Copyright 2000 Maurilio Longo <maurilio.longo@libero.it>
|
||||
* www - http://www.harbour-project.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version, with one exception:
|
||||
*
|
||||
* The exception is that if you link the Harbour Runtime Library (HRL)
|
||||
* and/or the Harbour Virtual Machine (HVM) with other files to produce
|
||||
* an executable, this does not by itself cause the resulting executable
|
||||
* to be covered by the GNU General Public License. Your use of that
|
||||
* executable is in no way restricted on account of linking the HRL
|
||||
* and/or HVM code into it.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
|
||||
* their web site at http://www.gnu.org/).
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hbclass.ch"
|
||||
#include "common.ch"
|
||||
#include "dbstruct.ch"
|
||||
#include "mysql.ch"
|
||||
|
||||
|
||||
// Returns an SQL string with clipper value converted ie. Date() -> "'YYYY-MM-DD'"
|
||||
static function ClipValue2SQL(Value)
|
||||
|
||||
local cValue := ""
|
||||
|
||||
do case
|
||||
case Valtype(Value) == "N"
|
||||
cValue := AllTrim(Str(Value))
|
||||
|
||||
case Valtype(Value) == "D"
|
||||
if !Empty(Value)
|
||||
// MySQL dates are like YYYY-MM-DD
|
||||
cValue := "'" + Str(Year(Value), 4) + "-" + PadL(Month(Value), 2, "0") + "-" + PadL(Day(Value), 2, "0") + "'"
|
||||
else
|
||||
cValue := "''"
|
||||
endif
|
||||
|
||||
case Valtype(Value) == "C"
|
||||
cValue := "'" + StrTran(Value, "'", "\'") + "'"
|
||||
|
||||
case Valtype(Value) == "L"
|
||||
cValue := AllTrim(Str(iif(Value == .F., 0, 1)))
|
||||
|
||||
otherwise
|
||||
cValue := "''" // NOTE: Here we lose values we cannot convert
|
||||
|
||||
endcase
|
||||
|
||||
return cValue
|
||||
|
||||
|
||||
// Every single row of an answer
|
||||
CLASS TMySQLRow
|
||||
|
||||
DATA aRow // a single row of answer
|
||||
DATA aDirty // array of booleans set to .T. if corresponding field of aRow has been changed
|
||||
DATA aOldValue // If aDirty[n] is .T. aOldValue[n] keeps a copy of changed value if aRow[n] is part of a primary key
|
||||
|
||||
DATA aFieldStruct // type of each field
|
||||
DATA cTable // Name of table containing this row, empty if TMySQLQuery returned this row
|
||||
|
||||
METHOD New(aRow, aFStruct, cTableName) // Create a new Row object
|
||||
|
||||
METHOD FieldGet(nNum) // Same as clipper ones
|
||||
METHOD FieldPut(nNum, Value)
|
||||
METHOD FieldName(nPosition)
|
||||
METHOD FieldPos(cFieldName)
|
||||
|
||||
METHOD MakePrimaryKeyWhere() // returns a WHERE x=y statement which uses primary key (if available)
|
||||
|
||||
ENDCLASS
|
||||
|
||||
|
||||
METHOD New(aRow, aFStruct, cTableName) CLASS TMySQLRow
|
||||
|
||||
default cTableName to ""
|
||||
default aFStruct to {}
|
||||
|
||||
::cTable := cTableName
|
||||
::aFieldStruct := aFStruct
|
||||
|
||||
::aRow := aRow
|
||||
::aFieldStruct := aFStruct
|
||||
|
||||
::aDirty := Array(Len(::aRow))
|
||||
::aOldValue := Array(Len(::aRow))
|
||||
AFill(::aDirty, .F.)
|
||||
|
||||
return Self
|
||||
|
||||
|
||||
METHOD FieldGet(nNum) CLASS TMySQLRow
|
||||
|
||||
if nNum > 0 .AND. nNum <= Len(::aRow)
|
||||
return ::aRow[nNum]
|
||||
else
|
||||
return nil
|
||||
endif
|
||||
|
||||
return
|
||||
|
||||
|
||||
METHOD FieldPut(nNum, Value) CLASS TMySQLRow
|
||||
|
||||
if nNum > 0 .AND. nNum <= Len(::aRow)
|
||||
if Valtype(Value) == Valtype(::aRow[nNum]) .OR. Empty(::aRow[nNum])
|
||||
::aRow[nNum] := Value
|
||||
::aDirty[nNum] := .T.
|
||||
return Value
|
||||
endif
|
||||
endif
|
||||
|
||||
return nil
|
||||
|
||||
|
||||
// Given a field name returns it's position
|
||||
METHOD FieldPos(cFieldName) CLASS TMySQLRow
|
||||
|
||||
local cUpperName, nPos := 1
|
||||
|
||||
cUpperName := Upper(cFieldName)
|
||||
|
||||
/* NOTE: this code block kills harbour if called a few thousand times
|
||||
nPos := AScan(::aFieldStruct, {|aItem| iif(Upper(aItem[MYSQL_FS_NAME]) == cUpperName, .T., .F.)})
|
||||
*/
|
||||
|
||||
while nPos <= Len(::aFieldStruct)
|
||||
if Upper(::aFieldStruct[nPos][MYSQL_FS_NAME]) == cUpperName
|
||||
exit
|
||||
endif
|
||||
nPos++
|
||||
enddo
|
||||
|
||||
return nPos
|
||||
|
||||
|
||||
// Returns name of field N
|
||||
METHOD FieldName(nPosition) CLASS TMySQLRow
|
||||
|
||||
if nPosition >=1 .AND. nPosition <= Len(::aFieldStruct)
|
||||
return ::aFieldStruct[nPosition][MYSQL_FS_NAME]
|
||||
else
|
||||
return ""
|
||||
endif
|
||||
|
||||
return
|
||||
|
||||
|
||||
// returns a WHERE x=y statement which uses primary key (if available)
|
||||
METHOD MakePrimaryKeyWhere() CLASS TMySQLRow
|
||||
|
||||
local ni, cWhere := " WHERE "
|
||||
|
||||
for nI := 1 to Len(::aFieldStruct)
|
||||
|
||||
// search for fields part of a primary key
|
||||
if sqlAND(::aFieldStruct[nI][MYSQL_FS_FLAGS], PRI_KEY_FLAG) == PRI_KEY_FLAG
|
||||
|
||||
cWhere += ::aFieldStruct[nI][MYSQL_FS_NAME] + "="
|
||||
|
||||
// if a part of a primary key has been changed, use original value
|
||||
if ::aDirty[nI]
|
||||
cWhere += ClipValue2SQL(::aOldValue[nI])
|
||||
else
|
||||
cWhere += ClipValue2SQL(::aRow[nI])
|
||||
endif
|
||||
|
||||
cWhere += " AND "
|
||||
endif
|
||||
|
||||
next
|
||||
|
||||
// remove last " AND "
|
||||
cWhere := Left(cWhere, Len(cWhere) - 5)
|
||||
|
||||
return cWhere
|
||||
|
||||
/* ----------------------------------------------------------------------------------------*/
|
||||
|
||||
// Every single query submitted to MySQL server
|
||||
CLASS TMySQLQuery
|
||||
|
||||
DATA nSocket // connection handle to MySQL server
|
||||
DATA nResultHandle // result handle received from MySQL
|
||||
|
||||
DATA cQuery // copy of query that generated this object
|
||||
|
||||
DATA nNumRows // number of rows available on answer NOTE MySQL is 0 based
|
||||
DATA nCurRow // I'm currently over row number
|
||||
|
||||
DATA nNumFields // how many fields per row
|
||||
DATA aFieldStruct // type of each field, a copy is here a copy inside each row
|
||||
|
||||
DATA lError // .T. if last operation failed
|
||||
|
||||
METHOD New(nSocket, cQuery) // New query object
|
||||
METHOD Destroy()
|
||||
|
||||
METHOD GetRow(nRow) // return Row n of answer
|
||||
|
||||
METHOD Skip(nRows) // Same as clipper ones
|
||||
|
||||
METHOD Bof() INLINE ::nCurRow == 1
|
||||
METHOD Eof() INLINE ::nCurRow > ::nNumRows
|
||||
METHOD RecNo() INLINE ::nCurRow
|
||||
METHOD LastRec() INLINE ::nNumRows
|
||||
|
||||
METHOD FCount()
|
||||
|
||||
METHOD NetErr() INLINE ::lError // Returns .T. if something went wrong
|
||||
METHOD Error() // Returns textual description of last error and clears ::lError
|
||||
|
||||
ENDCLASS
|
||||
|
||||
|
||||
METHOD New(nSocket, cQuery) CLASS TMySQLQuery
|
||||
|
||||
local nI, aField, rc
|
||||
|
||||
::aFieldStruct := {}
|
||||
::nSocket := nSocket
|
||||
::cQuery := cQuery
|
||||
::nCurRow := 1
|
||||
::lError := .F.
|
||||
|
||||
if (rc := sqlQuery(nSocket, cQuery)) == 0
|
||||
|
||||
// save result set
|
||||
::nResultHandle := sqlStoreR(nSocket)
|
||||
::nNumRows := sqlNRows(::nResultHandle)
|
||||
::nNumFields := sqlNumFi(::nResultHandle)
|
||||
|
||||
for nI := 1 to ::nNumFields
|
||||
|
||||
aField := sqlFetchF(::nResultHandle)
|
||||
AAdd(::aFieldStruct, aField)
|
||||
|
||||
next
|
||||
|
||||
else
|
||||
::nResultHandle := nil
|
||||
::nNumFields := 0
|
||||
::nNumRows := 0
|
||||
::lError := .T.
|
||||
|
||||
endif
|
||||
|
||||
return Self
|
||||
|
||||
|
||||
METHOD Skip(nRows) CLASS TMySQLQuery
|
||||
|
||||
// NOTE: MySQL row count starts from 0
|
||||
default nRows to 1
|
||||
|
||||
if nRows == 0
|
||||
// No move
|
||||
|
||||
elseif nRows < 0
|
||||
// Negative movement
|
||||
::nCurRow := Max(::nCurRow - nRows, 1)
|
||||
|
||||
else
|
||||
// positive movement
|
||||
::nCurRow := Min(::nCurRow + nRows, ::nNumRows + 1)
|
||||
|
||||
endif
|
||||
|
||||
sqlDataS(::nResultHandle, ::nCurRow - 1)
|
||||
|
||||
return Self
|
||||
|
||||
|
||||
/* Given a three letter month name gives back month number as two char string (ie. Apr -> 04) */
|
||||
static function NMonth(cMonthValue)
|
||||
|
||||
static cMonths := {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dec" }
|
||||
|
||||
nMonth := AScan(cMonths, cMonthValue)
|
||||
|
||||
return PadL(nMonth, 2, "0")
|
||||
|
||||
|
||||
// Get row n of a query and return it as a TMySQLRow object
|
||||
METHOD GetRow(nRow) CLASS TMySQLQuery
|
||||
|
||||
local aRow := NIL
|
||||
local oRow := NIL
|
||||
local i
|
||||
|
||||
default nRow to 0
|
||||
|
||||
if ::nResultHandle <> NIL
|
||||
if nRow >= 1 .AND. nRow <= ::nNumRows
|
||||
|
||||
// NOTE: row count starts from 0
|
||||
sqlDataS(::nResultHandle, nRow - 1)
|
||||
::nCurRow := nRow
|
||||
else
|
||||
::nCurRow++
|
||||
endif
|
||||
|
||||
aRow := sqlFetchR(::nResultHandle, ::nNumFields)
|
||||
|
||||
if aRow <> NIL
|
||||
|
||||
// Convert answer from text field to correct clipper types
|
||||
for i := 1 to ::nNumFields
|
||||
do case
|
||||
case ::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_TINY_TYPE
|
||||
aRow[i] := iif(Val(aRow[i]) == 0, .F., .T.)
|
||||
|
||||
case ::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_SHORT_TYPE .OR.;
|
||||
::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_LONG_TYPE
|
||||
aRow[i] := Val(aRow[i])
|
||||
|
||||
case ::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_DOUBLE_TYPE .OR.;
|
||||
::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_FLOAT_TYPE
|
||||
aRow[i] := Val(aRow[i])
|
||||
|
||||
case ::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_DATE_TYPE
|
||||
if Empty(aRow[i])
|
||||
aRow[i] := CToD("")
|
||||
else
|
||||
// Date format YYYY-MM-DD
|
||||
aRow[i] := CToD(__StrToken(aRow[i], 2, ",") + "-" + __StrToken(aRow[i], 3, ",") + "-" + __StrToken(aRow[i], 1, ","))
|
||||
endif
|
||||
otherwise
|
||||
endcase
|
||||
next
|
||||
|
||||
oRow := TMySQLRow():New(aRow, ::aFieldStruct)
|
||||
endif
|
||||
endif
|
||||
|
||||
return iif(aRow == NIL, NIL, oRow)
|
||||
|
||||
|
||||
// Free result handle and associated resources
|
||||
METHOD Destroy() CLASS TMySQLQuery
|
||||
|
||||
sqlFreeR(::nResultHandle)
|
||||
|
||||
return Self
|
||||
|
||||
|
||||
METHOD FCount() CLASS TMySQLQuery
|
||||
|
||||
return ::nNumFields
|
||||
|
||||
|
||||
METHOD Error() CLASS TMySQLQuery
|
||||
|
||||
::lError := .F.
|
||||
|
||||
return sqlGetErr(::nSocket)
|
||||
|
||||
/* ----------------------------------------------------------------------------------------*/
|
||||
|
||||
// A Table is a query without joins; this way I can Insert() e Delete() rows.
|
||||
// NOTE: it's always a SELECT result, so it will contain a full table only if
|
||||
// SELECT * FROM ... was issued
|
||||
CLASS TMySQLTable FROM TMySQLQuery
|
||||
|
||||
DATA cTable // name of table
|
||||
|
||||
METHOD New(nSocket, cQuery, cTableName)
|
||||
METHOD GetRow(nRow)
|
||||
|
||||
METHOD Update(oRow) // Gets an oRow and updates changed fields
|
||||
METHOD Delete(oRow) // Deletes passed row from table
|
||||
METHOD Append(oRow) // Inserts passed row into table
|
||||
METHOD GetBlankRow() // Returns an empty row with all available fields empty
|
||||
|
||||
ENDCLASS
|
||||
|
||||
|
||||
/* TODO: change to reflect MySQL lack of _rowid field */
|
||||
METHOD New(nSocket, cQuery, cTableName) CLASS TMySQLTable
|
||||
|
||||
local cTrimmedQuery, nRes, i, aField
|
||||
|
||||
::cTable := cTableName
|
||||
|
||||
cTrimmedQuery := AllTrim(cQuery)
|
||||
|
||||
super:New(nSocket, cTrimmedQuery)
|
||||
|
||||
return Self
|
||||
|
||||
|
||||
METHOD GetRow(nRow) CLASS TMySQLTable
|
||||
|
||||
local oRow := super:GetRow(nRow)
|
||||
|
||||
if oRow <> NIL
|
||||
oRow:cTable := ::cTable
|
||||
endif
|
||||
|
||||
return oRow
|
||||
|
||||
|
||||
/* Creates an update query for changed fields and submits it to server */
|
||||
METHOD Update(oRow) CLASS TMySQLTable
|
||||
|
||||
local cUpdateQuery := "UPDATE " + ::cTable + " SET "
|
||||
local i, cField
|
||||
|
||||
// is this a row of this table ?
|
||||
if oRow:cTable == ::cTable
|
||||
|
||||
for i := 1 to Len(oRow:aRow)
|
||||
|
||||
if oRow:aDirty[i]
|
||||
cUpdateQuery += oRow:aFieldStruct[i][MYSQL_FS_NAME] + "=" + ClipValue2SQL(oRow:aRow[i]) + ","
|
||||
endif
|
||||
next
|
||||
|
||||
// remove last comma
|
||||
cUpdateQuery := Left(cUpdateQuery, Len(cUpdateQuery) -1)
|
||||
|
||||
cUpdateQuery += oRow:MakePrimaryKeyWhere()
|
||||
|
||||
if sqlQuery(::nSocket, cUpdateQuery) == 0
|
||||
// All values are commited
|
||||
Afill(oRow:aDirty, .F.)
|
||||
return .T.
|
||||
|
||||
else
|
||||
::lError := .T.
|
||||
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
return .F.
|
||||
|
||||
|
||||
METHOD Delete(oRow) CLASS TMySQLTable
|
||||
|
||||
local cDeleteQuery := "DELETE FROM " + ::cTable
|
||||
|
||||
// is this a row of this table ?
|
||||
if oRow:cTable == ::cTable
|
||||
|
||||
cDeleteQuery += oRow:MakePrimaryKeyWhere()
|
||||
|
||||
if sqlQuery(::nSocket, cDeleteQuery) == 1
|
||||
return .T.
|
||||
|
||||
else
|
||||
::lError := .T.
|
||||
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
return .F.
|
||||
|
||||
|
||||
// Adds a row with values passed into oRow
|
||||
METHOD Append(oRow) CLASS TMySQLTable
|
||||
|
||||
local cInsertQuery := "INSERT INTO " + ::cTable + " ("
|
||||
local i, cField
|
||||
|
||||
// is this a row of this table ?
|
||||
if oRow:cTable == ::cTable
|
||||
|
||||
// field names
|
||||
for i := 1 to Len(oRow:aRow)
|
||||
cInsertQuery += oRow:aFieldStruct[i][MYSQL_FS_NAME] + ","
|
||||
next
|
||||
// remove last comma from list
|
||||
cInsertQuery := Left(cInsertQuery, Len(cInsertQuery) -1) + ") VALUES ("
|
||||
|
||||
// field values
|
||||
for i := 1 to Len(oRow:aRow)
|
||||
cInsertQuery += ClipValue2SQL(oRow:aRow[i]) + ","
|
||||
|
||||
next
|
||||
|
||||
// remove last comma from list of values and add closing parenthesis
|
||||
cInsertQuery := Left(cInsertQuery, Len(cInsertQuery) -1) + ")"
|
||||
|
||||
if sqlQuery(::nSocket, cInsertQuery) == 0
|
||||
return .T.
|
||||
else
|
||||
::lError := .T.
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
return .F.
|
||||
|
||||
|
||||
METHOD GetBlankRow() CLASS TMySQLTable
|
||||
|
||||
local i
|
||||
local aRow := Array(::FCount())
|
||||
|
||||
// crate an array of empty fields
|
||||
for i := 1 to ::FCount()
|
||||
|
||||
do case
|
||||
case ::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_STRING_TYPE .OR.;
|
||||
::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_VAR_STRING_TYPE
|
||||
aRow[i] := ""
|
||||
|
||||
case ::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_SHORT_TYPE .OR.;
|
||||
::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_LONG_TYPE
|
||||
aRow[i] := 0
|
||||
|
||||
case ::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_TINY_TYPE
|
||||
aRow[i] := .F.
|
||||
|
||||
case ::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_DOUBLE_TYPE .OR.;
|
||||
::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_FLOAT_TYPE
|
||||
aRow[i] := 0.0
|
||||
|
||||
case ::aFieldStruct[i][MYSQL_FS_TYPE] == MYSQL_DATE_TYPE
|
||||
aRow[i] := CToD("")
|
||||
|
||||
otherwise
|
||||
aRow[i] := nil
|
||||
|
||||
endcase
|
||||
next
|
||||
|
||||
return TMySQLRow():New(aRow, ::aFieldStruct, ::cTable, .F.)
|
||||
|
||||
return nil
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------------------*/
|
||||
|
||||
// Every available MySQL server
|
||||
CLASS TMySQLServer
|
||||
|
||||
DATA nSocket // connection handle to server (currently pointer to a MYSQL structure)
|
||||
DATA cServer // server name
|
||||
DATA cDBName // Selected DB
|
||||
DATA cUser // user accessing db
|
||||
DATA cPassword // his/her password
|
||||
DATA lError // .T. if occurred an error
|
||||
|
||||
METHOD New(cServer, cUser, cPassword) // Opens connection to a server, returns a server object
|
||||
METHOD Destroy() // Closes connection to server
|
||||
|
||||
METHOD SelectDB(cDBName) // Which data base I will use for subsequent queries
|
||||
|
||||
METHOD CreateTable(cTable, aStruct) // Create new table using the same syntax of dbCreate()
|
||||
METHOD DeleteTable(cTable) // delete table
|
||||
METHOD TableStruct(cTable) // returns a structure array compatible with clipper's dbStruct() ones
|
||||
METHOD CreateIndex(cName, cTable, aFNames, lUnique) // Create an index (unique) on field name(s) passed as an array of strings aFNames
|
||||
METHOD DeleteIndex(cName, cTable) // Delete index cName from cTable
|
||||
|
||||
METHOD ListDBs() // returns an array with list of data bases available
|
||||
METHOD ListTables() // returns an array with list of available tables in current database
|
||||
|
||||
METHOD Query(cQuery) // Gets a textual query and returns a TMySQLQuery or TMySQLTable object
|
||||
|
||||
METHOD NetErr() INLINE ::lError // Returns .T. if something went wrong
|
||||
METHOD Error() // Returns textual description of last error
|
||||
|
||||
ENDCLASS
|
||||
|
||||
|
||||
METHOD New(cServer, cUser, cPassword) CLASS TMySQLServer
|
||||
|
||||
::cServer := cServer
|
||||
::cUser := cUser
|
||||
::cPassword := cPassword
|
||||
::nSocket := sqlConnect(cServer, cUser, cPassword)
|
||||
::lError := .F.
|
||||
|
||||
if ::nSocket == 0
|
||||
::lError := .T.
|
||||
endif
|
||||
|
||||
return Self
|
||||
|
||||
METHOD Destroy() CLASS TMySQLServer
|
||||
|
||||
sqlClose(::nSocket)
|
||||
|
||||
return Self
|
||||
|
||||
|
||||
METHOD SelectDB(cDBName) CLASS TMySQLServer
|
||||
|
||||
if sqlSelectD(::nSocket, cDBName) == 0
|
||||
::cDBName := cDBName
|
||||
return .T.
|
||||
else
|
||||
::cDBName := ""
|
||||
endif
|
||||
|
||||
return .F.
|
||||
|
||||
|
||||
// NOTE: OS/2 port of MySQL is picky about table names, that is if you create a table with
|
||||
// an upper case name you cannot alter it (for example) using a lower case name, this violates
|
||||
// OS/2 case insensibility about names
|
||||
METHOD CreateTable(cTable, aStruct) CLASS TMySQLServer
|
||||
|
||||
local cCreateQuery := "CREATE TABLE " + cTable + " ("
|
||||
local i
|
||||
|
||||
// returns NOT NULL if extended structure has DBS_NOTNULL field to true
|
||||
local cNN := {|aArr| iif(Len(aArr) > DBS_DEC, iif(aArr[DBS_NOTNULL], " NOT NULL ", ""), "")}
|
||||
|
||||
for i := 1 to Len(aStruct)
|
||||
do case
|
||||
case aStruct[i][DBS_TYPE] == "C"
|
||||
cCreateQuery += aStruct[i][DBS_NAME] + " char(" + AllTrim(Str(aStruct[i][DBS_LEN])) + ")" + Eval(cNN, aStruct[i]) + ","
|
||||
|
||||
case aStruct[i][DBS_TYPE] == "N"
|
||||
if aStruct[i][DBS_DEC] == 0
|
||||
cCreateQuery += aStruct[i][DBS_NAME] + " int " + Eval(cNN, aStruct[i]) + ","
|
||||
else
|
||||
cCreateQuery += aStruct[i][DBS_NAME] + " real " + Eval(cNN, aStruct[i]) + ","
|
||||
endif
|
||||
|
||||
case aStruct[i][DBS_TYPE] == "D"
|
||||
cCreateQuery += aStruct[i][DBS_NAME] + " date " + Eval(cNN, aStruct[i]) + ","
|
||||
|
||||
case aStruct[i][DBS_TYPE] == "L"
|
||||
cCreateQuery += aStruct[i][DBS_NAME] + " tinyint " + Eval(cNN, aStruct[i]) + ","
|
||||
|
||||
otherwise
|
||||
cCreateQuery += aStruct[i][DBS_NAME] + " char(" + AllTrim(Str(aStruct[i][DBS_LEN])) + ")" + Eval(cNN, aStruct[i]) + ","
|
||||
|
||||
endcase
|
||||
|
||||
next
|
||||
|
||||
// remove last comma from list
|
||||
cCreateQuery := Left(cCreateQuery, Len(cCreateQuery) -1) + ")"
|
||||
|
||||
if sqlQuery(::nSocket, cCreateQuery) == 0
|
||||
return .T.
|
||||
else
|
||||
::lError := .T.
|
||||
endif
|
||||
|
||||
return .F.
|
||||
|
||||
|
||||
METHOD CreateIndex(cName, cTable, aFNames, lUnique) CLASS TMySQLServer
|
||||
|
||||
local cCreateQuery := "CREATE "
|
||||
local i
|
||||
|
||||
default lUnique to .F.
|
||||
|
||||
if lUnique
|
||||
cCreateQuery += "UNIQUE INDEX "
|
||||
else
|
||||
cCreateQuery += "INDEX "
|
||||
endif
|
||||
|
||||
cCreateQuery += cName + " ON " + cTable + " ("
|
||||
|
||||
for i := 1 to Len(aFNames)
|
||||
cCreateQuery += aFNames[i] + ","
|
||||
next
|
||||
|
||||
// remove last comma from list
|
||||
cCreateQuery := Left(cCreateQuery, Len(cCreateQuery) -1) + ")"
|
||||
|
||||
if sqlQuery(::nSocket, cCreateQuery) == 0
|
||||
return .T.
|
||||
|
||||
endif
|
||||
|
||||
return .F.
|
||||
|
||||
|
||||
METHOD DeleteIndex(cName, cTable) CLASS TMySQLServer
|
||||
|
||||
local cDropQuery := "DROP INDEX " + cName + " FROM " + cTable
|
||||
|
||||
if sqlQuery(::nSocket, cDropQuery) == 0
|
||||
return .T.
|
||||
endif
|
||||
|
||||
return .F.
|
||||
|
||||
|
||||
METHOD DeleteTable(cTable) CLASS TMySQLServer
|
||||
|
||||
local cDropQuery := "DROP TABLE " + cTable
|
||||
|
||||
if sqlQuery(::nSocket, cDropQuery) == 0
|
||||
return .T.
|
||||
|
||||
endif
|
||||
|
||||
return .F.
|
||||
|
||||
|
||||
METHOD Query(cQuery) CLASS TMySQLServer
|
||||
|
||||
local oQuery, cTableName, i, cUpperQuery, nNumTables, cToken
|
||||
|
||||
cUpperQuery := Upper(AllTrim(cQuery))
|
||||
i := 1
|
||||
nNumTables := 0
|
||||
|
||||
while __StrToken(cUpperQuery, i++, " ") <> "FROM"
|
||||
enddo
|
||||
while (cToken := __StrToken(cUpperQuery, i++, " ")) <> "WHERE" .AND. cToken <> "LIMIT" .AND. !Empty(cToken)
|
||||
cTableName := __StrToken(cQuery, i - 1, " ")
|
||||
nNumTables++
|
||||
enddo
|
||||
|
||||
if nNumTables == 1
|
||||
oQuery := TMySQLTable():New(::nSocket, cQuery, cTableName)
|
||||
else
|
||||
oQuery := TMySQLQuery():New(::nSocket, cQuery)
|
||||
endif
|
||||
|
||||
if oQuery:nNumRows < 0
|
||||
::lError := .T.
|
||||
endif
|
||||
|
||||
return oQuery
|
||||
|
||||
|
||||
METHOD Error() CLASS TMySQLServer
|
||||
|
||||
::lError := .F.
|
||||
|
||||
return sqlGetErr(::nSocket)
|
||||
|
||||
|
||||
METHOD ListDBs() CLASS TMySQLServer
|
||||
|
||||
local aList
|
||||
|
||||
aList := sqlListDB(::nSocket)
|
||||
|
||||
return aList
|
||||
|
||||
|
||||
METHOD ListTables() CLASS TMySQLServer
|
||||
|
||||
local aList
|
||||
|
||||
aList := sqlListTbl(::nSocket)
|
||||
|
||||
return aList
|
||||
|
||||
|
||||
/* TOFIX: Conversion creates a .dbf with fields of wrong dimension (often) */
|
||||
METHOD TableStruct(cTable) CLASS TMySQLServer
|
||||
|
||||
local nRes, aField, aStruct, aSField, i
|
||||
|
||||
|
||||
aStruct := {}
|
||||
|
||||
/* TODO: rewrite for MySQL
|
||||
nRes := sqlListF(::nSocket, cTable)
|
||||
|
||||
if nRes > 0
|
||||
for i := 1 to sqlNumFi(nRes)
|
||||
|
||||
aField := sqlFetchF(nRes)
|
||||
aSField := Array(DBS_DEC)
|
||||
|
||||
// don't count indexes as real fields
|
||||
if aField[MSQL_FS_TYPE] <= MSQL_LAST_REAL_TYPE
|
||||
|
||||
aSField[DBS_NAME] := Left(aField[MSQL_FS_NAME], 10)
|
||||
aSField[DBS_DEC] := 0
|
||||
|
||||
do case
|
||||
case aField[MSQL_FS_TYPE] == MSQL_INT_TYPE
|
||||
aSField[DBS_TYPE] := "N"
|
||||
aSField[DBS_LEN] := 11
|
||||
|
||||
case aField[MSQL_FS_TYPE] == MSQL_UINT_TYPE
|
||||
aSField[DBS_TYPE] := "L"
|
||||
aSField[DBS_LEN] := 1
|
||||
|
||||
case aField[MSQL_FS_TYPE] == MSQL_CHAR_TYPE
|
||||
aSField[DBS_TYPE] := "C"
|
||||
aSField[DBS_LEN] := aField[MSQL_FS_LENGTH]
|
||||
|
||||
case aField[MSQL_FS_TYPE] == MSQL_DATE_TYPE
|
||||
aSField[DBS_TYPE] := "D"
|
||||
aSField[DBS_LEN] := aField[MSQL_FS_LENGTH]
|
||||
|
||||
case aField[MSQL_FS_TYPE] == MSQL_REAL_TYPE
|
||||
aSField[DBS_TYPE] := "N"
|
||||
aSField[DBS_LEN] := 12
|
||||
aSFIeld[DBS_DEC] := 8
|
||||
|
||||
otherwise
|
||||
|
||||
endcase
|
||||
|
||||
AAdd(aStruct, aSField)
|
||||
endif
|
||||
next
|
||||
|
||||
sqlFreeR(nRes)
|
||||
|
||||
endif*/
|
||||
|
||||
return aStruct
|
||||
Reference in New Issue
Block a user