forked from r-dbi/RMySQL
/
RS-DBI.h
267 lines (238 loc) · 10.5 KB
/
RS-DBI.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#ifndef _RS_DBI_H
#define _RS_DBI_H 1
/*
* $Id$
*
* Copyright (C) 1999-2002 The Omega Project for Statistical Computing.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* The following include file defines a number of C macros that hide
* differences between R and S (e.g., the macro for type "Sint" expand
* to "long" in the case of S and to int in the case of R, etc.)
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "S4R.h"
/* WIN32 uses int _getpid() */
#if defined WIN32
#include <process.h>
/* #define getpid _getpid */
#include <ctype.h>
/* #define pid_t int */
#else
#include <unistd.h>
#endif
/* We now define 4 important data structures:
* RS_DBI_manager, RS_DBI_connection, RS_DBI_resultSet, and
* RS_DBI_fields, corresponding to dbManager, dbConnection,
* dbResultSet, and list of field descriptions.
*/
/* In R/S a dbObject is a foreign reference consisting of a vector
* of 1, 2 or 3 integers. In the C implementation we use these
* R/S vectors as handles (we could have used pointers).
*/
typedef enum enum_dbi_exception {
RS_DBI_MESSAGE,
RS_DBI_WARNING,
RS_DBI_ERROR,
RS_DBI_TERMINATE
} DBI_EXCEPTION;
/* dbObject handles are simple S/R integer vectors of 1, 2, or 3 integers
* the *_ID macros extract the appropriate scalar.
*/
#define Mgr_Handle s_object
#define Con_Handle s_object
#define Res_Handle s_object
#define Db_Handle s_object /* refers to any one of the above */
/* The integer value for the following enum's needs to equal
* GET_LENGTH(handle) for the various handles.
*/
typedef enum enum_handle_type {
MGR_HANDLE_TYPE = 1, /* dbManager handle */
CON_HANDLE_TYPE = 2, /* dbConnection handle */
RES_HANDLE_TYPE = 3 /* dbResult handle */
} HANDLE_TYPE;
#define MGR_ID(handle) INT_EL((handle),0) /* the actual scalar mgr id */
#define CON_ID(handle) INT_EL((handle),1)
#define RES_ID(handle) INT_EL((handle),2)
/* First, the following fully describes the field output by a select
* (or select-like) statement, and the mappings from the internal
* database types to S classes. This structure contains the info we need
* to build the R/S list (or data.frame) that will receive the SQL
* output. It still needs some work to handle arbitrty BLOB's (namely
* methods to map BLOBs into user-defined S objects).
* Each element is an array of num_fields, this flds->Sclass[3] stores
* the S class for the 4th output fields.
*/
typedef struct st_sdbi_fields {
int num_fields;
char **name; /* DBMS field names */
Sint *type; /* DBMS internal types */
Sint *length; /* DBMS lengths in bytes */
Sint *precision; /* DBMS num of digits for numeric types */
Sint *scale; /* DBMS num of decimals for numeric types */
Sint *nullOk; /* DBMS indicator for DBMS' NULL type */
Sint *isVarLength; /* DBMS variable-length char type */
Stype *Sclass; /* R/S class (type) -- may be overriden */
/* TODO: Need a table of fun pointers to converters */
} RS_DBI_fields;
typedef struct st_sdbi_exception {
DBI_EXCEPTION exceptionType; /* one of RS_DBI_WARN, RS_RBI_ERROR, etc */
int errorNum; /* SQL error number (possibly driver-dependent*/
char *errorMsg; /* SQL error message */
} RS_DBI_exception;
/* The RS-DBI resultSet consists of a pointer to the actual DBMS
* resultSet (e.g., MySQL, Oracle) possibly NULL, plus the fields
* defined by the RS-DBI implementation.
*/
typedef struct st_sdbi_resultset {
void *drvResultSet; /* the actual (driver's) cursor/result set */
void *drvData; /* a pointer to driver-specific data */
Sint managerId; /* the 3 *Id's are used for */
Sint connectionId; /* validating stuff coming from S */
Sint resultSetId;
Sint isSelect; /* boolean for testing SELECTs */
char *statement; /* SQL statement */
Sint rowsAffected; /* used by non-SELECT statements */
Sint rowCount; /* rows fetched so far (SELECT-types)*/
Sint completed; /* have we fetched all rows? */
RS_DBI_fields *fields;
} RS_DBI_resultSet;
/* A dbConnection consists of a pointer to the actual implementation
* (MySQL, Oracle, etc.) connection plus a resultSet and other
* goodies used by the RS-DBI implementation.
* The connection parameters (user, password, database name, etc.) are
* defined by the actual driver -- we just set aside a void pointer.
*/
typedef struct st_sdbi_connection {
void *conParams; /* pointer to connection params (host, user, etc)*/
void *drvConnection; /* pointer to the actual DBMS connection struct*/
void *drvData; /* to be used at will by individual drivers */
RS_DBI_resultSet **resultSets; /* vector to result set ptrs */
Sint *resultSetIds;
Sint length; /* max num of concurrent resultSets */
Sint num_res; /* num of open resultSets */
Sint counter; /* total number of queries */
Sint managerId;
Sint connectionId;
RS_DBI_exception *exception;
} RS_DBI_connection;
/* dbManager */
typedef struct st_sdbi_manager {
char *drvName; /* what driver are we implementing?*/
void *drvData; /* to be used by the drv implementation*/
RS_DBI_connection **connections; /* list of dbConnections */
Sint *connectionIds; /* array of connectionIds */
Sint length; /* max num of concurrent connections */
Sint num_con; /* num of opened connections */
Sint counter; /* num of connections handled so far*/
Sint fetch_default_rec; /* default num of records per fetch */
Sint managerId; /* typically, process id */
RS_DBI_exception *exception;
} RS_DBI_manager;
/* All RS_DBI functions and their signatures */
/* Note: the following alloc functions allocate the space for the
* corresponding manager, connection, resultSet; they all
* return handles. All DBI functions (free/get/etc) use the handle
* to work with the various dbObjects.
*/
Mgr_Handle *RS_DBI_allocManager(const char *drvName, Sint max_con,
Sint fetch_default_rec,
Sint force_realloc);
void RS_DBI_freeManager(Mgr_Handle *mgrHandle);
RS_DBI_manager *RS_DBI_getManager(Db_Handle *handle);
Mgr_Handle *RS_DBI_asMgrHandle(Sint pid);
s_object *RS_DBI_managerInfo(Mgr_Handle *mgrHandle);
/* dbConnection */
Con_Handle *RS_DBI_allocConnection(Mgr_Handle *mgrHandle,
Sint max_res);
void RS_DBI_freeConnection(Con_Handle *conHandle);
RS_DBI_connection *RS_DBI_getConnection(Db_Handle *handle);
Con_Handle *RS_DBI_asConHandle(Sint mgrId, Sint conId);
s_object *RS_DBI_connectionInfo(Con_Handle *con_Handle);
/* dbResultSet */
Res_Handle *RS_DBI_allocResultSet(Con_Handle *conHandle);
void RS_DBI_freeResultSet(Res_Handle *rsHandle);
RS_DBI_resultSet *RS_DBI_getResultSet(Res_Handle *rsHandle);
Res_Handle *RS_DBI_asResHandle(Sint pid, Sint conId, Sint resId);
s_object *RS_DBI_resultSetInfo(Res_Handle *rsHandle);
/* utility funs */
s_object *RS_DBI_validHandle(Db_Handle *handle); /* callable from S/R */
int is_validHandle(Db_Handle *handle, HANDLE_TYPE handleType);
/* a simple object database (mapping table) -- it uses simple linear
* search (we don't expect to have more than a handful of simultaneous
* connections and/or resultSets. If this is not the case, we could
* use a hash table, but I doubt it's worth it (famous last words!).
* These are used for storing/retrieving object ids, such as
* connection ids from the manager object, and resultSet ids from a
* connection object; of course, this is transparent to the various
* drivers -- they should deal with handles exclusively.
*/
Sint RS_DBI_newEntry(Sint *table, Sint length);
Sint RS_DBI_lookup(Sint *table, Sint length, Sint obj_id);
Sint RS_DBI_listEntries(Sint *table, Sint length, Sint *entries);
void RS_DBI_freeEntry(Sint *table, Sint indx);
/* description of the fields in a result set */
RS_DBI_fields *RS_DBI_allocFields(int num_fields);
s_object *RS_DBI_getFieldDescriptions(RS_DBI_fields *flds);
void RS_DBI_freeFields(RS_DBI_fields *flds);
/* we (re)allocate the actual output list in here (with the help of
* RS_DBI_fields). This should be some kind of R/S "relation"
* table, not a dataframe nor a list.
*/
void RS_DBI_allocOutput(s_object *output,
RS_DBI_fields *flds,
Sint num_rec,
Sint expand);
void RS_DBI_makeDataFrame(s_object *data);
/* TODO: We need to elevate RS_DBI_errorMessage to either
* dbManager and/or dbConnection methods. I still need to
* go back and re-code the error-handling throughout, darn!
*/
void RS_DBI_errorMessage(char *msg, DBI_EXCEPTION exceptionType);
void RS_DBI_setException(Db_Handle *handle,
DBI_EXCEPTION exceptionType,
int errorNum,
const char *errorMsg);
/* utility funs (copy strings, convert from R/S types to string, etc.*/
char *RS_DBI_copyString(const char *str);
char *RS_DBI_nCopyString(const char *str, size_t len, int del_blanks);
/* We now define a generic data type name-Id mapping struct
* and initialize the RS_dataTypeTable[]. Each driver could
* define similar table for generating friendly type names
*/
struct data_types {
char *typeName;
Sint typeId;
};
/* return the primitive type name for a primitive type id */
char *RS_DBI_getTypeName(Sint typeCode, const struct data_types table[]);
/* same, but callable from S/R and vectorized */
s_object *RS_DBI_SclassNames(s_object *types);
s_object *RS_DBI_createNamedList(char **names,
Stype *types,
Sint *lengths,
Sint n);
s_object *RS_DBI_copyFields(RS_DBI_fields *flds);
void RS_na_set(void *ptr, Stype type);
int RS_is_na(void *ptr, Stype type);
extern const struct data_types RS_dataTypeTable[];
/* int isalpha(int c); */
#ifdef __cplusplus
}
#endif
#endif /* _RS_DBI_H */