1 /* @source ensbaseadaptor *****************************************************
2 **
3 ** Ensembl Base Adaptor functions
4 **
5 ** @author Copyright (C) 1999 Ensembl Developers
6 ** @author Copyright (C) 2006 Michael K. Schuster
7 ** @version $Revision: 1.40 $
8 ** @modified 2009 by Alan Bleasby for incorporation into EMBOSS core
9 ** @modified $Date: 2013/02/17 13:03:35 $ by $Author: mks $
10 ** @@
11 **
12 ** This library is free software; you can redistribute it and/or
13 ** modify it under the terms of the GNU Lesser General Public
14 ** License as published by the Free Software Foundation; either
15 ** version 2.1 of the License, or (at your option) any later version.
16 **
17 ** This library is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 ** Lesser General Public License for more details.
21 **
22 ** You should have received a copy of the GNU Lesser General Public
23 ** License along with this library; if not, write to the Free Software
24 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 ** MA  02110-1301,  USA.
26 **
27 ******************************************************************************/
28 
29 /* ========================================================================= */
30 /* ============================= include files ============================= */
31 /* ========================================================================= */
32 
33 #include "ensanalysis.h"
34 #include "ensbaseadaptor.h"
35 #include "ensfeature.h"
36 #include "enstable.h"
37 
38 
39 
40 
41 /* ========================================================================= */
42 /* =============================== constants =============================== */
43 /* ========================================================================= */
44 
45 /* @const ensKBaseadaptorMaximumIdentifiers ***********************************
46 **
47 ** Limit the number of identifier instances in SQL queries to chunks of
48 ** maximum size.
49 **
50 ** Ensure that the MySQL max_allowed_packet is not exceeded, which defaults
51 ** to 1 MB, by splitting large queries into smaller queries of at most 256 KiB
52 ** (32768 8-bit characters). Assuming a (generous) average identifier string
53 ** length of 16, this means a maximum of 2048 identifier instances in each
54 ** statement.
55 **
56 ******************************************************************************/
57 
58 const ajuint ensKBaseadaptorMaximumIdentifiers = 2048U;
59 
60 
61 
62 
63 /* ========================================================================= */
64 /* =========================== global variables ============================ */
65 /* ========================================================================= */
66 
67 
68 
69 
70 /* ========================================================================= */
71 /* ============================= private data ============================== */
72 /* ========================================================================= */
73 
74 
75 
76 
77 /* ========================================================================= */
78 /* =========================== private constants =========================== */
79 /* ========================================================================= */
80 
81 
82 
83 
84 /* ========================================================================= */
85 /* =========================== private variables =========================== */
86 /* ========================================================================= */
87 
88 
89 
90 
91 /* ========================================================================= */
92 /* =========================== private functions =========================== */
93 /* ========================================================================= */
94 
95 static AjBool baseadaptorFetchAllStatement(
96     EnsPBaseadaptor ba,
97     const char* const* Pcolumnnames,
98     const AjPStr constraint,
99     AjPStr *Pstatement);
100 
101 static AjBool baseadaptorRetrieveAllStatement(
102     EnsPBaseadaptor ba,
103     const AjPStr tablename,
104     const AjPStr columnname,
105     AjPStr *Pstatement);
106 
107 
108 
109 
110 /* ========================================================================= */
111 /* ======================= All functions by section ======================== */
112 /* ========================================================================= */
113 
114 
115 
116 
117 /* @filesection ensbaseadaptor ************************************************
118 **
119 ** @nam1rule ens Function belongs to the Ensembl library
120 **
121 ******************************************************************************/
122 
123 
124 
125 
126 /* @datasection [EnsPBaseadaptor] Ensembl Base Adaptor ************************
127 **
128 ** @nam2rule Baseadaptor Functions for manipulating
129 ** Ensembl Base Adaptor objects
130 **
131 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor
132 ** @cc CVS Revision: 1.68
133 ** @cc CVS Tag: branch-ensembl-68
134 **
135 ******************************************************************************/
136 
137 
138 
139 
140 /* @section constructors ******************************************************
141 **
142 ** All constructors return a new Ensembl Base Adaptor by pointer.
143 ** It is the responsibility of the user to first destroy any previous
144 ** Base Adaptor. The target pointer does not need to be initialised to
145 ** NULL, but it is good programming practice to do so anyway.
146 **
147 ** @fdata [EnsPBaseadaptor]
148 **
149 ** @nam3rule New Constructor with initial values
150 **
151 ** @argrule New dba [EnsPDatabaseadaptor]
152 ** Ensembl Database Adaptor
153 ** @argrule New Ptablenames [const char* const*]
154 ** SQL table name array
155 ** @argrule New Pcolumnnames [const char* const*]
156 ** SQL column name array
157 ** @argrule New leftjoins [const EnsPBaseadaptorLeftjoin]
158 ** SQL LEFT JOIN condition array
159 ** @argrule New defaultcondition [const char*]
160 ** SQL SELECT default condition
161 ** @argrule New finalcondition [const char*]
162 ** SQL SELECT final condition
163 ** @argrule New Fstatement [AjBool function]
164 ** Statement function address
165 **
166 ** @valrule * [EnsPBaseadaptor] Ensembl Base Adaptor or NULL
167 **
168 ** @fcategory new
169 ******************************************************************************/
170 
171 
172 
173 
174 /* @func ensBaseadaptorNew ****************************************************
175 **
176 ** Default constructor for an Ensembl Base Adaptor.
177 **
178 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::new
179 ** @param [u] dba [EnsPDatabaseadaptor]
180 ** Ensembl Database Adaptor
181 ** @param [r] Ptablenames [const char* const*]
182 ** SQL table name array
183 ** @param [r] Pcolumnnames [const char* const*]
184 ** SQL column name array
185 ** @param [rN] leftjoins [const EnsPBaseadaptorLeftjoin]
186 ** SQL LEFT JOIN condition array
187 ** @param [rN] defaultcondition [const char*]
188 ** SQL SELECT default condition
189 ** @param [rN] finalcondition [const char*]
190 ** SQL SELECT final condition
191 ** @param [f] Fstatement [AjBool function]
192 ** Statement function address
193 **
194 ** @return [EnsPBaseadaptor] Ensembl Base Adaptor or NULL
195 **
196 ** @release 6.2.0
197 ** @@
198 ******************************************************************************/
199 
ensBaseadaptorNew(EnsPDatabaseadaptor dba,const char * const * Ptablenames,const char * const * Pcolumnnames,const EnsPBaseadaptorLeftjoin leftjoins,const char * defaultcondition,const char * finalcondition,AjBool (* Fstatement)(EnsPBaseadaptor ba,const AjPStr statement,EnsPAssemblymapper am,EnsPSlice slice,AjPList objects))200 EnsPBaseadaptor ensBaseadaptorNew(
201     EnsPDatabaseadaptor dba,
202     const char *const *Ptablenames,
203     const char *const *Pcolumnnames,
204     const EnsPBaseadaptorLeftjoin leftjoins,
205     const char *defaultcondition,
206     const char *finalcondition,
207     AjBool (*Fstatement) (EnsPBaseadaptor ba,
208                           const AjPStr statement,
209                           EnsPAssemblymapper am,
210                           EnsPSlice slice,
211                           AjPList objects))
212 {
213     EnsPBaseadaptor ba = NULL;
214 
215     if (!dba)
216         return NULL;
217 
218     if (!Ptablenames)
219         return NULL;
220 
221     if (!Pcolumnnames)
222         return NULL;
223 
224     if (!Fstatement)
225         return NULL;
226 
227     AJNEW0(ba);
228 
229     ba->Adaptor          = dba;
230     ba->Tablenames       = Ptablenames;
231     ba->Columnnames      = Pcolumnnames;
232     ba->Leftjoins        = leftjoins;
233     ba->Defaultcondition = defaultcondition;
234     ba->Finalcondition   = finalcondition;
235     ba->Fstatement       = Fstatement;
236 
237     return ba;
238 }
239 
240 
241 
242 
243 /* @section destructors *******************************************************
244 **
245 ** Destruction destroys all internal data structures and frees the memory
246 ** allocated for an Ensembl Base Adaptor object.
247 **
248 ** @fdata [EnsPBaseadaptor]
249 **
250 ** @nam3rule Del Destroy (free) an Ensembl Base Adaptor
251 **
252 ** @argrule * Pba [EnsPBaseadaptor*] Ensembl Base Adaptor address
253 **
254 ** @valrule * [void]
255 **
256 ** @fcategory delete
257 ******************************************************************************/
258 
259 
260 
261 
262 /* @func ensBaseadaptorDel ****************************************************
263 **
264 ** Default destructor for an Ensembl Base Adaptor.
265 **
266 ** @param [d] Pba [EnsPBaseadaptor*] Ensembl Base Adaptor address
267 **
268 ** @return [void]
269 **
270 ** @release 6.2.0
271 ** @@
272 ******************************************************************************/
273 
ensBaseadaptorDel(EnsPBaseadaptor * Pba)274 void ensBaseadaptorDel(EnsPBaseadaptor *Pba)
275 {
276     EnsPBaseadaptor pthis = NULL;
277 
278     if (!Pba)
279         return;
280 
281 #if defined(AJ_DEBUG) && AJ_DEBUG >= 1
282     if (ajDebugTest("ensBaseadaptorDel"))
283         ajDebug("ensBaseadaptorDel\n"
284                 "  *Pba %p\n",
285                 *Pba);
286 #endif /* defined(AJ_DEBUG) && AJ_DEBUG >= 1 */
287 
288     if (!(pthis = *Pba))
289         return;
290 
291     ajMemFree((void **) Pba);
292 
293     return;
294 }
295 
296 
297 
298 
299 /* @section member retrieval **************************************************
300 **
301 ** Functions for returning members of an Ensembl Base Adaptor object.
302 **
303 ** @fdata [EnsPBaseadaptor]
304 **
305 ** @nam3rule Get Return Base Adaptor attribute(s)
306 ** @nam4rule Columnnames Return the SQl column name array
307 ** @nam4rule Databaseadaptor Return the Ensembl Database Adaptor
308 ** @nam4rule Tablenames Return the SQL table name array
309 **
310 ** @argrule * ba [const EnsPBaseadaptor] Ensembl Base Adaptor
311 **
312 ** @valrule Columnnames [const char* const*] SQL column name array or NULL
313 ** @valrule Databaseadaptor [EnsPDatabaseadaptor] Ensembl Database Adaptor
314 ** or NULL
315 ** @valrule Tablenames [const char* const*] SQL table name array or NULL
316 **
317 ** @fcategory use
318 ******************************************************************************/
319 
320 
321 
322 
323 /* @func ensBaseadaptorGetColumnnames *****************************************
324 **
325 ** Get the SQL column name array member of an Ensembl Base Adaptor.
326 **
327 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::_columns
328 ** @param [r] ba [const EnsPBaseadaptor] Ensembl Base Adaptor
329 **
330 ** @return [const char* const*] SQL column name array or NULL
331 **
332 ** @release 6.2.0
333 ** @@
334 ******************************************************************************/
335 
ensBaseadaptorGetColumnnames(const EnsPBaseadaptor ba)336 const char* const* ensBaseadaptorGetColumnnames(const EnsPBaseadaptor ba)
337 {
338     return (ba) ? ba->Columnnames : NULL;
339 }
340 
341 
342 
343 
344 /* @func ensBaseadaptorGetDatabaseadaptor *************************************
345 **
346 ** Get the Ensembl Database Adaptor member of an Ensembl Base Adaptor.
347 **
348 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::db
349 ** @param [r] ba [const EnsPBaseadaptor] Ensembl Base Adaptor
350 **
351 ** @return [EnsPDatabaseadaptor] Ensembl Database Adaptor or NULL
352 **
353 ** @release 6.2.0
354 ** @@
355 ******************************************************************************/
356 
ensBaseadaptorGetDatabaseadaptor(const EnsPBaseadaptor ba)357 EnsPDatabaseadaptor ensBaseadaptorGetDatabaseadaptor(const EnsPBaseadaptor ba)
358 {
359     return (ba) ? ba->Adaptor : NULL;
360 }
361 
362 
363 
364 
365 /* @func ensBaseadaptorGetTablenames ******************************************
366 **
367 ** Get the SQL table name array member of an Ensembl Base Adaptor.
368 **
369 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::_tables
370 ** @param [r] ba [const EnsPBaseadaptor] Ensembl Base Adaptor
371 **
372 ** @return [const char* const*] SQL table name array or NULL
373 **
374 ** @release 6.2.0
375 ** @@
376 ******************************************************************************/
377 
ensBaseadaptorGetTablenames(const EnsPBaseadaptor ba)378 const char* const* ensBaseadaptorGetTablenames(const EnsPBaseadaptor ba)
379 {
380     return (ba) ? ba->Tablenames : NULL;
381 }
382 
383 
384 
385 
386 /* @section member assignment *************************************************
387 **
388 ** Functions for assigning members of an Ensembl Base Adaptor object.
389 **
390 ** @fdata [EnsPBaseadaptor]
391 **
392 ** @nam3rule Set Set one member of a Base Adaptor
393 ** @nam4rule Columnnames Set the SQL column name array
394 ** @nam4rule Defaultcondition Set the SQL SELECT default condition
395 ** @nam4rule Finalcondition Set the SQL SELECT final condition
396 ** @nam4rule Tablenames Set the SQL table name array
397 **
398 ** @argrule * ba [EnsPBaseadaptor] Base Adaptor
399 ** @argrule Columnnames Pcolumnnames [const char* const*]
400 ** SQL column name array
401 ** @argrule Defaultcondition defaultcondition [const char*]
402 ** SQL SELECT default condition
403 ** @argrule Finalcondition finalcondition [const char*]
404 ** SQL SELECT final condition
405 ** @argrule Tablenames Ptablenames [const char* const*]
406 ** SQL table name array
407 **
408 ** @valrule * [AjBool] ajTrue upon success, ajFalse otherwise
409 **
410 ** @fcategory modify
411 ******************************************************************************/
412 
413 
414 
415 
416 /* @func ensBaseadaptorSetColumnnames *****************************************
417 **
418 ** Set the SQL column name array member of an Ensembl Base Adaptor.
419 **
420 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::_columns
421 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
422 ** @param [r] Pcolumnnames [const char* const*] SQL column name array
423 **
424 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
425 **
426 ** @release 6.2.0
427 ** @@
428 ******************************************************************************/
429 
ensBaseadaptorSetColumnnames(EnsPBaseadaptor ba,const char * const * Pcolumnnames)430 AjBool ensBaseadaptorSetColumnnames(EnsPBaseadaptor ba,
431                                     const char* const* Pcolumnnames)
432 {
433     if (!ba)
434         return ajFalse;
435 
436     if (!Pcolumnnames)
437         return ajFalse;
438 
439     ba->Columnnames = Pcolumnnames;
440 
441     return ajTrue;
442 }
443 
444 
445 
446 
447 /* @func ensBaseadaptorSetDefaultcondition ************************************
448 **
449 ** Set the SQL SELECT default condition member of an Ensembl Base Adaptor.
450 **
451 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::_default_where_clause
452 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
453 ** @param [r] defaultcondition [const char*] SQL SELECT default condition
454 **
455 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
456 **
457 ** @release 6.4.0
458 ** @@
459 ******************************************************************************/
460 
ensBaseadaptorSetDefaultcondition(EnsPBaseadaptor ba,const char * defaultcondition)461 AjBool ensBaseadaptorSetDefaultcondition(EnsPBaseadaptor ba,
462                                          const char *defaultcondition)
463 {
464     if (!ba)
465         return ajFalse;
466 
467     ba->Defaultcondition = defaultcondition;
468 
469     return ajTrue;
470 }
471 
472 
473 
474 
475 /* @func ensBaseadaptorSetFinalcondition **************************************
476 **
477 ** Set the SQL SELECT final condition member of an Ensembl Base Adaptor.
478 **
479 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::_final_clause
480 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
481 ** @param [r] finalcondition [const char*] SQL SELECT final condition
482 **
483 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
484 **
485 ** @release 6.4.0
486 ** @@
487 ******************************************************************************/
488 
ensBaseadaptorSetFinalcondition(EnsPBaseadaptor ba,const char * finalcondition)489 AjBool ensBaseadaptorSetFinalcondition(EnsPBaseadaptor ba,
490                                        const char *finalcondition)
491 {
492     if (!ba)
493         return ajFalse;
494 
495     ba->Finalcondition = finalcondition;
496 
497     return ajTrue;
498 }
499 
500 
501 
502 
503 /* @func ensBaseadaptorSetTablenames ******************************************
504 **
505 ** Set the SQL table name array member of an Ensembl Base Adaptor.
506 **
507 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::_tables
508 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
509 ** @param [r] Ptablenames [const char* const*] SQL table name array
510 **
511 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
512 **
513 ** @release 6.2.0
514 ** @@
515 ******************************************************************************/
516 
ensBaseadaptorSetTablenames(EnsPBaseadaptor ba,const char * const * Ptablenames)517 AjBool ensBaseadaptorSetTablenames(EnsPBaseadaptor ba,
518                                    const char* const* Ptablenames)
519 {
520     if (!ba)
521         return ajFalse;
522 
523     if (!Ptablenames)
524         return ajFalse;
525 
526     ba->Tablenames = Ptablenames;
527 
528     return ajTrue;
529 }
530 
531 
532 
533 
534 /* @section convenience functions *********************************************
535 **
536 ** Ensembl Base Adaptor convenience functions
537 **
538 ** @fdata [EnsPBaseadaptor]
539 **
540 ** @nam3rule Escape Escape a string
541 ** @nam4rule C Escape to an AJAX String
542 ** @nam4rule S Escape to a C-type character string
543 ** @nam3rule Get Get members(s)
544 ** @nam4rule All Get all members
545 ** @nam4rule Multispecies Get the Ensembl Database Adaptor
546 ** multiple-species flag
547 ** @nam4rule Primarytable Get the primary SQL table name
548 ** @nam4rule Speciesidentifier Get the Ensembl Database Adaptor
549 ** species identifier
550 **
551 ** @argrule Escape ba [EnsPBaseadaptor] Ensembl Base Adaptor
552 ** @argrule EscapeC Ptxt [char**] Address of the (new) SQL-escaped C string
553 ** @argrule EscapeC str [const AjPStr] AJAX String to be escaped
554 ** @argrule EscapeS Pstr [AjPStr*] Address of the (new) SQL-escaped AJAX String
555 ** @argrule EscapeS str [const AjPStr] AJAX String to be escaped
556 ** @argrule Get ba [const EnsPBaseadaptor] Ensembl Base Adaptor
557 **
558 ** @valrule EscapeC [AjBool] ajTrue upon success, ajFalse otherwise
559 ** @valrule EscapeS [AjBool] ajTrue upon success, ajFalse otherwise
560 ** @valrule Multispecies [AjBool] ajTrue for multiple species
561 ** @valrule Primarytable [const char*] Primary table name address or NULL
562 ** @valrule Speciesidentifier [ajuint] Ensembl Database Adaptor
563 ** species identifier or 0
564 **
565 ** @fcategory use
566 ******************************************************************************/
567 
568 
569 
570 
571 /* @func ensBaseadaptorEscapeC ************************************************
572 **
573 ** Escape special characters in an AJAX String for use in an SQL statement,
574 ** taking into account the current character set of the AJAX SQL Connection
575 ** and return a C-type character string.
576 **
577 ** The caller is responsible for deleting the escaped C-type character string.
578 **
579 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
580 ** @param [wP] Ptxt [char**] Address of the (new) SQL-escaped C string
581 ** @param [r] str [const AjPStr] AJAX String to be escaped
582 **
583 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
584 **
585 ** @release 6.2.0
586 ** @@
587 ******************************************************************************/
588 
ensBaseadaptorEscapeC(EnsPBaseadaptor ba,char ** Ptxt,const AjPStr str)589 AjBool ensBaseadaptorEscapeC(EnsPBaseadaptor ba,
590                              char **Ptxt,
591                              const AjPStr str)
592 {
593 #if defined(AJ_DEBUG) && AJ_DEBUG >= 1
594     if (ajDebugTest("ensBaseadaptorEscapeC"))
595         ajDebug("ensBaseadaptorEscapeC\n"
596                 "  ba %p\n"
597                 "  Ptxt %p\n"
598                 "  str '%S'\n",
599                 ba,
600                 Ptxt,
601                 str);
602 #endif /* defined(AJ_DEBUG) && AJ_DEBUG >= 1 */
603 
604     return ensDatabaseadaptorEscapeC(
605         ensBaseadaptorGetDatabaseadaptor(ba),
606         Ptxt,
607         str);
608 }
609 
610 
611 
612 
613 /* @func ensBaseadaptorEscapeS ************************************************
614 **
615 ** Escape special characters in an AJAX String for use in an SQL statement,
616 ** taking into account the current character set of the AJAX SQL Connection
617 ** and return an AJAX String.
618 **
619 ** The caller is responsible for deleting the escaped AJAX String.
620 **
621 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
622 ** @param [wP] Pstr [AjPStr*] Address of the (new) SQL-escaped AJAX String
623 ** @param [r] str [const AjPStr] AJAX String to be escaped
624 **
625 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
626 **
627 ** @release 6.2.0
628 ** @@
629 ******************************************************************************/
630 
ensBaseadaptorEscapeS(EnsPBaseadaptor ba,AjPStr * Pstr,const AjPStr str)631 AjBool ensBaseadaptorEscapeS(EnsPBaseadaptor ba,
632                              AjPStr *Pstr,
633                              const AjPStr str)
634 {
635 #if defined(AJ_DEBUG) && AJ_DEBUG >= 1
636     if (ajDebugTest("ensBaseadaptorEscapeS"))
637         ajDebug("ensBaseadaptorEscapeS\n"
638                 "  ba %p\n"
639                 "  Pstr %p\n"
640                 "  str '%S'\n",
641                 ba,
642                 Pstr,
643                 str);
644 #endif /* defined(AJ_DEBUG) && AJ_DEBUG >= 1 */
645 
646     return ensDatabaseadaptorEscapeS(
647         ensBaseadaptorGetDatabaseadaptor(ba),
648         Pstr,
649         str);
650 }
651 
652 
653 
654 
655 /* @func ensBaseadaptorGetMultispecies ****************************************
656 **
657 ** Get the multiple-species member of the Ensembl Database Adaptor member
658 ** of an Ensembl Base Adaptor.
659 **
660 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::is_multispecies
661 ** @param [r] ba [const EnsPBaseadaptor] Ensembl Base Adaptor
662 **
663 ** @return [AjBool] ajTrue if the database contains multiple species,
664 **                  ajFalse otherwise
665 **
666 ** @release 6.4.0
667 ** @@
668 ******************************************************************************/
669 
ensBaseadaptorGetMultispecies(const EnsPBaseadaptor ba)670 AjBool ensBaseadaptorGetMultispecies(const EnsPBaseadaptor ba)
671 {
672     return ensDatabaseadaptorGetMultispecies(
673         ensBaseadaptorGetDatabaseadaptor(ba));
674 }
675 
676 
677 
678 
679 /* @func ensBaseadaptorGetPrimarytable ****************************************
680 **
681 ** Get the primary SQL table name address of an Ensembl Base Adaptor.
682 ** The primary SQL table name is the first one in the SQL table name array.
683 **
684 ** @param [r] ba [const EnsPBaseadaptor] Ensembl Base Adaptor
685 **
686 ** @return [const char*] Primary SQL table name address or NULL
687 **
688 ** @release 6.4.0
689 ** @@
690 ******************************************************************************/
691 
ensBaseadaptorGetPrimarytable(const EnsPBaseadaptor ba)692 const char* ensBaseadaptorGetPrimarytable(const EnsPBaseadaptor ba)
693 {
694     return (ba) ? ba->Tablenames[0] : NULL;
695 }
696 
697 
698 
699 
700 /* @func ensBaseadaptorGetSpeciesidentifier ***********************************
701 **
702 ** Get the species identifier member of the Ensembl Database Adaptor member
703 ** of an Ensembl Base Adaptor.
704 **
705 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::species_id
706 ** @param [r] ba [const EnsPBaseadaptor] Ensembl Base Adaptor
707 **
708 ** @return [ajuint] Ensembl species identifier or 0U, defaults to 1U
709 **
710 ** @release 6.4.0
711 ** @@
712 ******************************************************************************/
713 
ensBaseadaptorGetSpeciesidentifier(const EnsPBaseadaptor ba)714 ajuint ensBaseadaptorGetSpeciesidentifier(const EnsPBaseadaptor ba)
715 {
716     return ensDatabaseadaptorGetIdentifier(
717         ensBaseadaptorGetDatabaseadaptor(ba));
718 }
719 
720 
721 
722 
723 /* @funcstatic baseadaptorFetchAllStatement ***********************************
724 **
725 ** Generic function to fetch Ensembl Objects via an Ensembl Base Adaptor.
726 **
727 ** The caller is responsible for deleting the Ensembl Objects before
728 ** deleting the AJAX List.
729 **
730 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::_generate_sql
731 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
732 ** @param [rN] Pcolumnnames [const char* const*] SQL column name array
733 ** @param [rN] constraint [const AjPStr] SQL SELECT constraint
734 ** @param [u] Pstatement [AjPStr*] AJAX String (SQL statement) address
735 **
736 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
737 **
738 ** @release 6.5.0
739 ** @@
740 ******************************************************************************/
741 
baseadaptorFetchAllStatement(EnsPBaseadaptor ba,const char * const * Pcolumnnames,const AjPStr constraint,AjPStr * Pstatement)742 static AjBool baseadaptorFetchAllStatement(
743     EnsPBaseadaptor ba,
744     const char* const* Pcolumnnames,
745     const AjPStr constraint,
746     AjPStr *Pstatement)
747 {
748     const char *const *columnnamesrray = NULL;
749 
750     register ajuint i = 0U;
751     register ajuint j = 0U;
752 
753     AjBool debug  = AJFALSE;
754     AjBool match  = AJFALSE;
755 
756     AjPStr columnnames = NULL;
757     AjPStr tablenames  = NULL;
758     AjPStr joins       = NULL;
759     AjPStr parentheses = NULL;
760 
761     debug = ajDebugTest("baseadaptorFetchAllStatement");
762 
763     if (debug)
764         ajDebug("baseadaptorFetchAllStatement\n"
765                 "  ba %p\n"
766                 "  Pcolumnnames %p\n"
767                 "  constraint '%S'\n"
768                 "  Pstatement %p\n",
769                 ba,
770                 Pcolumnnames,
771                 constraint,
772                 Pstatement);
773 
774     if (!ba)
775         return ajFalse;
776 
777     if (!Pstatement)
778         return ajFalse;
779 
780     if (*Pstatement)
781         ajStrAssignClear(Pstatement);
782     else
783         *Pstatement = ajStrNew();
784 
785     columnnames = ajStrNew();
786     tablenames  = ajStrNew();
787     joins       = ajStrNew();
788     parentheses = ajStrNew();
789 
790     /* Build the column expression. */
791 
792     columnnamesrray = (Pcolumnnames) ? Pcolumnnames : ba->Columnnames;
793 
794     for (i = 0U; columnnamesrray[i]; i++)
795         ajFmtPrintAppS(&columnnames, "%s, ", columnnamesrray[i]);
796 
797     /* Remove last comma and space from the column expression. */
798 
799     ajStrCutEnd(&columnnames, 2);
800 
801     /*
802     ** Build the SQL table expression.
803     ** Construct a LEFT JOIN statement if one was defined and subsequently,
804     ** remove the left-joined SQL table from the SQL table expression.
805     */
806 
807     for (i = 0U; ba->Tablenames[i]; i++)
808     {
809         if (debug)
810             ajDebug("ensBaseadaptorFetchAllbyConstraint "
811                     "array index %u "
812                     "SQL table name '%s'\n",
813                     i, ba->Tablenames[i]);
814 
815         match = ajFalse;
816 
817         if (ba->Leftjoins)
818         {
819             for (j = 0U; ba->Leftjoins[j].Tablename; j++)
820             {
821                 if (ajCharMatchC(ba->Tablenames[i], ba->Leftjoins[j].Tablename))
822                 {
823                     ajStrAppendK(&parentheses, '(');
824 
825                     ajFmtPrintAppS(&joins,
826                                    "LEFT JOIN %s ON %s) ",
827                                    ba->Leftjoins[j].Tablename,
828                                    ba->Leftjoins[j].Condition);
829 
830                     match = ajTrue;
831 
832                     break;
833                 }
834             }
835         }
836 
837         if (!match)
838             ajFmtPrintAppS(&tablenames, "%s, ", ba->Tablenames[i]);
839     }
840 
841     /* Remove last comma and space from the SQL table expression. */
842 
843     ajStrCutEnd(&tablenames, 2);
844 
845     /* Build the SQL statement. */
846 
847     ajStrAssignC(Pstatement, "SELECT");
848 
849     if (ba->Mysqlstraightjoin)
850         ajStrAppendC(Pstatement, " STRAIGHT_JOIN");
851 
852     ajFmtPrintAppS(Pstatement, " %S FROM %S(%S)",
853                    columnnames, parentheses, tablenames);
854 
855     if (joins && ajStrGetLen(joins))
856         ajFmtPrintAppS(Pstatement, " %S", joins);
857 
858     if (constraint && ajStrGetLen(constraint))
859     {
860         ajFmtPrintAppS(Pstatement, " WHERE %S", constraint);
861 
862         if (ba->Defaultcondition)
863             ajFmtPrintAppS(Pstatement, " AND %s", ba->Defaultcondition);
864     }
865     else if (ba->Defaultcondition)
866         ajFmtPrintAppS(Pstatement, " WHERE %s", ba->Defaultcondition);
867 
868     if (ba->Finalcondition)
869         ajFmtPrintAppS(Pstatement, " %s", ba->Finalcondition);
870 
871     ajStrDel(&columnnames);
872     ajStrDel(&tablenames);
873     ajStrDel(&joins);
874     ajStrDel(&parentheses);
875 
876     return ajTrue;
877 }
878 
879 
880 
881 
882 /* @section object count ******************************************************
883 **
884 ** Functions for counting Ensembl Objects in an Ensembl database.
885 **
886 ** @fdata [EnsPBaseadaptor]
887 **
888 ** @nam3rule Count       Count Ensembl Object(s)
889 ** @nam4rule All         Count all Ensembl Objects
890 ** @nam4rule Allby       Count all Ensembl Objects matching a criterion
891 ** @nam5rule Constraint  Count all Ensembl Objects by an SQL SELECT constraint
892 **
893 ** @argrule * ba [EnsPBaseadaptor] Ensembl Base Adaptor
894 ** @argrule AllbyConstraint constraint [const AjPStr] SQL SELECT constraint
895 ** @argrule * Pcount [ajuint*]
896 ** AJAX integer (Ensembl Object count) address
897 **
898 ** @valrule * [AjBool] ajTrue upon success, ajFalse otherwise
899 **
900 ** @fcategory use
901 ******************************************************************************/
902 
903 
904 
905 
906 /* @func ensBaseadaptorCountAll ***********************************************
907 **
908 ** Generic function to count all Ensembl Objects via an Ensembl Base Adaptor.
909 ** Please note that it is probably not a good idea to use this function on
910 ** very large SQL tables quite common in the Ensembl genome annotation system.
911 **
912 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::fetch_all
913 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
914 ** @param [u] Pcount [ajuint*] AJAX integer (Ensembl Object count) address
915 **
916 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
917 **
918 ** @release 6.5.0
919 ** @@
920 ******************************************************************************/
921 
ensBaseadaptorCountAll(EnsPBaseadaptor ba,ajuint * Pcount)922 AjBool ensBaseadaptorCountAll(
923     EnsPBaseadaptor ba,
924     ajuint *Pcount)
925 {
926     return ensBaseadaptorCountAllbyConstraint(ba, (AjPStr) NULL, Pcount);
927 }
928 
929 
930 
931 
932 /* @func ensBaseadaptorCountAllbyConstraint ***********************************
933 **
934 ** Generic function to count all Ensembl Objects via an Ensembl Base Adaptor.
935 **
936 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::generic_count
937 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
938 ** @param [rN] constraint [const AjPStr] Constraint (optional)
939 ** @param [u] Pcount [ajuint*] AJAX integer (Ensembl Object count) address
940 **
941 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
942 **
943 ** @release 6.5.0
944 ** @@
945 ******************************************************************************/
946 
ensBaseadaptorCountAllbyConstraint(EnsPBaseadaptor ba,const AjPStr constraint,ajuint * Pcount)947 AjBool ensBaseadaptorCountAllbyConstraint(
948     EnsPBaseadaptor ba,
949     const AjPStr constraint,
950     ajuint *Pcount)
951 {
952     const char *const Pcolumnnames[] =
953         {
954             "COUNT(*)",
955             (const char*) NULL
956         };
957 
958     AjBool result = AJFALSE;
959 
960     AjPSqlstatement sqls = NULL;
961     AjISqlrow sqli       = NULL;
962     AjPSqlrow sqlr       = NULL;
963 
964     AjPStr statement = NULL;
965 
966     EnsPDatabaseadaptor dba = NULL;
967 
968     if (!ba)
969         return ajFalse;
970 
971     if (!Pcount)
972         return ajFalse;
973 
974     *Pcount = 0U;
975 
976     statement = ajStrNew();
977 
978     result = baseadaptorFetchAllStatement(
979         ba,
980         Pcolumnnames,
981         constraint,
982         &statement);
983 
984     if (!result)
985     {
986         ajStrDel(&statement);
987         return ajFalse;
988     }
989 
990     dba = ensBaseadaptorGetDatabaseadaptor(ba);
991 
992     sqls = ensDatabaseadaptorSqlstatementNew(dba, statement);
993 
994     sqli = ajSqlrowiterNew(sqls);
995 
996     while (!ajSqlrowiterDone(sqli))
997     {
998         *Pcount = 0U;
999 
1000         sqlr = ajSqlrowiterGet(sqli);
1001 
1002         ajSqlcolumnToUint(sqlr, Pcount);
1003     }
1004 
1005     ajSqlrowiterDel(&sqli);
1006 
1007     ensDatabaseadaptorSqlstatementDel(dba, &sqls);
1008 
1009     ajStrDel(&statement);
1010 
1011     return result;
1012 }
1013 
1014 
1015 
1016 
1017 /* @section object retrieval **************************************************
1018 **
1019 ** Functions for fetching Ensembl Objects from an Ensembl database.
1020 **
1021 ** @fdata [EnsPBaseadaptor]
1022 **
1023 ** @nam3rule Fetch       Fetch Ensembl Object(s)
1024 ** @nam4rule All         Fetch all Ensembl Objects
1025 ** @nam4rule Allby       Fetch all Ensembl Objects matching a criterion
1026 ** @nam5rule Constraint  Fetch all Ensembl Objects by an SQL SELECT constraint
1027 ** @nam5rule Identifiers Fetch all by SQL database-internal identifier objects
1028 ** @nam4rule By          Fetch one Ensembl Object matching a criterion
1029 ** @nam5rule Identifier  Fetch by SQL database-internal identifier
1030 **
1031 ** @argrule * ba [EnsPBaseadaptor] Ensembl Base Adaptor
1032 ** @argrule All objects [AjPList] AJAX List of Ensembl Objects
1033 ** @argrule AllbyConstraint constraint [const AjPStr] SQL SELECT constraint
1034 ** @argrule AllbyConstraint am [EnsPAssemblymapper] Ensembl Assembly Mapper
1035 ** @argrule AllbyConstraint slice [EnsPSlice] Ensembl Slice
1036 ** @argrule AllbyConstraint objects [AjPList] AJAX List of Ensembl Objects
1037 ** @argrule AllbyIdentifiers slice [EnsPSlice] Ensembl Slice
1038 ** @argrule AllbyIdentifiers FobjectGetIdentifier [ajuint function]
1039 ** Get Ensembl Object Identifier function address
1040 ** @argrule AllbyIdentifiers objects [AjPTable]
1041 ** AJAX Table of AJAX unsigned integer key data (SQL database-internal
1042 ** identifier used in an SQL SELECT IN comparison function) and Ensembl Object
1043 ** value data
1044 ** @argrule Identifier identifier [ajuint] SQL database-internal identifier
1045 ** @argrule By Pobject [void**] Ensembl Object address
1046 **
1047 ** @valrule * [AjBool] ajTrue upon success, ajFalse otherwise
1048 **
1049 ** @fcategory use
1050 ******************************************************************************/
1051 
1052 
1053 
1054 
1055 /* @func ensBaseadaptorFetchAll ***********************************************
1056 **
1057 ** Generic function to fetch all Ensembl Objects via an Ensembl Base Adaptor.
1058 ** Please note that it is probably not a good idea to use this function on
1059 ** very large SQL tables quite common in the Ensembl genome annotation system.
1060 **
1061 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::fetch_all
1062 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
1063 ** @param [u] objects [AjPList] AJAX List of Ensembl Objects
1064 **
1065 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
1066 **
1067 ** @release 6.2.0
1068 ** @@
1069 ******************************************************************************/
1070 
ensBaseadaptorFetchAll(EnsPBaseadaptor ba,AjPList objects)1071 AjBool ensBaseadaptorFetchAll(
1072     EnsPBaseadaptor ba,
1073     AjPList objects)
1074 {
1075     return ensBaseadaptorFetchAllbyConstraint(
1076         ba,
1077         (AjPStr) NULL,
1078         (EnsPAssemblymapper) NULL,
1079         (EnsPSlice) NULL,
1080         objects);
1081 }
1082 
1083 
1084 
1085 
1086 /* @func ensBaseadaptorFetchAllbyConstraint ***********************************
1087 **
1088 ** Generic function to fetch Ensembl Objects via an Ensembl Base Adaptor.
1089 **
1090 ** The caller is responsible for deleting the Ensembl Objects before
1091 ** deleting the AJAX List.
1092 **
1093 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::generic_fetch
1094 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
1095 ** @param [rN] constraint [const AjPStr] SQL SELECT constraint
1096 ** @param [uN] am [EnsPAssemblymapper] Ensembl Assembly Mapper
1097 ** @param [uN] slice [EnsPSlice] Ensembl Slice
1098 ** @param [u] objects [AjPList] AJAX List to Ensembl Objects
1099 **
1100 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
1101 **
1102 ** @release 6.4.0
1103 ** @@
1104 ******************************************************************************/
1105 
ensBaseadaptorFetchAllbyConstraint(EnsPBaseadaptor ba,const AjPStr constraint,EnsPAssemblymapper am,EnsPSlice slice,AjPList objects)1106 AjBool ensBaseadaptorFetchAllbyConstraint(
1107     EnsPBaseadaptor ba,
1108     const AjPStr constraint,
1109     EnsPAssemblymapper am,
1110     EnsPSlice slice,
1111     AjPList objects)
1112 {
1113     AjBool debug  = AJFALSE;
1114     AjBool result = AJFALSE;
1115 
1116     AjPStr statement   = NULL;
1117 
1118     debug = ajDebugTest("ensBaseadaptorFetchAllbyConstraint");
1119 
1120     if (debug)
1121         ajDebug("ensBaseadaptorFetchAllbyConstraint\n"
1122                 "  ba %p\n"
1123                 "  constraint '%S'\n"
1124                 "  am %p\n"
1125                 "  slice %p\n"
1126                 "  objects %p\n",
1127                 ba,
1128                 constraint,
1129                 am,
1130                 slice,
1131                 objects);
1132 
1133     if (!ba)
1134         return ajFalse;
1135 
1136     if (!objects)
1137         return ajFalse;
1138 
1139     statement = ajStrNew();
1140 
1141     result = baseadaptorFetchAllStatement(
1142         ba,
1143         (const char *const *) NULL,
1144         constraint,
1145         &statement);
1146 
1147     if (!result)
1148     {
1149         ajStrDel(&statement);
1150         return ajFalse;
1151     }
1152 
1153     result = (*ba->Fstatement) (ba, statement, am, slice, objects);
1154 
1155     ajStrDel(&statement);
1156 
1157     return result;
1158 }
1159 
1160 
1161 
1162 
1163 /* @func ensBaseadaptorFetchAllbyIdentifiers **********************************
1164 **
1165 ** Generic function to fetch Ensembl Objects by an AJAX Table of
1166 ** AJAX unsigned integer (SQL database-internal identifier) key data objects
1167 ** via an Ensembl Base Adaptor.
1168 **
1169 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::fetch_all_by_dbID_list
1170 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor.
1171 **
1172 ** @param [uN] slice [EnsPSlice] Ensembl Slice
1173 ** @param [f] FobjectGetIdentifier [ajuint function]
1174 ** Get Ensembl Object Identifier function address
1175 ** @param [u] objects [AjPTable]
1176 ** AJAX Table of AJAX unsigned integer key data (SQL database-internal
1177 ** identifier used in an SQL SELECT IN comparison function) and Ensembl Object
1178 ** value data
1179 **
1180 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
1181 **
1182 ** @release 6.4.0
1183 ** @@
1184 ******************************************************************************/
1185 
ensBaseadaptorFetchAllbyIdentifiers(EnsPBaseadaptor ba,EnsPSlice slice,ajuint (* FobjectGetIdentifier)(const void * object),AjPTable objects)1186 AjBool ensBaseadaptorFetchAllbyIdentifiers(
1187     EnsPBaseadaptor ba,
1188     EnsPSlice slice,
1189     ajuint (*FobjectGetIdentifier) (const void *object),
1190     AjPTable objects)
1191 {
1192     void **keyarray = NULL;
1193 
1194     register ajuint i = 0U;
1195 
1196     AjBool debug = AJFALSE;
1197 
1198     AjPList list = NULL;
1199 
1200     AjPStr constraint = NULL;
1201     AjPStr csv        = NULL;
1202 
1203     debug = ajDebugTest("ensBaseadaptorFetchAllbyIdentifiers");
1204 
1205     if (debug)
1206     {
1207         ajDebug("ensBaseadaptorFetchAllbyIdentifiers"
1208                 "  ba %p\n"
1209                 "  slice %p\n"
1210                 "  FobjectGetIdentifier %p\n"
1211                 "  objects %p\n",
1212                 ba,
1213                 slice,
1214                 FobjectGetIdentifier,
1215                 objects);
1216 
1217         ajTableTrace(objects);
1218     }
1219 
1220     if (!ba)
1221         return ajFalse;
1222 
1223     if (!FobjectGetIdentifier)
1224         return ajFalse;
1225 
1226     if (!objects)
1227         return ajFalse;
1228 
1229     list = ajListNew();
1230 
1231     csv = ajStrNew();
1232 
1233     /*
1234     ** Large queries are split into smaller ones on the basis of the maximum
1235     ** number of identifier instances configured in the Ensembl Base Adaptor
1236     ** module.
1237     ** This ensures that MySQL is faster and the maximum query size is not
1238     ** exceeded.
1239     */
1240 
1241     ajTableToarrayKeys(objects, &keyarray);
1242 
1243     for (i = 0U; keyarray[i]; i++)
1244     {
1245         if (debug)
1246             ajDebug("ensBaseadaptorFetchAllbyIdentifiers identifier %u\n",
1247                     *((ajuint *) keyarray[i]));
1248 
1249         ajFmtPrintAppS(&csv, "%u, ", *((ajuint *) keyarray[i]));
1250 
1251         /*
1252         ** Run the statement if the maximum chunk size is exceed or
1253         ** if there are no more array elements to process.
1254         */
1255 
1256         if ((((i + 1U) % ensKBaseadaptorMaximumIdentifiers) == 0) ||
1257             (keyarray[i + 1U] == NULL))
1258         {
1259             /* Remove the last comma and space. */
1260 
1261             ajStrCutEnd(&csv, 2);
1262 
1263             if (ajStrGetLen(csv))
1264             {
1265                 constraint = ajFmtStr("%s.%s_id IN (%S)",
1266                                       ba->Tablenames[0U],
1267                                       ba->Tablenames[0U],
1268                                       csv);
1269 
1270                 ensBaseadaptorFetchAllbyConstraint(
1271                     ba,
1272                     constraint,
1273                     (EnsPAssemblymapper) NULL,
1274                     slice,
1275                     list);
1276 
1277                 ajStrDel(&constraint);
1278             }
1279 
1280             ajStrAssignClear(&csv);
1281         }
1282     }
1283 
1284     AJFREE(keyarray);
1285 
1286     ajStrDel(&csv);
1287 
1288     /* Move Ensembl Objects from the AJAX List to the AJAX Table. */
1289 
1290     ensTableuintFromList(objects, FobjectGetIdentifier, list);
1291 
1292     ajListFree(&list);
1293 
1294     return ajTrue;
1295 }
1296 
1297 
1298 
1299 
1300 /* @func ensBaseadaptorFetchByIdentifier **************************************
1301 **
1302 ** Generic function to fetch an Ensembl Object by its SQL database-internal
1303 ** identifier via an Ensembl Base Adaptor.
1304 **
1305 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::fetch_by_dbID
1306 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
1307 ** @param [r] identifier [ajuint] SQL database-internal identifier
1308 ** @param [wP] Pobject [void**] Ensembl Object address
1309 **
1310 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
1311 **
1312 ** @release 6.2.0
1313 ** @@
1314 ******************************************************************************/
1315 
ensBaseadaptorFetchByIdentifier(EnsPBaseadaptor ba,ajuint identifier,void ** Pobject)1316 AjBool ensBaseadaptorFetchByIdentifier(
1317     EnsPBaseadaptor ba,
1318     ajuint identifier,
1319     void **Pobject)
1320 {
1321     AjBool result = AJFALSE;
1322 
1323     AjPList objects = NULL;
1324 
1325     AjPStr constraint = NULL;
1326 
1327     if (!ba)
1328         return ajFalse;
1329 
1330     if (!identifier)
1331         return ajFalse;
1332 
1333     if (!Pobject)
1334         return ajFalse;
1335 
1336     if (!ba->Tablenames[0])
1337         return ajFalse;
1338 
1339     *Pobject = NULL;
1340 
1341     constraint = ajFmtStr(
1342         "%s.%s_id = %u",
1343         ba->Tablenames[0],
1344         ba->Tablenames[0],
1345         identifier);
1346 
1347     objects = ajListNew();
1348 
1349     result = ensBaseadaptorFetchAllbyConstraint(
1350         ba,
1351         constraint,
1352         (EnsPAssemblymapper) NULL,
1353         (EnsPSlice) NULL,
1354         objects);
1355 
1356     if (ajListGetLength(objects) > 1)
1357         ajFatal("ensBaseadaptorFetchByIdentifier got more than one object "
1358                 "for constraint '%S'.\n", constraint);
1359 
1360     /*
1361     ** NOTE: Since an object-specific deletion function is not available,
1362     ** any additional objects lead to a memory leak.
1363     */
1364 
1365     ajListPop(objects, Pobject);
1366 
1367     ajListFree(&objects);
1368 
1369     ajStrDel(&constraint);
1370 
1371     return result;
1372 }
1373 
1374 
1375 
1376 
1377 /* @section accessory object retrieval ****************************************
1378 **
1379 ** Functions for retrieving objects releated to Ensembl Transcript objects
1380 ** from an Ensembl SQL database.
1381 **
1382 ** @fdata [EnsPBaseadaptor]
1383 **
1384 ** @nam3rule Retrieve Retrieve Ensembl Object-releated object(s)
1385 ** @nam4rule All Retrieve all Ensembl Object-releated objects
1386 ** @nam5rule Identifiers Retrieve all SQL database-internal identifier objects
1387 ** @nam5rule Strings Retrieve all AJAX String objects
1388 ** @nam4rule Feature Retrieve an Ensembl Feature
1389 **
1390 ** @argrule * ba [EnsPBaseadaptor] Ensembl Base Adaptor
1391 ** @argrule All tablename [const AjPStr] SQL table name
1392 ** @argrule All columnname [const AjPStr] SQL column name
1393 ** @argrule Identifiers identifiers [AjPList]
1394 ** AJAX List of AJAX unsigned integer objects
1395 ** @argrule Strings strings [AjPList]
1396 ** AJAX List of AJAX String objects
1397 ** @argrule Feature analysisid [ajuint] Ensembl Analysis identifier
1398 ** @argrule Feature srid [ajuint] Ensembl Sequence Region identifier
1399 ** @argrule Feature srstart [ajuint] Ensembl Sequence Region start
1400 ** @argrule Feature srend [ajuint] Ensembl Sequence Region end
1401 ** @argrule Feature srstrand [ajint] Ensembl Sequence Region strand
1402 ** @argrule Feature am [EnsPAssemblymapper] Ensembl Assembly Mapper
1403 ** @argrule Feature slice [EnsPSlice] Ensembl Slice
1404 ** @argrule Feature Pfeature [EnsPFeature*] Ensembl Feature
1405 **
1406 ** @valrule * [AjBool] ajTrue upon success, ajFalse otherwise
1407 **
1408 ** @fcategory use
1409 ******************************************************************************/
1410 
1411 
1412 
1413 
1414 /* @funcstatic baseadaptorRetrieveAllStatement ********************************
1415 **
1416 ** Helper function building a complete SQL statement for the generic retrieval
1417 ** of AJAX unsigned integer or AJAX String Ensembl Object identifiers via an
1418 ** Ensembl Base Adaptor.
1419 **
1420 ** If a SQL column name has not been provided, the primary key will be used,
1421 ** which by definition in Ensembl, is always the SQL table name suffixed
1422 ** with "_id".
1423 **
1424 ** The caller is responsible for deleting the AJAX String.
1425 **
1426 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::_list_dbIDs
1427 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
1428 ** @param [r] tablename [const AjPStr] SQL table name
1429 ** @param [rN] columnname [const AjPStr] SQL column name
1430 ** @param [u] Pstatement [AjPStr*] AJAX String address
1431 **
1432 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
1433 **
1434 ** @release 6.5.0
1435 ** @@
1436 ******************************************************************************/
1437 
baseadaptorRetrieveAllStatement(EnsPBaseadaptor ba,const AjPStr tablename,const AjPStr columnname,AjPStr * Pstatement)1438 static AjBool baseadaptorRetrieveAllStatement(
1439     EnsPBaseadaptor ba,
1440     const AjPStr tablename,
1441     const AjPStr columnname,
1442     AjPStr *Pstatement)
1443 {
1444     if (!ba)
1445         return ajFalse;
1446 
1447     if (!tablename)
1448         return ajFalse;
1449 
1450     if (!Pstatement)
1451         return ajFalse;
1452 
1453     if (*Pstatement)
1454         ajStrAssignClear(Pstatement);
1455     else
1456         *Pstatement = ajStrNew();
1457 
1458     if (columnname && ajStrGetLen(columnname))
1459         ajFmtPrintAppS(Pstatement,
1460                        "SELECT %S.%S FROM %S",
1461                        tablename,
1462                        columnname,
1463                        tablename);
1464     else
1465         ajFmtPrintAppS(Pstatement,
1466                        "SELECT %S.%S_id FROM %S",
1467                        tablename,
1468                        tablename,
1469                        tablename);
1470 
1471     return ajTrue;
1472 }
1473 
1474 
1475 
1476 
1477 /* @func ensBaseadaptorRetrieveAllIdentifiers *********************************
1478 **
1479 ** Generic function to retrieve SQL database-internal identifier objects of
1480 ** Ensembl Objects via an Ensembl Base Adaptor.
1481 **
1482 ** If a SQL column name has not been provided, the primary key will be used,
1483 ** which by definition in Ensembl, is always the SQL table name suffixed
1484 ** with "_id".
1485 **
1486 ** The caller is responsible for deleting the AJAX unsigned integer objects
1487 ** before deleting the AJAX List.
1488 **
1489 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::_list_dbIDs
1490 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
1491 ** @param [r] tablename [const AjPStr] SQL table name
1492 ** @param [rN] columnname [const AjPStr] SQL column name
1493 ** @param [u] identifiers [AjPList] AJAX List of AJAX unsigned integer
1494 ** (SQL database-internal identifier) objects
1495 **
1496 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
1497 **
1498 ** @release 6.4.0
1499 ** @@
1500 ** NOTE: The Perl API has an ordered parameter to this function, which
1501 ** appends an 'order by seq_region_id, seq_region_start' clause.
1502 ** A seq_region column, however, may not be part of the table definition,
1503 ** especially if this object does not inherit from Bio::EnsEMBL::Feature.
1504 ** This should probably move into the Bio::EnEMBL::DBSQL::BaseFeatureAdaptor,
1505 ** which always has a seq_region_id associated.
1506 ******************************************************************************/
1507 
ensBaseadaptorRetrieveAllIdentifiers(EnsPBaseadaptor ba,const AjPStr tablename,const AjPStr columnname,AjPList identifiers)1508 AjBool ensBaseadaptorRetrieveAllIdentifiers(
1509     EnsPBaseadaptor ba,
1510     const AjPStr tablename,
1511     const AjPStr columnname,
1512     AjPList identifiers)
1513 {
1514     ajuint *Pidentifier = NULL;
1515 
1516     AjPSqlstatement sqls = NULL;
1517     AjISqlrow sqli       = NULL;
1518     AjPSqlrow sqlr       = NULL;
1519 
1520     AjPStr statement = NULL;
1521 
1522     EnsPDatabaseadaptor dba = NULL;
1523 
1524     if (!ba)
1525         return ajFalse;
1526 
1527     if (!tablename)
1528         return ajFalse;
1529 
1530     if (!identifiers)
1531         return ajFalse;
1532 
1533     statement = ajStrNew();
1534 
1535     baseadaptorRetrieveAllStatement(ba, tablename, columnname, &statement);
1536 
1537     dba = ensBaseadaptorGetDatabaseadaptor(ba);
1538 
1539     sqls = ensDatabaseadaptorSqlstatementNew(dba, statement);
1540 
1541     sqli = ajSqlrowiterNew(sqls);
1542 
1543     while (!ajSqlrowiterDone(sqli))
1544     {
1545         AJNEW0(Pidentifier);
1546 
1547         sqlr = ajSqlrowiterGet(sqli);
1548 
1549         ajSqlcolumnToUint(sqlr, Pidentifier);
1550 
1551         ajListPushAppend(identifiers, (void *) Pidentifier);
1552     }
1553 
1554     ajSqlrowiterDel(&sqli);
1555 
1556     ensDatabaseadaptorSqlstatementDel(dba, &sqls);
1557 
1558     ajStrDel(&statement);
1559 
1560     return ajTrue;
1561 }
1562 
1563 
1564 
1565 
1566 /* @func ensBaseadaptorRetrieveAllStrings *************************************
1567 **
1568 ** Generic function to retrieve SQL database-internal AJAX String objects of
1569 ** Ensembl Objects via an Ensembl Base Adaptor.
1570 **
1571 ** If a SQL column name has not been provided, the primary key will be used,
1572 ** which by definition in Ensembl, is always the SQL table name suffixed
1573 ** with "_id".
1574 **
1575 ** The caller is responsible for deleting the AJAX String objects before
1576 ** deleting the AJAX List.
1577 **
1578 ** @cc Bio::EnsEMBL::DBSQL::BaseAdaptor::_list_dbIDs
1579 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
1580 ** @param [r] tablename [const AjPStr] SQL table name
1581 ** @param [rN] columnname [const AjPStr] SQL column name
1582 ** @param [u] strings [AjPList]
1583 ** AJAX List of AJAX String (SQL database-internal string) objects
1584 **
1585 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
1586 **
1587 ** @release 6.4.0
1588 ** @@
1589 ** NOTE: The Perl API has an ordered parameter to this function, which
1590 ** appends an 'order by seq_region_id, seq_region_start' clause.
1591 ** A seq_region column, however, may not be part of the table definition,
1592 ** especially if this object does not inherit from Bio::EnsEMBL::Feature.
1593 ** This should probably move into the Bio::EnEMBL::DBSQL::BaseFeatureAdaptor,
1594 ** which always has a seq_region_id associated.
1595 ******************************************************************************/
1596 
ensBaseadaptorRetrieveAllStrings(EnsPBaseadaptor ba,const AjPStr tablename,const AjPStr columnname,AjPList strings)1597 AjBool ensBaseadaptorRetrieveAllStrings(
1598     EnsPBaseadaptor ba,
1599     const AjPStr tablename,
1600     const AjPStr columnname,
1601     AjPList strings)
1602 {
1603     AjPSqlstatement sqls = NULL;
1604     AjISqlrow sqli       = NULL;
1605     AjPSqlrow sqlr       = NULL;
1606 
1607     AjPStr statement = NULL;
1608     AjPStr string    = NULL;
1609 
1610     EnsPDatabaseadaptor dba = NULL;
1611 
1612     if (!ba)
1613         return ajFalse;
1614 
1615     if (!tablename)
1616         return ajFalse;
1617 
1618     if (!strings)
1619         return ajFalse;
1620 
1621     statement = ajStrNew();
1622 
1623     baseadaptorRetrieveAllStatement(ba, tablename, columnname, &statement);
1624 
1625     dba = ensBaseadaptorGetDatabaseadaptor(ba);
1626 
1627     sqls = ensDatabaseadaptorSqlstatementNew(dba, statement);
1628 
1629     sqli = ajSqlrowiterNew(sqls);
1630 
1631     while (!ajSqlrowiterDone(sqli))
1632     {
1633         string = ajStrNew();
1634 
1635         sqlr = ajSqlrowiterGet(sqli);
1636 
1637         ajSqlcolumnToStr(sqlr, &string);
1638 
1639         ajListPushAppend(strings, (void *) string);
1640     }
1641 
1642     ajSqlrowiterDel(&sqli);
1643 
1644     ensDatabaseadaptorSqlstatementDel(dba, &sqls);
1645 
1646     ajStrDel(&statement);
1647 
1648     return ajTrue;
1649 }
1650 
1651 
1652 
1653 
1654 /* @func ensBaseadaptorRetrieveFeature ****************************************
1655 **
1656 ** Maps Ensembl Sequence Region coordinates for Ensembl Feature objects into
1657 ** Ensembl Slice coordinates and returns an Ensembl Feature object.
1658 **
1659 ** The caller is responsible for deleting the Ensembl Feature.
1660 ** This function aims to simplify all private
1661 ** objectadaptorFetchAllByStatement functions.
1662 **
1663 ** @param [u] ba [EnsPBaseadaptor] Ensembl Base Adaptor
1664 ** @param [r] analysisid [ajuint] Ensembl Analysis identifier
1665 ** @param [r] srid [ajuint] Ensembl Sequence Region identifier
1666 ** @param [r] srstart [ajuint] Ensembl Sequence Region start
1667 ** @param [r] srend [ajuint] Ensembl Sequence Region end
1668 ** @param [r] srstrand [ajint] Ensembl Sequence Region strand
1669 ** @param [uN] am [EnsPAssemblymapper] Ensembl Assembly Mapper
1670 ** @param [uN] slice [EnsPSlice] Ensembl Slice
1671 ** @param [u] Pfeature [EnsPFeature*] Ensembl Feature
1672 **
1673 ** @return [AjBool] ajTrue upon success, ajFalse otherwise
1674 ** @@
1675 ******************************************************************************/
1676 
ensBaseadaptorRetrieveFeature(EnsPBaseadaptor ba,ajuint analysisid,ajuint srid,ajuint srstart,ajuint srend,ajint srstrand,EnsPAssemblymapper am,EnsPSlice slice,EnsPFeature * Pfeature)1677 AjBool ensBaseadaptorRetrieveFeature(
1678     EnsPBaseadaptor ba,
1679     ajuint analysisid,
1680     ajuint srid,
1681     ajuint srstart,
1682     ajuint srend,
1683     ajint srstrand,
1684     EnsPAssemblymapper am,
1685     EnsPSlice slice,
1686     EnsPFeature *Pfeature)
1687 {
1688     ajint slstart  = 0;
1689     ajint slend    = 0;
1690     ajint slstrand = 0;
1691     ajint sllength = 0;
1692     ajint tmpstart = 0;
1693 
1694     AjBool circular = AJFALSE;
1695 
1696     AjPList mrs = NULL;
1697 
1698     EnsPAnalysis analysis   = NULL;
1699     EnsPAnalysisadaptor ana = NULL;
1700 
1701     EnsPAssemblymapperadaptor ama = NULL;
1702 
1703     EnsPCoordsystemadaptor csa = NULL;
1704 
1705     EnsPDatabaseadaptor dba = NULL;
1706 
1707     EnsPMapperresult mr = NULL;
1708 
1709     EnsPSlice srslice    = NULL;
1710     EnsPSliceadaptor sla = NULL;
1711 
1712     /* Presult has to be the first! */
1713 
1714     if (Pfeature)
1715         *Pfeature = NULL;
1716     else
1717         return ajFalse;
1718 
1719     if (!ba)
1720         return ajFalse;
1721 
1722     dba = ensBaseadaptorGetDatabaseadaptor(ba);
1723 
1724     ana = ensRegistryGetAnalysisadaptor(dba);
1725     ama = ensRegistryGetAssemblymapperadaptor(dba);
1726     csa = ensRegistryGetCoordsystemadaptor(dba);
1727     sla = (slice) ? ensSliceGetAdaptor(slice) : ensRegistryGetSliceadaptor(dba);
1728 
1729     /* Need to get the internal Ensembl Sequence Region identifier. */
1730 
1731     srid = ensCoordsystemadaptorGetSeqregionidentifierInternal(csa, srid);
1732 
1733     /*
1734     ** Since the Ensembl SQL schema defines Sequence Region start and end
1735     ** coordinates as unsigned integers for all Ensembl Feature objects,
1736     ** the range needs checking.
1737     */
1738 
1739     if (srstart <= INT_MAX)
1740         slstart = (ajint) srstart;
1741     else
1742         ajFatal("ensBaseadaptorRetrieveFeature got an Ensembl "
1743                 "Sequence Region start coordinate (%u) outside the "
1744                 "maximum integer limit (%d).",
1745                 srstart, INT_MAX);
1746 
1747     if (srend <= INT_MAX)
1748         slend = (ajint) srend;
1749     else
1750         ajFatal("ensBaseadaptorRetrieveFeature got an Ensembl "
1751                 "Sequence Region end coordinate (%u) outside the "
1752                 "maximum integer limit (%d).",
1753                 srend, INT_MAX);
1754 
1755     slstrand = srstrand;
1756 
1757     /* Fetch a Slice spanning the entire Sequence Region. */
1758 
1759     ensSliceadaptorFetchBySeqregionIdentifier(sla, srid, 0, 0, 0, &srslice);
1760 
1761     /*
1762     ** Increase the reference counter of the Ensembl Assembly Mapper if
1763     ** one has been specified, otherwise fetch it from the database if a
1764     ** destination Slice has been specified.
1765     */
1766 
1767     if (am)
1768         am = ensAssemblymapperNewRef(am);
1769     else if (slice && (!ensCoordsystemMatch(
1770                            ensSliceGetCoordsystemObject(slice),
1771                            ensSliceGetCoordsystemObject(srslice))))
1772         ensAssemblymapperadaptorFetchBySlices(ama, slice, srslice, &am);
1773 
1774     /*
1775     ** Remap the Ensembl Feature coordinates to another
1776     ** Ensembl Coordinate System, if an Ensembl Assembly Mapper is defined
1777     ** at this point.
1778     */
1779 
1780     if (am)
1781     {
1782         mrs = ajListNew();
1783 
1784         ensAssemblymapperMapToSeqregion(am,
1785                                         ensSliceGetSeqregion(srslice),
1786                                         slstart,
1787                                         slend,
1788                                         slstrand,
1789                                         ensSliceGetSeqregion(slice),
1790                                         ajTrue, /* fastmap mode */
1791                                         mrs);
1792 
1793         /*
1794         ** The ensAssemblymapperMapToSeqregion function in fastmap mode
1795         ** returns at best one Ensembl Mapper Result.
1796         */
1797 
1798         ajListPeekFirst(mrs, (void **) &mr);
1799 
1800         /*
1801         ** Skip Features that map to gaps or
1802         ** Coordinate System boundaries.
1803         */
1804 
1805         if (ensMapperresultGetType(mr) != ensEMapperresultTypeCoordinate)
1806         {
1807             /* This Ensembl Feature could not be mapped successfully. */
1808 
1809             while (ajListPop(mrs, (void **) &mr))
1810                 ensMapperresultDel(&mr);
1811 
1812             ajListFree(&mrs);
1813 
1814             ensAssemblymapperDel(&am);
1815 
1816             ensSliceDel(&srslice);
1817 
1818             return ajTrue;
1819         }
1820 
1821         srid     = ensMapperresultGetObjectidentifier(mr);
1822         slstart  = ensMapperresultGetCoordinateStart(mr);
1823         slend    = ensMapperresultGetCoordinateEnd(mr);
1824         slstrand = ensMapperresultGetCoordinateStrand(mr);
1825 
1826         /*
1827         ** Replace the original Sequence Region Slice by a Slice in the
1828         ** Coordinate System just mapped to.
1829         */
1830 
1831         ensSliceDel(&srslice);
1832 
1833         ensSliceadaptorFetchBySeqregionIdentifier(sla,
1834                                                   srid,
1835                                                   0,
1836                                                   0,
1837                                                   0,
1838                                                   &srslice);
1839 
1840         while (ajListPop(mrs, (void **) &mr))
1841             ensMapperresultDel(&mr);
1842 
1843         ajListFree(&mrs);
1844     }
1845 
1846     ensAssemblymapperDel(&am);
1847 
1848     /*
1849     ** Convert Sequence Region Slice coordinates to destination Slice
1850     ** coordinates, if a destination Slice has been provided.
1851     */
1852 
1853     if (slice)
1854     {
1855         /* Check that the length of the Slice is within range. */
1856 
1857         if (ensSliceCalculateLength(slice) <= INT_MAX)
1858             sllength = (ajint) ensSliceCalculateLength(slice);
1859         else
1860             ajFatal("ensBaseadaptorRetrieveFeature got an Ensembl Slice, "
1861                     "which length (%u) exceeds the "
1862                     "maximum integer limit (%d).",
1863                     ensSliceCalculateLength(slice), INT_MAX);
1864 
1865         if (!ensSliceIsCircular(slice, &circular))
1866             return ajFalse;
1867 
1868         if (ensSliceGetStrand(slice) >= 0)
1869         {
1870             /* On the positive strand ... */
1871 
1872             slstart = slstart - ensSliceGetStart(slice) + 1;
1873             slend   = slend   - ensSliceGetStart(slice) + 1;
1874 
1875             if (
1876                 (
1877                     (slend > ensSliceGetStart(slice))
1878                     ||
1879                     (slend < 0)
1880                     ||
1881                     (
1882                         (ensSliceGetStart(slice) > ensSliceGetEnd(slice))
1883                         &&
1884                         (slend < 0)
1885                      )
1886                  )
1887                 &&
1888                 (circular == ajTrue)
1889                 )
1890             {
1891                 if (slstart > slend)
1892                 {
1893                     /* A Feature overlapping the chromsome origin. */
1894 
1895                     /* Region in the beginning of the chromosome. */
1896                     if (slend > ensSliceGetStart(slice))
1897                         slstart -= sllength;
1898 
1899                     if (slend < 0)
1900                         slend += sllength;
1901                 }
1902                 else
1903                 {
1904                     if ((ensSliceGetStart(slice) > ensSliceGetEnd(slice))
1905                         && (slend < 0))
1906                     {
1907                         /*
1908                         ** A region overlapping the chromosome origin
1909                         ** and a Feature, which is at the beginning of
1910                         ** the chromosome.
1911                         */
1912 
1913                         slstart += sllength;
1914                         slend   += sllength;
1915                     }
1916                 }
1917             }
1918         }
1919         else
1920         {
1921             /* On the negative strand ... */
1922 
1923             if ((slstart > slend) && (circular == ajTrue))
1924             {
1925                 /* Handle circular chromosomes. */
1926 
1927                 if (ensSliceGetStart(slice) > ensSliceGetEnd(slice))
1928                 {
1929                     tmpstart = slstart;
1930                     slstart = ensSliceGetEnd(slice) - slend + 1;
1931                     slend   = ensSliceGetEnd(slice) + sllength - tmpstart + 1;
1932                 }
1933                 else
1934                 {
1935                     if (slend > ensSliceGetStart(slice))
1936                     {
1937                         /*
1938                         ** Looking at the region in the beginning of the
1939                         ** chromosome.
1940                         */
1941 
1942                         slstart = ensSliceGetEnd(slice) - slend + 1;
1943                         slend   = slend - sllength - slstart + 1;
1944                     }
1945                     else
1946                     {
1947                         tmpstart = slstart;
1948                         slstart  = ensSliceGetEnd(slice) - slend - sllength + 1;
1949                         slend    = slend - tmpstart + 1;
1950                     }
1951                 }
1952             }
1953             else
1954             {
1955                 /* Non-circular Ensembl Slice objects... */
1956 
1957                 slend   = ensSliceGetEnd(slice) - slstart + 1;
1958                 slstart = ensSliceGetEnd(slice) - slend   + 1;
1959             }
1960 
1961             slstrand *= -1;
1962         }
1963 
1964         /*
1965         ** Throw away Features off the end of the requested Slice or on
1966         ** any other than the requested Slice.
1967         */
1968 
1969         if ((slend < 1) ||
1970             (slstart > sllength) ||
1971             (srid != ensSliceGetSeqregionIdentifier(slice)))
1972         {
1973             /* This Ensembl Feature could not be mapped successfully. */
1974 
1975             ensSliceDel(&srslice);
1976 
1977             return ajTrue;
1978         }
1979 
1980         /* Delete the Sequence Region Slice and set the requested Slice. */
1981 
1982         ensSliceDel(&srslice);
1983 
1984         srslice = ensSliceNewRef(slice);
1985     }
1986 
1987     if (analysisid)
1988         ensAnalysisadaptorFetchByIdentifier(ana, analysisid, &analysis);
1989 
1990     *Pfeature = ensFeatureNewIniS(analysis, srslice, slstart, slend, slstrand);
1991 
1992     ensAnalysisDel(&analysis);
1993 
1994     ensSliceDel(&srslice);
1995 
1996     return ajTrue;
1997 }
1998