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 DBAPIConn
*dbapi2open(const char *provider
, const char *database
) {
160 for(i
=0;i
<MAX_PROVIDERS
;i
++) {
161 if(providerobjs
[i
] && !strcmp(provider
, providerobjs
[i
]->__providerdata
->name
)) {
167 Error("dbapi2", ERR_WARNING
, "Couldn't find forced database provider %s", provider
);
171 for(i
=0;i
<MAX_PROVIDERS
;i
++) {
172 if(providerobjs
[i
]) {
179 Error("dbapi2", ERR_WARNING
, "No database providers found.");
184 p
= providerobjs
[found
];
186 db
= calloc(1, sizeof(DBAPIConn
));
191 db
->query
= dbsafequery
;
192 db
->createtable
= dbsafecreatetable
;
193 db
->squery
= dbsafesimplequery
;
194 db
->loadtable
= dbloadtable
;
195 db
->escapestring
= p
->escapestring
;
196 db
->tablename
= p
->tablename
;
197 db
->unsafequery
= dbunsafequery
;
198 db
->unsafesquery
= dbunsafesimplequery
;
199 db
->unsafecreatetable
= dbunsafecreatetable
;
201 db
->__query
= p
->query
;
202 db
->__close
= p
->close
;
203 db
->__quotestring
= p
->quotestring
;
204 db
->__createtable
= p
->createtable
;
205 db
->__loadtable
= p
->loadtable
;
207 strlcpy(db
->name
, database
, DBNAME_LEN
);
209 db
->handle
= p
->new(db
);
212 Error("dbapi2", ERR_WARNING
, "Unable to initialise database %s, provider: %s", database
, p
->__providerdata
->name
);
216 Error("dbapi2", ERR_INFO
, "Database %s opened with provider %s.", database
, p
->__providerdata
->name
);
221 static void dbvsnprintf(const DBAPIConn
*db
, char *buf
, size_t size
, const char *format
, const char *types
, va_list ap
) {
224 static char convbuf
[VSNPF_MAXARGS
][VSNPF_MAXARGLEN
+10];
243 for(i
=0;i
<VSNPF_MAXARGS
;i
++)
244 convbuf
[i
][0] = '\0';
247 for(;*types
;types
++) {
248 char *cb
= convbuf
[argcount
];
250 if(argcount
++ >= VSNPF_MAXARGS
) {
252 Error("dbapi2", ERR_STOP
, "Maximum arguments reached in dbvsnprintf, format: '%s', database: %s", format
, db
->name
);
258 s
= va_arg(ap
, char *);
262 /* falling through */
265 s
= va_arg(ap
, char *);
266 l
= va_arg(ap
, size_t);
269 /* now... this is a guess, but we should catch it most of the time */
270 if((l
> (VSNPF_MAXARGLEN
/ 2)) || !db
->__quotestring(db
, cb
, sizeof(convbuf
[0]), s
, l
)) {
271 Error("dbapi2", ERR_STOP
, "Long string truncated, format: '%s', database: %s", format
, db
->name
);
277 s
= va_arg(ap
, char *);
279 strlcpy(cb
, s
, sizeof(convbuf
[0]));
282 s
= va_arg(ap
, char *);
284 strlcpy(cb
, db
->tablename(db
, s
), sizeof(convbuf
[0]));
288 snprintf(cb
, VSNPF_MAXARGLEN
, "%d", d
);
291 u
= va_arg(ap
, unsigned int);
292 snprintf(cb
, VSNPF_MAXARGLEN
, "%u", u
);
295 t
= va_arg(ap
, time_t);
296 snprintf(cb
, VSNPF_MAXARGLEN
, "%jd", (intmax_t)t
);
299 _l
= va_arg(ap
, long);
300 snprintf(cb
, VSNPF_MAXARGLEN
, "%ld", _l
);
303 ul
= va_arg(ap
, unsigned long);
304 snprintf(cb
, VSNPF_MAXARGLEN
, "%lu", ul
);
307 g
= va_arg(ap
, double);
308 snprintf(cb
, VSNPF_MAXARGLEN
, "%.1f", g
);
312 Error("dbapi2", ERR_STOP
, "Bad format specifier '%c' supplied in dbvsnprintf, format: '%s', database: %s", *types
, format
, db
->name
);
317 sbinit(&b
, buf
, size
);
319 for(arg
=0,p
=format
;*p
;p
++) {
321 if(!sbaddchar(&b
, *p
))
327 Error("dbapi2", ERR_STOP
, "Gone over number of arguments in dbvsnprintf, format: '%s', database: %s", format
, db
->name
);
329 if(!sbaddstr(&b
, convbuf
[arg
]))
330 Error("dbapi2", ERR_STOP
, "Possible truncation in dbvsnprintf, format: '%s', database: %s", format
, db
->name
);