1 #define MAX_PROVIDERS 10
2 #define PROVIDER_NAME_LEN 100
3 #define QUERYBUFLEN 8192*2
5 #define VSNPF_MAXARGS 20
6 #define VSNPF_MAXARGLEN 2048
14 #include "../core/error.h"
15 #include "../lib/strlfunc.h"
16 #include "../lib/stringbuf.h"
17 #include "../lib/version.h"
22 struct DBAPIProviderData
{
23 char name
[PROVIDER_NAME_LEN
+1];
26 static DBAPIProvider
*providerobjs
[MAX_PROVIDERS
];
27 static struct DBAPIProviderData providerdata
[MAX_PROVIDERS
];
29 static void dbvsnprintf(const DBAPIConn
*db
, char *buf
, size_t size
, const char *format
, const char *types
, va_list ap
);
32 memset(providerobjs
, 0, sizeof(providerobjs
));
36 /* everything should be unregistered already */
39 int registerdbprovider(const char *name
, DBAPIProvider
*provider
) {
42 for(i
=0;i
<MAX_PROVIDERS
;i
++) {
46 providerobjs
[i
] = provider
;
47 providerobjs
[i
]->__providerdata
= &providerdata
[i
];
49 strlcpy(providerobjs
[i
]->__providerdata
->name
, name
, PROVIDER_NAME_LEN
);
51 Error("dbapi2", ERR_INFO
, "Database API registered: %s", name
);
56 Error("dbapi2", ERR_WARNING
, "No remaining space for new database provider: %s", name
);
60 void deregisterdbprovider(int handle
) {
64 providerobjs
[handle
] = NULL
;
67 static void dbclose(DBAPIConn
*db
) {
69 free((DBAPIConn
*)db
);
72 static void dbunsafequery(const DBAPIConn
*db
, DBAPIQueryCallback cb
, DBAPIUserData data
, const char *format
, ...) {
74 char buf
[QUERYBUFLEN
];
78 ret
= vsnprintf(buf
, sizeof(buf
), format
, ap
);
81 if(ret
>= sizeof(buf
))
82 Error("dbapi2", ERR_STOP
, "Query truncated in dbunsafequery, format: '%s', database: %s", format
, db
->name
);
84 db
->__query(db
, cb
, data
, buf
);
87 static void dbunsafecreatetable(const DBAPIConn
*db
, DBAPIQueryCallback cb
, DBAPIUserData data
, const char *format
, ...) {
89 char buf
[QUERYBUFLEN
];
93 ret
= vsnprintf(buf
, sizeof(buf
), format
, ap
);
96 if(ret
>= sizeof(buf
))
97 Error("dbapi2", ERR_STOP
, "Query truncated in dbunsafecreatetable, format: '%s', database: %s", format
, db
->name
);
99 db
->__createtable(db
, cb
, data
, buf
);
102 static void dbunsafesimplequery(const DBAPIConn
*db
, const char *format
, ...) {
104 char buf
[QUERYBUFLEN
];
107 va_start(ap
, format
);
108 ret
= vsnprintf(buf
, sizeof(buf
), format
, ap
);
111 if(ret
>= sizeof(buf
))
112 Error("dbapi2", ERR_STOP
, "Query truncated in dbunsafequery, format: '%s', database: %s", format
, db
->name
);
114 db
->__query(db
, NULL
, NULL
, buf
);
117 static void dbsafequery(const DBAPIConn
*db
, DBAPIQueryCallback cb
, DBAPIUserData data
, const char *format
, const char *types
, ...) {
119 char buf
[QUERYBUFLEN
];
122 dbvsnprintf(db
, buf
, sizeof(buf
), format
, types
, ap
);
125 db
->__query(db
, cb
, data
, buf
);
128 static void dbsafecreatetable(const DBAPIConn
*db
, DBAPIQueryCallback cb
, DBAPIUserData data
, const char *format
, const char *types
, ...) {
130 char buf
[QUERYBUFLEN
];
133 dbvsnprintf(db
, buf
, sizeof(buf
), format
, types
, ap
);
136 db
->__createtable(db
, cb
, data
, buf
);
139 static void dbsafesimplequery(const DBAPIConn
*db
, const char *format
, const char *types
, ...) {
141 char buf
[QUERYBUFLEN
];
144 dbvsnprintf(db
, buf
, sizeof(buf
), format
, types
, ap
);
147 db
->__query(db
, NULL
, NULL
, buf
);
150 static void dbloadtable(const DBAPIConn
*db
, DBAPIQueryCallback init
, DBAPIQueryCallback data
, DBAPIQueryCallback fini
, DBAPIUserData tag
, const char *tablename
) {
151 db
->__loadtable(db
, init
, data
, fini
, tag
, db
->tablename(db
, tablename
));
154 static void dbcall(const DBAPIConn
*db
, DBAPIQueryCallback cb
, DBAPIUserData data
, const char *function
, const char *format
, const char *types
, ...) {
156 char buf
[QUERYBUFLEN
];
159 dbvsnprintf(db
, buf
, sizeof(buf
), format
, types
, ap
);
162 db
->__call(db
, cb
, data
, function
, buf
);
165 static void dbsimplecall(const DBAPIConn
*db
, const char *function
, const char *format
, const char *types
, ...) {
167 char buf
[QUERYBUFLEN
];
170 dbvsnprintf(db
, buf
, sizeof(buf
), format
, types
, ap
);
173 db
->__call(db
, NULL
, NULL
, function
, buf
);
176 DBAPIConn
*dbapi2open(const char *provider
, const char *database
) {
182 for(i
=0;i
<MAX_PROVIDERS
;i
++) {
183 if(providerobjs
[i
] && !strcmp(provider
, providerobjs
[i
]->__providerdata
->name
)) {
189 Error("dbapi2", ERR_WARNING
, "Couldn't find forced database provider %s", provider
);
193 for(i
=0;i
<MAX_PROVIDERS
;i
++) {
194 if(providerobjs
[i
]) {
201 Error("dbapi2", ERR_WARNING
, "No database providers found.");
206 p
= providerobjs
[found
];
208 db
= calloc(1, sizeof(DBAPIConn
));
213 db
->query
= dbsafequery
;
214 db
->createtable
= dbsafecreatetable
;
215 db
->squery
= dbsafesimplequery
;
216 db
->loadtable
= dbloadtable
;
217 db
->escapestring
= p
->escapestring
;
218 db
->tablename
= p
->tablename
;
219 db
->unsafequery
= dbunsafequery
;
220 db
->unsafesquery
= dbunsafesimplequery
;
221 db
->unsafecreatetable
= dbunsafecreatetable
;
223 db
->scall
= dbsimplecall
;
225 db
->__query
= p
->query
;
226 db
->__close
= p
->close
;
227 db
->__quotestring
= p
->quotestring
;
228 db
->__createtable
= p
->createtable
;
229 db
->__loadtable
= p
->loadtable
;
230 db
->__call
= p
->call
;
232 strlcpy(db
->name
, database
, DBNAME_LEN
);
234 db
->handle
= p
->new(db
);
237 Error("dbapi2", ERR_WARNING
, "Unable to initialise database %s, provider: %s", database
, p
->__providerdata
->name
);
241 Error("dbapi2", ERR_INFO
, "Database %s opened with provider %s.", database
, p
->__providerdata
->name
);
246 static void dbvsnprintf(const DBAPIConn
*db
, char *buf
, size_t size
, const char *format
, const char *types
, va_list ap
) {
249 static char convbuf
[VSNPF_MAXARGS
][VSNPF_MAXARGLEN
+10];
268 for(i
=0;i
<VSNPF_MAXARGS
;i
++)
269 convbuf
[i
][0] = '\0';
272 for(;*types
;types
++) {
273 char *cb
= convbuf
[argcount
];
275 if(argcount
++ >= VSNPF_MAXARGS
) {
277 Error("dbapi2", ERR_STOP
, "Maximum arguments reached in dbvsnprintf, format: '%s', database: %s", format
, db
->name
);
283 s
= va_arg(ap
, char *);
288 /* falling through */
291 s
= va_arg(ap
, char *);
292 l
= va_arg(ap
, size_t);
296 strlcpy(cb
, "NULL", sizeof(convbuf
[0]));
297 } else if((l
> (VSNPF_MAXARGLEN
/ 2)) || !db
->__quotestring(db
, cb
, sizeof(convbuf
[0]), s
, l
)) {
298 /* now... this is a guess, but we should catch it most of the time */
299 Error("dbapi2", ERR_STOP
, "Long string truncated, format: '%s', database: %s", format
, db
->name
);
305 s
= va_arg(ap
, char *);
307 strlcpy(cb
, s
, sizeof(convbuf
[0]));
310 s
= va_arg(ap
, char *);
312 strlcpy(cb
, db
->tablename(db
, s
), sizeof(convbuf
[0]));
316 snprintf(cb
, VSNPF_MAXARGLEN
, "%d", d
);
319 u
= va_arg(ap
, unsigned int);
320 snprintf(cb
, VSNPF_MAXARGLEN
, "%u", u
);
323 t
= va_arg(ap
, time_t);
324 snprintf(cb
, VSNPF_MAXARGLEN
, "%jd", (intmax_t)t
);
327 _l
= va_arg(ap
, long);
328 snprintf(cb
, VSNPF_MAXARGLEN
, "%ld", _l
);
331 ul
= va_arg(ap
, unsigned long);
332 snprintf(cb
, VSNPF_MAXARGLEN
, "%lu", ul
);
335 g
= va_arg(ap
, double);
336 snprintf(cb
, VSNPF_MAXARGLEN
, "%.1f", g
);
340 Error("dbapi2", ERR_STOP
, "Bad format specifier '%c' supplied in dbvsnprintf, format: '%s', database: %s", *types
, format
, db
->name
);
345 sbinit(&b
, buf
, size
);
347 for(arg
=0,p
=format
;*p
;p
++) {
349 if(!sbaddchar(&b
, *p
))
355 Error("dbapi2", ERR_STOP
, "Gone over number of arguments in dbvsnprintf, format: '%s', database: %s", format
, db
->name
);
357 if(!sbaddstr(&b
, convbuf
[arg
]))
358 Error("dbapi2", ERR_STOP
, "Possible truncation in dbvsnprintf, format: '%s', database: %s", format
, db
->name
);