mSQL Compatibility Library (fwd) - Mailing list pgsql-interfaces
From | Aldrin L. |
---|---|
Subject | mSQL Compatibility Library (fwd) |
Date | |
Msg-id | Pine.LNX.3.96.980515023207.2605F-200000@zero Whole thread Raw |
Responses |
Re: [INTERFACES] mSQL Compatibility Library (fwd)
|
List | pgsql-interfaces |
Hello! :) (Sorry for my english. But if i wrote in portuguese, you wouldn't understand nothing. :]) I found it's the right place to post this. I'm a newcomer in these lists. I hope i did it right. :] <BOREDOM> When i started using SQL, i started with mSQL. I developed a lot of useful apps for me and my job with C, mainly because i loved it's elegant, simple api. But for a large project i'm doing in these days, i thought is was not enough, because it felt a lot of features i started to need, like security and subselects. (and it's not free :)) So after looking at the options, choose to start again with postgres. It offered everything that i needed, and the documentation is really good (remember me to thank the one who wrote'em). But for my little apps, i needed to start porting them to libpq. After looking at pq's syntax, i found it was better to write a bridge between the mSQL api and libpq. I found that rewriting the libmsql.a routines that calls libpq would made things much easier. I guess the results are quite good right now. </BOREDOM> Ok. Lets' summarize it: mpgsql.c is the bridge. Acting as a wrapper, it's really good, since i could run mSQL. But it's not accurate. Some highlights: CONS: * It's not well documented (this post is it's first documentation attempt, in fact); * It doesn't handle field types correctly. I plan to fix it, if people start doing feedbacks; * It's limited to 10 simultaneous connections. I plan to enhance this, i'm just figuring out; * I'd like to make it reentrant/thread safe, although i don't think this could be done without changing the API structure; * Error Management should be better. This is my first priority now; * Some calls are just empty implementations. PROS: * the mSQL Monitor runs Okay. :] * It's really cool. :) * Make mSQL-made applications compatible with postgresql just by changing link options. * Uses postgreSQL. :] * the mSQL API it's far easier to use and understand than libpq. Consider this example: #include "msql.h" void main(int argc, char **argv, char **envp) { int sid; sid = msqlConnect(NULL); /* Connects via unix socket */ if (sid >= 0) { m_result *rlt; m_row *row; msqlSelectDB(sid, "hosts"); if (msqlQuery(sid, "select host_id from hosts")) { rlt = msqlStoreResult(); while (row = (m_row*)msqlFetchRow(rlt)) printf("hostid: %s\n", row[0]); msqlFreeResult(rlt); } msqlClose(sid); } } I enclose mpgsql.c inside. I'd like to maintain it, and (maybe, am i dreaming) make it as part of the pgsql distribution. I guess it doesn't depends on me, but mainly on it's acceptance by its users. Hm... i forgot: you'll need a msql.h copy, since it's copyrighted by Hughes Technologies Pty Ltd. If you haven't it yes, fetch one from www.hughes.com.au. I would like to catch users ideas. My next goal is to add better error handling, and to make it better documented, and try to let relshow run through it. :) done. Aldrin Leal <aldrin@americasnet.com> #include <time.h> #include <string.h> #include <stdlib.h> #include "msql.h" #include "libpq-fe.h" #define HNDMAX 10 PGconn *PGh[HNDMAX] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; #define E_NOHANDLERS 0 char *msqlErrors[] = { "Out of database handlers." }; char msqlErrMsg[BUFSIZ], *tfrom = "dunno"; PGresult *queryres = NULL; int msqlConnect (char *host) { int count; for (count = 0; count < HNDMAX; count++) if (PGh[count] == NULL) break; if (count == HNDMAX) { strncpy(msqlErrMsg, msqlErrors[E_NOHANDLERS], BUFSIZ); return -1; } PGh[count] = malloc(sizeof (PGconn)); PGh[count]->pghost = host ? strdup(host) : NULL; return count; } int msqlSelectDB(int handle, char *dbname) { char *options = calloc(1, BUFSIZ); char *e = getenv("PG_OPTIONS"); if (e == NULL) e = ""; if (PGh[handle]->pghost) { strcat(options, "host="); strncat(options, PGh[handle]->pghost, BUFSIZ); strncat(options, " ", BUFSIZ); free(PGh[handle]->pghost); PGh[handle]->pghost = NULL; } strncat(options, "dbname=", BUFSIZ); strncat(options, dbname, BUFSIZ); strncat(options, " ", BUFSIZ); strncat(options, e, BUFSIZ); free(PGh[handle]); PGh[handle] = PQconnectdb(options); free(options); strncpy(msqlErrMsg, PQerrorMessage(PGh[handle]), BUFSIZ); return (PQstatus(PGh[handle]) == CONNECTION_BAD ? -1 : 0); } int msqlQuery(int handle, char *query) { char *tq = strdup(query); char *p = tq; PGresult *res; PGconn *conn = PGh[handle]; ExecStatusType rcode; res = PQexec(conn, p); rcode = PQresultStatus(res); if (rcode == PGRES_TUPLES_OK) { queryres = res; return PQntuples(res); } else if (rcode == PGRES_FATAL_ERROR || rcode == PGRES_NONFATAL_ERROR) { PQclear(res); queryres = NULL; return -1; } else { PQclear(res); queryres = NULL; return 0; } } int msqlCreateDB (int a, char*b) { char tbuf[BUFSIZ]; sprintf(tbuf, "create database %s", b); return msqlQuery(a, tbuf) >= 0 ? 0 : -1; } int msqlDropDB (int a, char* b) { char tbuf[BUFSIZ]; sprintf(tbuf, "drop database %s", b); return msqlQuery(a, tbuf) >= 0 ? 0 : -1; } int msqlShutdown(int a) { } int msqlGetProtoInfo(void) { } int msqlReloadAcls(int a) { } char *msqlGetServerInfo(void) { } char *msqlGetHostInfo(void) { } char *msqlUnixTimeToDate(time_t date) { } char *msqlUnixTimeToTime(time_t time) { } void msqlClose(int a) { PQfinish(PGh[a]); PGh[a] = NULL; if (queryres) { free(queryres); queryres = NULL; } } void msqlDataSeek(m_result *result, int count) { int c; result->cursor = result->queryData; for (c = 1; c < count; c++) if (result->cursor->next) result->cursor = result->cursor->next; } void msqlFieldSeek(m_result *result, int count) { int c; result->fieldCursor = result->fieldData; for (c = 1; c < count; c++) if (result->fieldCursor->next) result->fieldCursor = result->fieldCursor->next; } void msqlFreeResult(m_result *result) { if (result) { /* Clears fields */ free(result->fieldData); result->cursor = result->queryData; while (result->cursor) { int c; m_row m = result->cursor->data; for (c = 0; m[c]; c++) free(m[c]); result->cursor = result->cursor->next; } free(result->queryData); free(result); } } m_row msqlFetchRow(m_result *row) { m_data *r = row->cursor; if (r) { row->cursor = row->cursor->next; return (m_row)r->data; } return (m_row)NULL; } m_seq *msqlGetSequenceInfo(int a, char *b) { } m_field *msqlFetchField (m_result *mr) { m_field *m = (m_field*)mr->fieldCursor; if (m) { mr->fieldCursor = mr->fieldCursor->next; return m; } return NULL; } m_result *msqlListDBs(int a) { m_result *m; if (msqlQuery(a, "select datname from pg_database") > 0) { m = msqlStoreResult(); return m; } else return NULL; } m_result *msqlListTables(int a) { m_result *m; char tbuf[BUFSIZ]; sprintf(tbuf, "select relname from pg_class where relkind='r' and relowner=%d", getuid()); if (msqlQuery(a, tbuf) > 0) { m = msqlStoreResult(); return m; } else return NULL; } m_result *msqlListFields(int a, char *b) { } m_result *msqlListIndex(int a, char *b, char *c) { m_result *m; char tbuf[BUFSIZ]; sprintf(tbuf, "select relname from pg_class where relkind='i' and relowner=%d", getuid()); if (msqlQuery(a, tbuf) > 0) { m = msqlStoreResult(); return m; } else return NULL; } m_result *msqlStoreResult(void) { if (queryres) { m_result *mr = malloc(sizeof(m_result)); m_fdata *mf; m_data *md; int count; mr->queryData = mr->cursor = NULL; mr->numRows = PQntuples(queryres); mr->numFields = PQnfields(queryres); mf = calloc(PQnfields(queryres), sizeof(m_fdata)); for (count = 0; count < PQnfields(queryres); count++) { (m_fdata*)(mf+count)->field.name = strdup(PQfname(queryres, count)); (m_fdata*)(mf+count)->field.table = tfrom; (m_fdata*)(mf+count)->field.type = CHAR_TYPE; (m_fdata*)(mf+count)->field.length = PQfsize(queryres, count); (m_fdata*)(mf+count)->next = (m_fdata*)(mf+count+1); } (m_fdata*)(mf+count-1)->next = NULL; md = calloc(PQntuples(queryres), sizeof(m_data)); for (count = 0; count < PQntuples(queryres); count++) { m_row rows = calloc(PQnfields(queryres)*sizeof(m_row)+1, 1); int c; for (c = 0; c < PQnfields(queryres); c++) { rows[c] = strdup(PQgetvalue(queryres, count, c)); } (m_data*)(md+count)->data = rows; (m_data*)(md+count)->width = PQnfields(queryres); (m_data*)(md+count)->next = (m_data*)(md+count+1); } (m_data*)(md+count-1)->next = NULL; mr->queryData = mr->cursor = md; mr->fieldCursor = mr->fieldData = mf; return mr; } else return NULL; } time_t msqlDateToUnixTime(char *a) { } time_t msqlTimeToUnixTime(char *b) { } char *msql_tmpnam(void) { return tmpnam("/tmp/msql.XXXXXX"); } int msqlLoadConfigFile(char *a) { }
pgsql-interfaces by date: