Next version of JABA
[jabaws.git] / binaries / src / fasta34 / mysql_lib.c
1
2 /* mysql_lib.c copyright (c) 2000 William R. Pearson */
3
4 /* $Name: fa_34_26_5 $ - $Id: mysql_lib.c,v 1.21 2006/04/12 18:00:02 wrp Exp $ */
5
6 /* functions for opening, reading, seeking a mySQL database */
7
8 /*
9   For the moment, this interface assumes that the file to be searched will
10   be specified in a single, long, string with 4 parts:
11
12   (1) a database open string. This string has four fields, separated by
13       whitespace (' \t'):
14         hostname:port dbname user password
15
16    '--' dashes at the beginning of lines are ignored -
17    thus the first line could be:
18    -- hostname:port dbname user password
19
20   (2) a database query string that will return an unique ID (not
21       necessarily numberic, but it must be < 12 characters as libstr[12]
22       is used) and a sequence string
23
24   (2a) a series of mySQL commands that do not generate results
25        starting with 'DO', followed by a select() statement.
26
27   (3) a database select string that will return a description
28       given a unique ID
29
30   (4) a database select string that well return a sequence given a
31       unique ID
32
33    Lines (3) and (4) are not required for pv34comp* libraries, but
34    line (2) must generate a complete description as well as a sequence.
35
36
37    18-July-2001
38    Additional syntax has been added to support multiline SQL queries.
39
40    If the host line begins with '+', then the SQL is openned on the same
41    connection as the previous SQL file.
42
43    If the host line contains '-' just before the terminal ';', then
44    the file will not produce any output.
45
46    This string can contain "\n". ";" are used to separate the four
47    functions, which must be specified in the order shown above.
48    The last (fourth) query must terminate with a ';' */
49
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <ctype.h>
54
55 #include <mysql.h>
56 #define MYSQL_LIB 16
57
58 #include "defs.h"
59 #include "mm_file.h"
60
61 #define XTERNAL
62 #include "uascii.h"
63 #define EOSEQ 0
64 /* #include "upam.h" */
65
66 #ifdef SUPERFAMNUM
67 int sfnum[10], nsfnum;
68 #endif
69
70 int mysql_getlib(unsigned char *, int, char *, int, fseek_t *, int *, struct lmf_str *, long *);
71 void mysql_ranlib(char *, int, fseek_t, char *, struct lmf_str *m_fd);
72
73 #define MYSQL_BUF 4096
74
75 struct lmf_str *
76 mysql_openlib(char *sname, int ldnaseq, int *sascii) {
77   FILE *sql_file;
78   char *tmp_str, *ttmp_str;
79   int tmp_str_len;
80   char *bp, *bps, *bdp, *tp, tchar;
81   int i, qs_len, qqs_len;
82   char *sql_db, *sql_host, *sql_dbname, *sql_user, *sql_pass;
83   char *sql_do;
84   int sql_do_cnt;
85   int sql_port;
86   struct lmf_str *m_fptr;
87
88   /*  if (sql_reopen) return NULL; - should not be called for re-open */
89
90   tmp_str_len = MYSQL_BUF;
91   if ((tmp_str=(char *)calloc(tmp_str_len,sizeof(char)))==NULL) {
92     fprintf(stderr,"cannot allocate %d for mySQL buffer\n",tmp_str_len);
93     return NULL;
94   }
95
96   if (sname[0] == '%') {
97     strncpy(tmp_str,sname+1,tmp_str_len);
98     tmp_str[sizeof(tmp_str)-1]='\0';
99   }
100   else {
101     if ((sql_file=fopen(sname,"r"))==NULL) {
102       fprintf(stderr," cannot open mySQL file: %s\n",sname);
103       return NULL;
104     }
105
106     if ((qs_len=fread(tmp_str,sizeof(char),tmp_str_len-1,sql_file))<=0) {
107       fprintf(stderr," cannot read mySQL file: %s\n",sname);
108       return NULL;
109     }
110     else  {
111       tmp_str[qs_len]='\0';
112       qqs_len = qs_len;
113       while (qqs_len >= tmp_str_len-1) {
114         tmp_str_len += MYSQL_BUF;
115         if ((tmp_str=(char *)realloc(tmp_str,tmp_str_len))==NULL) {
116           fprintf(stderr,
117                   " cannot reallocate %d for mySQL buffer\n",tmp_str_len);
118           return NULL;
119         }
120         ttmp_str = &tmp_str[qqs_len];
121         if ((qs_len=fread(ttmp_str,sizeof(char),MYSQL_BUF,sql_file))<0) {
122           fprintf(stderr," cannot read mySQL file: %s\n",sname);
123           return NULL;
124         }
125         ttmp_str[qs_len]='\0';
126         qqs_len += qs_len;
127       }
128     }
129     fclose(sql_file);
130   }
131
132   bps = tmp_str;
133   if ((bp=strchr(bps,';'))!=NULL) {
134     *bp='\0';
135     if ((sql_db=calloc(strlen(bps)+1,sizeof(char)))==NULL) {
136       fprintf(stderr, " cannot allocate space for database name [%d], %s\n",
137               strlen(bps),bps);
138       return NULL;
139     }
140     /* have database name, parse the fields */
141     else {
142       strcpy(sql_db,bps);       /* strcpy OK because allocated strlen(bps) */
143       bps = bp+1;       /* points to next char after ';' */
144       while (isspace(*bps)) bps++;
145       *bp=';'; /* replace ; */
146       bp = sql_db;
147       while (*bp=='-') {*bp++ = ' ';}
148       sql_host = strtok(bp," \t\n");
149       sql_dbname = strtok(NULL," \t\n");
150       sql_user = strtok(NULL," \t\n");
151       sql_pass = strtok(NULL," \t\n");
152       if ((tp=strchr(sql_host,':'))!=NULL) {
153         *tp='\0';
154         sql_port=atoi(tp+1);
155       }
156       else sql_port = 0;
157     }
158   }
159   else {
160     fprintf(stderr," cannot find database fields:\n%s\n",tmp_str);
161     return NULL;
162   }
163
164   /* we have all the info we need to open a database, allocate lmf_str */
165   if ((m_fptr = (struct lmf_str *)calloc(1,sizeof(struct lmf_str)))==NULL) {
166     fprintf(stderr," cannot allocate lmf_str (%ld) for %s\n",
167             sizeof(struct lmf_str),sname);
168     return NULL;
169   }
170
171   /* have our struct, initialize it */
172
173   strncpy(m_fptr->lb_name,sname,MAX_FN);
174   m_fptr->lb_name[MAX_FN-1]='\0';
175
176   m_fptr->sascii = sascii;
177
178   m_fptr->sql_db = sql_db;
179   m_fptr->getlib = mysql_getlib;
180   m_fptr->ranlib = mysql_ranlib;
181   m_fptr->mm_flg = 0;
182   m_fptr->sql_reopen = 0;
183   m_fptr->lb_type = MYSQL_LIB;
184
185   /* now open the database, if necessary */
186   if ((m_fptr->mysql_conn=mysql_init(NULL))==NULL) {
187     fprintf(stderr,"*** Error - mysql_init\n");
188     goto error_r;
189   }
190
191   if (mysql_real_connect(m_fptr->mysql_conn,
192                          sql_host,sql_user,sql_pass,
193                          sql_dbname,
194                          sql_port,
195                          NULL,
196                          0)==NULL)
197     {
198       fprintf(stderr,"*** Error %u - could  not open database:\n%s\n%s",
199               mysql_errno(m_fptr->mysql_conn),tmp_str,
200               mysql_error(m_fptr->mysql_conn));
201       goto error_r;
202     }
203   else {
204     fprintf(stderr," Database %s opened on %s\n",sql_dbname,sql_host);
205   }
206
207   /* check for 'DO' command - copy to 'DO' string */
208   while (*bps == '-') { *bps++=' ';}
209   if (isspace(bps[-1]) && toupper(bps[0])=='D' &&
210       toupper(bps[1])=='O' && isspace(bps[2])) {
211     /* have some 'DO' commands */
212     /* check where the end of the last DO statement is */
213
214     sql_do_cnt = 1;     /* count up the number of 'DO' statements for later */
215     bdp=bps+3;
216     while ((bp=strchr(bdp,';'))!=NULL) {
217       tp = bp+2; /* skip ;\n */
218       while (isspace(*tp) || *tp == '-') {*tp++ = ' ';}
219       if (toupper(*tp)=='D' && toupper(tp[1])=='O' && isspace(tp[2])) {
220         sql_do_cnt++;           /* count the DO statements */
221         bdp = tp+3;             /* move to the next DO statement */
222       }
223       else break;
224     }
225     if (bp != NULL) {   /* end of the last DO, begin of select */
226       tchar = *(bp+1);
227       *(bp+1)='\0';             /* terminate DO strings */
228       if ((sql_do = calloc(strlen(bps)+1, sizeof(char)))==NULL) {
229         fprintf(stderr," cannot allocate %d for sql_do\n",strlen(bps));
230         goto error_r;
231       }
232       else {
233         strcpy(sql_do,bps);
234         *(bp+1)=tchar;  /* replace missing ';' */
235       }
236       bps = bp+1;
237       while (isspace(*bps)) bps++;
238     }
239     else {
240       fprintf(stderr," terminal ';' not found: %s\n",bps);
241       goto error_r;
242     }
243     /* all the DO commands are in m_fptr->sql_do in the form: 
244      DO command1; DO command2; DO command3; */
245     bdp = sql_do;
246     while (sql_do_cnt-- && (bp=strchr(bdp,';'))!=NULL) {
247       /* do the mysql statement on bdp+3 */
248       /* check for error */
249       *bp='\0';
250       if (mysql_query(m_fptr->mysql_conn,bdp+3)) {
251         fprintf(stderr,"*** Error %u - query failed:\n%s\n%s\n",
252                 mysql_errno(m_fptr->mysql_conn), bdp+3, mysql_error(m_fptr->mysql_conn));
253         goto error_r;
254       }
255       *bp=';';
256       bdp = bp+1;
257       while (isspace(*bdp)) bdp++;
258     }
259   }
260
261   /* copy 1st query field */
262   if ((bp=strchr(bps,';'))!=NULL) {
263     *bp='\0';
264     if ((m_fptr->sql_query=calloc(strlen(bps)+1,sizeof(char)))==NULL) {
265       fprintf(stderr, " cannot allocate space for query string [%d], %s\n",
266               strlen(bps),bps);
267       goto error_r;
268     }
269     /* have query, copy it */
270     else {
271       strcpy(m_fptr->sql_query,bps);
272       *bp=';'; /* replace ; */
273       bps = bp+1;
274       while(isspace(*bps)) bps++;
275     }
276   }
277   else {
278     fprintf(stderr," cannot find database query field:\n%s\n",tmp_str);
279     goto error_r;
280   }
281
282   /* copy get_desc field */
283   if ((bp=strchr(bps,';'))!=NULL) {
284     *bp='\0';
285     if ((m_fptr->sql_getdesc=calloc(strlen(bps)+1,sizeof(char)))==NULL) {
286       fprintf(stderr, " cannot allocate space for database name [%d], %s\n",
287               strlen(bps),bps);
288       goto error_r;
289     }
290     /* have get_desc, copy it */
291     else {
292       strcpy(m_fptr->sql_getdesc,bps);
293       *bp=';'; /* replace ; */
294       bps = bp+1;
295       while(isspace(*bps)) bps++;
296     }
297   }
298   else {
299     fprintf(stderr," cannot find getdesc field:\n%s\n",tmp_str);
300     goto error_r;
301   }
302
303   if ((bp=strchr(bps,';'))!=NULL) { *bp='\0';}
304
305   if ((m_fptr->sql_getseq=calloc(strlen(bps)+1,sizeof(char)))==NULL) {
306     fprintf(stderr, " cannot allocate space for database name [%d], %s\n",
307             strlen(bps),bps);
308     goto error_r;
309   }
310
311   if (strlen(bps) > 0) {
312     strcpy(m_fptr->sql_getseq,bps);
313   }
314   else {
315     fprintf(stderr," cannot find getseq field:\n%s\n",tmp_str);
316     return 0;
317   }
318   if (bp!=NULL) *bp=';';
319
320   /* now do the query */    
321
322   if (mysql_query(m_fptr->mysql_conn,m_fptr->sql_query)) {
323     fprintf(stderr,"*** Error %u - query failed:\n%s\n%s\n",
324             mysql_errno(m_fptr->mysql_conn), m_fptr->sql_query, mysql_error(m_fptr->mysql_conn));
325     goto error_r;
326   }
327
328   if ((m_fptr->mysql_res = mysql_use_result(m_fptr->mysql_conn)) == NULL) {
329     fprintf(stderr,"*** Error = use result failed\n%s\n",
330             mysql_error(m_fptr->mysql_conn));
331     goto error_r;
332   }
333   return m_fptr;
334
335  error_r:
336   free(m_fptr->sql_getseq);
337   free(m_fptr->sql_getdesc);
338   free(m_fptr->sql_query);
339   free(m_fptr);
340   free(sql_db);
341   return NULL;
342 }
343
344 struct lmf_str *
345 mysql_reopen(struct lmf_str *m_fptr) {
346   m_fptr->sql_reopen = 1;
347   return m_fptr;
348 }
349
350 void
351 mysql_closelib(struct lmf_str *m_fptr) {
352
353   if (m_fptr == NULL) return;
354   if (m_fptr->mysql_res != NULL)
355     mysql_free_result(m_fptr->mysql_res);
356   mysql_close(m_fptr->mysql_conn);
357   m_fptr->sql_reopen=0;
358 }
359
360 /*
361 static char *sql_seq = NULL, *sql_seqp;
362 static int sql_seq_len;
363 static MYSQL_ROW sql_row;
364 */
365
366 int
367 mysql_getlib( unsigned char *seq,
368               int maxs,
369               char *libstr,
370               int n_libstr,
371               fseek_t *libpos,
372               int *lcont,
373               struct lmf_str *lm_fd,
374               long *l_off)
375 {
376   register unsigned char *cp, *seqp;
377   register int *ap;
378   unsigned char *seqm, *seqm1;
379   char *bp;
380   /*   int l_start, l_stop, len; */
381
382   seqp = seq;
383   seqm = &seq[maxs-9];
384   seqm1 = seqm-1;
385
386   ap = lm_fd->sascii;
387
388 #ifdef SUPERFAMNUM
389   sfnum[0]=nsfnum = 0;
390 #endif
391
392   if (*lcont==0) {
393     /* get a row, with UID, sequence */
394     *l_off = 1;
395     if ((lm_fd->mysql_row =mysql_fetch_row(lm_fd->mysql_res))!=NULL) {
396       *libpos=(fseek_t)atol(lm_fd->mysql_row[0]);
397
398       /* for @P:1-n removed */
399       /*
400       if ((bp=strchr(lm_fd->mysql_row[2],'@'))!=NULL &&
401           !strncmp(bp+1,"P:",2)) {
402         sscanf(bp+3,"%d-%d",&l_start,&l_stop)
403         l_start--;
404         if (l_start < 0) l_start=0;
405         if (l_stop > (len=strlen(lm_fd->mysql_row[1]))) l_stop= len-1;
406         lm_fd->sql_seqp = lm_fd->mysql_row[1];
407         lm_fd->sql_seqp[l_stop]='\0';
408         lm_fd->sql_seqp += l_start;
409       */
410
411       if (lm_fd->mysql_row[2] == NULL) {
412         fprintf(stderr," NULL comment at: [%s] %ld\n",
413                 lm_fd->mysql_row[0],*libpos);
414       }
415       else if ((bp=strchr(lm_fd->mysql_row[2],'@'))!=NULL &&
416           !strncmp(bp+1,"C:",2)) sscanf(bp+3,"%ld",l_off);
417       else *l_off = 1;
418
419       lm_fd->sql_seqp = lm_fd->mysql_row[1];
420
421       /* because of changes in mysql_ranlib(), it is essential that
422          libstr return the unique identifier; thus we must use
423          sql_row[0], not sql_row[2]. Using libstr as the UID allows
424          one to use any UID, not just numeric ones.  *libpos is not
425          used for mysql libraries.
426       */
427
428       if (n_libstr <= MAX_UID) {
429         /* the normal case returns only GID/sequence */
430         strncpy(libstr,lm_fd->mysql_row[0],MAX_UID-1);
431         libstr[MAX_UID-1]='\0';
432       }
433       else {
434         /* here we do not use the UID in libstr, because we are not
435            going back into the db */
436         /* the PVM case also returns a long description */
437         if (lm_fd->mysql_row[2]!=NULL) {
438           strncpy(libstr,lm_fd->mysql_row[2],n_libstr-1);
439         }
440         else {
441           strncpy(libstr,lm_fd->mysql_row[0],n_libstr-1);
442         }
443         libstr[n_libstr-1]='\0';
444       }
445     }
446     else {
447       mysql_free_result(lm_fd->mysql_res);
448       lm_fd->mysql_res=NULL;
449       *lcont = 0;
450       *seqp = EOSEQ;
451       return -1;
452     }
453   }
454
455   for (cp=(unsigned char *)lm_fd->sql_seqp; seqp<seqm1 && *cp; ) {
456     if ((*seqp++=ap[*cp++])<NA &&
457         (*seqp++=ap[*cp++])<NA &&
458         (*seqp++=ap[*cp++])<NA &&
459         (*seqp++=ap[*cp++])<NA &&
460         (*seqp++=ap[*cp++])<NA &&
461         (*seqp++=ap[*cp++])<NA &&
462         (*seqp++=ap[*cp++])<NA &&
463         (*seqp++=ap[*cp++])<NA &&
464         (*seqp++=ap[*cp++])<NA &&
465         (*seqp++=ap[*cp++])<NA) continue;
466     --seqp;
467     if (*(cp-1)==0) break;
468   }
469   lm_fd->sql_seqp = (char *)cp;
470
471   if (seqp>=seqm1) (*lcont)++;
472   else {
473     *lcont=0;
474     if (lm_fd->sql_reopen) {
475       mysql_free_result(lm_fd->mysql_res);
476       lm_fd->mysql_res = NULL;
477     }
478   }
479
480   *seqp = EOSEQ;
481   /*   if ((int)(seqp-seq)==0) return 1; */
482   return (int)(seqp-seq);
483 }
484
485 void
486 mysql_ranlib(char *str,
487              int cnt,
488              fseek_t libpos,
489              char *libstr,
490              struct lmf_str *lm_fd
491              )
492 {
493   char tmp_query[1024], tmp_val[20];
494   char *bp;
495
496   str[0]='\0';
497
498   /* put the UID into the query string - cannot use sprintf because of
499      "%' etc */
500
501   /*   sprintf(tmp_query,lm_fd->sql_getdesc,libpos); */
502
503   if ((bp=strchr(lm_fd->sql_getdesc,'#'))==NULL) {
504     fprintf(stderr, "no GID position in %s\n",lm_fd->sql_getdesc);
505     goto next1;
506   }
507   else {
508     *bp = '\0';
509     strncpy(tmp_query,lm_fd->sql_getdesc,sizeof(tmp_query));
510     tmp_query[sizeof(tmp_query)-1]='\0';
511     /*    sprintf(tmp_val,"%ld",(long)libpos); */
512     strncat(tmp_query,libstr,sizeof(tmp_query)-1);
513     strncat(tmp_query,bp+1,sizeof(tmp_query)-1);
514     *bp='#';
515     lm_fd->lpos = libpos;
516   }
517
518   /*  fprintf(stderr," requesting: %s\n",tmp_query); */
519
520   if (lm_fd->mysql_res !=NULL) {
521     mysql_free_result(lm_fd->mysql_res);
522     lm_fd->mysql_res = NULL;
523   }
524
525   if (mysql_query(lm_fd->mysql_conn,tmp_query)) {
526     fprintf(stderr,"*** Error - query failed:\n%s\n%s\n",tmp_query,
527             mysql_error(lm_fd->mysql_conn));
528     sprintf(str,"gi|%ld ***Error - query failed***",(long)libpos);
529     goto next1;
530   }
531
532   if ((lm_fd->mysql_res = mysql_use_result(lm_fd->mysql_conn)) == NULL) {
533 /*     fprintf(stderr,"*** Error = use result failed\n%s\n", 
534            mysql_error(lm_fd->mysql_conn)); */
535     sprintf(str,"gi|%ld ***use result failed***",(long)libpos);
536     goto next0;
537   }
538   
539   /* have the description */
540   if ((lm_fd->mysql_row = mysql_fetch_row(lm_fd->mysql_res))==NULL) {
541     /*    fprintf(stderr," cannot fetch description: %s\n",tmp_query); */
542     sprintf(str,"gi|%ld ***cannot fetch description***",(long)libpos);
543     goto next0;
544   }
545   
546   if (lm_fd->mysql_row[1] != NULL) strncpy(str,lm_fd->mysql_row[1],cnt-1);
547   else strncpy(str,lm_fd->mysql_row[0],cnt-1);
548   str[cnt-1]='\0';
549   while (strlen(str) < cnt-1 &&
550          (lm_fd->mysql_row = mysql_fetch_row(lm_fd->mysql_res))!=NULL) {
551     strncat(str," ",cnt-2-strlen(str));
552     if (lm_fd->mysql_row[1]!=NULL) 
553       strncat(str,lm_fd->mysql_row[1],cnt-2-strlen(str));
554     else break;
555   }
556
557   str[cnt-1]='\0';
558   if ((bp = strchr(str,'\r'))!=NULL) *bp='\0';
559   if ((bp = strchr(str,'\n'))!=NULL) *bp='\0';
560
561  next0:
562   mysql_free_result(lm_fd->mysql_res);
563  next1: 
564   lm_fd->mysql_res = NULL;
565
566   /* get the sequence, set up for mysql_getseq() */
567   /* put the UID into the query string */
568
569   if ((bp=strchr(lm_fd->sql_getseq,'#'))==NULL) {
570     fprintf(stderr, "no GID position in %s\n",lm_fd->sql_getseq);
571     return;
572   }
573   else {
574     *bp = '\0';
575     strncpy(tmp_query,lm_fd->sql_getseq,sizeof(tmp_query));
576     tmp_query[sizeof(tmp_query)-1]='\0';
577     /*    sprintf(tmp_val,"%ld",(long)libpos); */
578     strncat(tmp_query,libstr,sizeof(tmp_query));
579     strncat(tmp_query,bp+1,sizeof(tmp_query));
580     *bp='#';
581   }
582
583   if (mysql_query(lm_fd->mysql_conn,tmp_query)) {
584     fprintf(stderr,"*** Error - query failed:\n%s\n%s\n",tmp_query,
585             mysql_error(lm_fd->mysql_conn));
586   }
587
588   if ((lm_fd->mysql_res = mysql_use_result(lm_fd->mysql_conn)) == NULL) {
589     fprintf(stderr,"*** Error = use result failed\n%s\n",
590             mysql_error(lm_fd->mysql_conn));
591   }
592 }