Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
/**
3
 * ADOdb Load Balancer
4
 *
5
 * ADOdbLoadBalancer is a class that allows the user to do read/write splitting
6
 * and load balancing across multiple servers. It can handle and load balance
7
 * any number of write capable (AKA: master) or readonly (AKA: slave) connections,
8
 * including dealing with connection failures and retrying queries on a different
9
 * connection instead.
10
 *
11
 * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
12
 *
13
 * @package ADOdb
14
 * @link https://adodb.org Project's web site and documentation
15
 * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
16
 *
17
 * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
18
 * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
19
 * any later version. This means you can use it in proprietary products.
20
 * See the LICENSE.md file distributed with this source code for details.
21
 * @license BSD-3-Clause
22
 * @license LGPL-2.1-or-later
23
 *
24
 * @copyright 2016 Mike Benoit and the ADOdb community
25
 */
26
 
27
/**
28
 * Class ADOdbLoadBalancer
29
 */
30
class ADOdbLoadBalancer
31
{
32
    /**
33
     * @var bool    Once a write or readonly connection is made, stick to that connection for the entire request.
34
     */
35
    public $enable_sticky_sessions = true;
36
 
37
 
38
    /**
39
     * @var bool|array    All connections to each database.
40
     */
41
    protected $connections = [];
42
 
43
    /**
44
     * @var bool|array    Just connections to the write capable database.
45
     */
46
    protected $connections_write = [];
47
 
48
    /**
49
     * @var bool|array    Just connections to the readonly database.
50
     */
51
    protected $connections_readonly = [];
52
 
53
    /**
54
     * @var array    Counts of all connections and their types.
55
     */
56
    protected $total_connections = array('all' => 0, 'write' => 0, 'readonly' => 0);
57
 
58
    /**
59
     * @var array    Weights of all connections for each type.
60
     */
61
    protected $total_connection_weights = array('all' => 0, 'write' => 0, 'readonly' => 0);
62
 
63
    /**
64
     * @var bool    When in transactions, always use this connection.
65
     */
66
    protected $pinned_connection_id = false;
67
 
68
    /**
69
     * @var array    Last connection_id for each database type.
70
     */
71
    protected $last_connection_id = array('write' => false, 'readonly' => false, 'all' => false);
72
 
73
    /**
74
     * @var bool    Session variables that must be maintained across all connections, ie: SET TIME ZONE.
75
     */
76
    protected $session_variables = [];
77
 
78
    /**
79
     * @var bool    Called immediately after connecting to any DB.
80
     */
81
    protected $user_defined_session_init_sql = [];
82
 
83
 
84
    /**
85
     * Defines SQL queries that are executed each time a new database connection is established.
86
     *
87
     * @param  $sql
88
     * @return bool
89
     */
90
    public function setSessionInitSQL($sql)
91
    {
92
        $this->user_defined_session_init_sql[] = $sql;
93
 
94
        return true;
95
    }
96
 
97
    /**
98
     * Adds a new database connection to the pool, but no actual connection is made until its needed.
99
     *
100
     * @param  $obj
101
     * @return bool
102
     * @throws Exception
103
     */
104
    public function addConnection($obj)
105
    {
106
        if ($obj instanceof ADOdbLoadBalancerConnection) {
107
            $this->connections[] = $obj;
108
            end($this->connections);
109
            $i = key($this->connections);
110
 
111
            $this->total_connections[$obj->type]++;
112
            $this->total_connections['all']++;
113
 
114
            $this->total_connection_weights[$obj->type] += abs($obj->weight);
115
            $this->total_connection_weights['all'] += abs($obj->weight);
116
 
117
            if ($obj->type == 'write') {
118
                $this->connections_write[] = $i;
119
            } else {
120
                $this->connections_readonly[] = $i;
121
            }
122
 
123
            return true;
124
        }
125
 
126
        throw new Exception('Connection object is not an instance of ADOdbLoadBalancerConnection');
127
    }
128
 
129
    /**
130
     * Removes a database connection from the pool.
131
     *
132
     * @param  $i
133
     * @return bool
134
     */
135
    public function removeConnection($i)
136
    {
137
        if (isset($this->connections[$i])) {
138
               $obj = $this->connections[ $i ];
139
 
140
               $this->total_connections[ $obj->type ]--;
141
               $this->total_connections['all']--;
142
 
143
               $this->total_connection_weights[ $obj->type ] -= abs($obj->weight);
144
               $this->total_connection_weights['all'] -= abs($obj->weight);
145
 
146
            if ($obj->type == 'write') {
147
                unset($this->connections_write[array_search($i, $this->connections_write)]);
148
                // Reindex array.
149
                $this->connections_write = array_values($this->connections_write);
150
            } else {
151
                unset($this->connections_readonly[array_search($i, $this->connections_readonly)]);
152
                // Reindex array.
153
                $this->connections_readonly = array_values($this->connections_readonly);
154
            }
155
 
156
            // Remove any sticky connections as well.
157
            if ($this->last_connection_id[$obj->type] == $i) {
158
                $this->last_connection_id[$obj->type] = false;
159
            }
160
 
161
            unset($this->connections[$i]);
162
 
163
            return true;
164
        }
165
 
166
        return false;
167
    }
168
 
169
    /**
170
     * Returns a database connection of the specified type.
171
     *
172
     * Takes into account the connection weight for load balancing.
173
     *
174
     * @param  string $type Type of database connection, either: 'write' capable or 'readonly'
175
     * @return bool|int|string
176
     */
177
    public function getConnectionByWeight($type)
178
    {
179
        if ($type == 'readonly') {
180
            $total_weight = $this->total_connection_weights['all'];
181
        } else {
182
            $total_weight = $this->total_connection_weights['write'];
183
        }
184
 
185
        $i = false;
186
        if (is_array($this->connections)) {
187
            $n = 0;
188
            $num = mt_rand(0, $total_weight);
189
            foreach ($this->connections as $i => $connection_obj) {
190
                if ($connection_obj->weight > 0 && ($type == 'readonly' || $connection_obj->type == 'write')) {
191
                    $n += $connection_obj->weight;
192
                    if ($n >= $num) {
193
                        break;
194
                    }
195
                }
196
            }
197
        }
198
 
199
        return $i;
200
    }
201
 
202
    /**
203
     * Returns the proper database connection when taking into account sticky sessions and load balancing.
204
     *
205
     * @param  $type
206
     * @return bool|int|mixed|string
207
     */
208
    public function getLoadBalancedConnection($type)
209
    {
210
        if ($this->total_connections == 0) {
211
            $connection_id = 0;
212
        } else {
213
            if ($this->enable_sticky_sessions == true && $this->last_connection_id[$type] !== false) {
214
                $connection_id = $this->last_connection_id[$type];
215
            } else {
216
                if ($type == 'write' && $this->total_connections['write'] == 1) {
217
                    $connection_id = $this->connections_write[0];
218
                } else {
219
                    $connection_id = $this->getConnectionByWeight($type);
220
                }
221
            }
222
        }
223
 
224
        return $connection_id;
225
    }
226
 
227
    /**
228
     * Returns the ADODB connection object by connection_id.
229
     *
230
     * Ensures that it's connected and the session variables are executed.
231
     *
232
     * @param  $connection_id
233
     * @return bool|ADOConnection
234
     * @throws Exception
235
     */
236
    public function getConnectionById($connection_id)
237
    {
238
        if (isset($this->connections[$connection_id])) {
239
            $connection_obj = $this->connections[$connection_id];
240
            /** @var ADOConnection $adodb_obj */
241
            $adodb_obj = $connection_obj->getADOdbObject();
242
            if (is_object($adodb_obj) && $adodb_obj->_connectionID == false) {
243
                try {
244
                    if ($connection_obj->persistent_connection == true) {
245
                        $adodb_obj->Pconnect(
246
                            $connection_obj->host,
247
                            $connection_obj->user,
248
                            $connection_obj->password,
249
                            $connection_obj->database
250
                        );
251
                    } else {
252
                        $adodb_obj->Connect(
253
                            $connection_obj->host,
254
                            $connection_obj->user,
255
                            $connection_obj->password,
256
                            $connection_obj->database
257
                        );
258
                    }
259
                } catch (Exception $e) {
260
                    // Connection error, see if there are other connections to try still.
261
                    throw $e; // No connections left, reThrow exception so application can catch it.
262
                }
263
 
264
                // Check to see if a connection test callback was defined, and if so execute it.
265
                // This is useful for testing replication lag and such to ensure the connection is suitable to be used.
266
                $test_connection_callback = $connection_obj->getConnectionTestCallback();
267
                if (is_callable($test_connection_callback)
268
                    && $test_connection_callback($connection_obj, $adodb_obj) !== TRUE
269
                ) {
270
                    return false;
271
                }
272
 
273
                if (is_array($this->user_defined_session_init_sql)) {
274
                    foreach ($this->user_defined_session_init_sql as $session_init_sql) {
275
                        $adodb_obj->Execute($session_init_sql);
276
                    }
277
                }
278
                $this->executeSessionVariables($adodb_obj);
279
            }
280
 
281
            return $adodb_obj;
282
        } else {
283
            throw new Exception('Unable to return Connection object...');
284
        }
285
    }
286
 
287
    /**
288
     * Returns the ADODB connection object by database type.
289
     *
290
     * Ensures that it's connected and the session variables are executed.
291
     *
292
     * @param  string $type
293
     * @param  null   $pin_connection
294
     * @return ADOConnection|bool
295
     * @throws Exception
296
     */
297
    public function getConnection($type = 'write', $pin_connection = null)
298
    {
299
        while (($type == 'write' && $this->total_connections['write'] > 0)
300
            || ($type == 'readonly' && $this->total_connections['all'] > 0)
301
        ) {
302
            if ($this->pinned_connection_id !== false) {
303
                $connection_id = $this->pinned_connection_id;
304
            } else {
305
                $connection_id = $this->getLoadBalancedConnection($type);
306
            }
307
 
308
            if ($connection_id !== false) {
309
                try {
310
                    $adodb_obj = $this->getConnectionById($connection_id);
311
                    if (is_object($adodb_obj)) {
312
                        break; //Found valid connection, continue with it.
313
                    } else {
314
                        throw new Exception('ADODB Connection Object does not exist. Perhaps LoadBalancer Database Connection Test Failed?');
315
                    }
316
                } catch (Exception $e) {
317
                    // Connection error, see if there are other connections to try still.
318
                    $this->removeConnection($connection_id);
319
                    if (   ($type == 'write' && $this->total_connections['write'] == 0)
320
                        || ($type == 'readonly' && $this->total_connections['all'] == 0)
321
                    ) {
322
                        throw $e;
323
                    }
324
                }
325
            } else {
326
                throw new Exception('Connection ID is invalid!');
327
            }
328
        }
329
 
330
        if (!isset($connection_id)) {
331
            throw new Exception('No connection available to use at this time! Type: ' . $type);
332
        }
333
 
334
        $this->last_connection_id[$type] = $connection_id;
335
 
336
        if ($pin_connection === true) {
337
            $this->pinned_connection_id = $connection_id;
338
        } elseif ($pin_connection === false && $adodb_obj->transOff <= 1) {
339
            // UnPin connection only if we are 1 level deep in a transaction.
340
            $this->pinned_connection_id = false;
341
 
342
            // When unpinning connection, reset last_connection_id so readonly
343
            // queries don't get stuck on the write capable connection.
344
            $this->last_connection_id['write'] = false;
345
            $this->last_connection_id['readonly'] = false;
346
        }
347
 
348
        return $adodb_obj;
349
    }
350
 
351
    /**
352
     * This is a hack to work around pass by reference error.
353
     *
354
     * Parameter 1 to ADOConnection::GetInsertSQL() expected to be a reference,
355
     * value given in adodb-loadbalancer.inc.php on line 83
356
     *
357
     * @param  $arr
358
     * @return array
359
     */
360
    private function makeValuesReferenced($arr)
361
    {
362
        $refs = array();
363
 
364
        foreach ($arr as $key => $value) {
365
            $refs[$key] = &$arr[$key];
366
        }
367
 
368
        return $refs;
369
    }
370
 
371
    /**
372
     * Allow setting session variables that are maintained across connections.
373
     *
374
     * Its important that these are set using name/value, so it can determine
375
     * if the same variable is set multiple times causing bloat/clutter when
376
     * new connections are established. For example if the time_zone is set to
377
     * many different ones through the course of a single connection, a new
378
     * connection should only set it to the most recent value.
379
     *
380
     * @param  $name
381
     * @param  $value
382
     * @param  bool  $execute_immediately
383
     * @return array|bool|mixed
384
     * @throws Exception
385
     */
386
    public function setSessionVariable($name, $value, $execute_immediately = true)
387
    {
388
        $this->session_variables[$name] = $value;
389
 
390
        if ($execute_immediately == true) {
391
            return $this->executeSessionVariables();
392
        } else {
393
            return true;
394
        }
395
    }
396
 
397
    /**
398
     * Executes the session variables on a given ADODB object.
399
     *
400
     * @param  ADOConnection|bool $adodb_obj
401
     * @return array|bool|mixed
402
     * @throws Exception
403
     */
404
    private function executeSessionVariables($adodb_obj = false)
405
    {
406
        if (is_array($this->session_variables) && count($this->session_variables) > 0) {
407
            $sql = '';
408
            foreach ($this->session_variables as $name => $value) {
409
                // $sql .= 'SET SESSION '. $name .' '. $value;
410
                // MySQL uses: SET SESSION foo_bar='foo'
411
                // PGSQL uses: SET SESSION foo_bar 'foo'
412
                // So leave it up to the user to pass the proper value with '=' if needed.
413
                // This may be a candidate to move into ADOdb proper.
414
                $sql .= 'SET SESSION ' . $name . ' ' . $value;
415
            }
416
 
417
            if ($adodb_obj !== false) {
418
                return $adodb_obj->Execute($sql);
419
            } else {
420
                return $this->ClusterExecute($sql);
421
            }
422
        }
423
 
424
        return false;
425
    }
426
 
427
    /**
428
     * Executes the same SQL QUERY on the entire cluster of connections.
429
     * Would be used for things like SET SESSION TIME ZONE calls and such.
430
     *
431
     * @param  $sql
432
     * @param  bool $inputarr
433
     * @param  bool $return_all_results
434
     * @param  bool $existing_connections_only
435
     * @return array|bool|mixed
436
     * @throws Exception
437
     */
438
    public function clusterExecute(
439
        $sql,
440
        $inputarr = false,
441
        $return_all_results = false,
442
        $existing_connections_only = true
443
    ) {
444
        if (is_array($this->connections) && count($this->connections) > 0) {
445
            foreach ($this->connections as $key => $connection_obj) {
446
                if ($existing_connections_only == false
447
                    || ($existing_connections_only == true
448
                        && $connection_obj->getADOdbObject()->_connectionID !== false
449
                    )
450
                ) {
451
                    $adodb_obj = $this->getConnectionById($key);
452
                    if (is_object($adodb_obj)) {
453
                        $result_arr[] = $adodb_obj->Execute($sql, $inputarr);
454
                    }
455
                }
456
            }
457
 
458
            if (isset($result_arr) && $return_all_results == true) {
459
                return $result_arr;
460
            } else {
461
                // Loop through all results checking to see if they match, if they do return the first one
462
                // otherwise return an array of all results.
463
                if (isset($result_arr)) {
464
                    foreach ($result_arr as $result) {
465
                        if ($result == false) {
466
                            return $result_arr;
467
                        }
468
                    }
469
 
470
                    return $result_arr[0];
471
                } else {
472
                    // When using lazy connections, there are cases where
473
                    // setSessionVariable() is called early on, but there are
474
                    // no connections to execute the queries on yet.
475
                    // This captures that case and forces a RETURN TRUE to occur.
476
                    // As likely the queries will be executed as soon as a
477
                    // connection is established.
478
                    return true;
479
                }
480
            }
481
        }
482
 
483
        return false;
484
    }
485
 
486
    /**
487
     * Determines if a SQL query is read-only or not.
488
     *
489
     * @param  string $sql SQL Query to test.
490
     * @return bool
491
     */
492
    public function isReadOnlyQuery($sql)
493
    {
494
        if (   stripos($sql, 'SELECT') === 0
495
            && stripos($sql, 'FOR UPDATE') === false
496
            && stripos($sql, ' INTO ') === false
497
            && stripos($sql, 'LOCK IN') === false
498
        ) {
499
            return true;
500
        }
501
 
502
        return false;
503
    }
504
 
505
    /**
506
     * Use this instead of __call() as it significantly reduces the overhead of call_user_func_array().
507
     *
508
     * @param  $sql
509
     * @param  bool $inputarr
510
     * @return array|bool|mixed
511
     * @throws Exception
512
     */
513
    public function execute($sql, $inputarr = false)
514
    {
515
        $type = 'write';
516
        $pin_connection = null;
517
 
518
        // Prevent leading spaces from causing isReadOnlyQuery/stripos from failing.
519
        $sql = trim($sql);
520
 
521
        // SELECT queries that can write and therefore must be run on a write capable connection.
522
        // SELECT ... FOR UPDATE;
523
        // SELECT ... INTO ...
524
        // SELECT .. LOCK IN ... (MYSQL)
525
        if ($this->isReadOnlyQuery($sql) == true) {
526
            $type = 'readonly';
527
        } elseif (stripos($sql, 'SET') === 0) {
528
            // SET SQL statements should likely use setSessionVariable() instead,
529
            // so state is properly maintained across connections, especially when they are lazily created.
530
            return $this->ClusterExecute($sql, $inputarr);
531
        }
532
 
533
        $adodb_obj = $this->getConnection($type, $pin_connection);
534
        if ($adodb_obj !== false) {
535
            return $adodb_obj->Execute($sql, $inputarr);
536
        }
537
 
538
        return false;
539
    }
540
 
541
    /**
542
     * Magic method to intercept method and callback to the proper ADODB object for write/readonly connections.
543
     *
544
     * @param  string $method ADODB method to call.
545
     * @param  array  $args   Arguments to the ADODB method.
546
     * @return bool|mixed
547
     * @throws Exception
548
     */
549
    public function __call($method, $args)
550
    {
551
        $type = 'write';
552
        $pin_connection = null;
553
 
554
        // Intercept specific methods to determine if they are read-only or not.
555
        $method = strtolower($method);
556
        switch ($method) {
557
            // case 'execute': // This is the direct overloaded function above instead.
558
            case 'getone':
559
            case 'getrow':
560
            case 'getall':
561
            case 'getcol':
562
            case 'getassoc':
563
            case 'selectlimit':
564
                if ($this->isReadOnlyQuery(trim($args[0])) == true) {
565
                    $type = 'readonly';
566
                }
567
                break;
568
            case 'cachegetone':
569
            case 'cachegetrow':
570
            case 'cachegetall':
571
            case 'cachegetcol':
572
            case 'cachegetassoc':
573
            case 'cacheexecute':
574
            case 'cacheselect':
575
            case 'pageexecute':
576
            case 'cachepageexecute':
577
                $type = 'readonly';
578
                break;
579
                // case 'ignoreerrors':
580
                // 	// When ignoreerrors is called, PIN to the connection until its called again.
581
                // 	if (!isset($args[0]) || (isset($args[0]) && $args[0] == FALSE)) {
582
                // 		$pin_connection = TRUE;
583
                // 	} else {
584
                // 		$pin_connection = FALSE;
585
                // 	}
586
                // 	break;
587
 
588
                // Manual transactions
589
            case 'begintrans':
590
            case 'settransactionmode':
591
                    $pin_connection = true;
592
                break;
593
            case 'rollbacktrans':
594
            case 'committrans':
595
                $pin_connection = false;
596
                break;
597
                // Smart transactions
598
            case 'starttrans':
599
                $pin_connection = true;
600
                break;
601
            case 'completetrans':
602
            case 'failtrans':
603
                // getConnection() will only unpin the transaction if we're exiting the last nested transaction
604
                $pin_connection = false;
605
                break;
606
 
607
            // Functions that don't require any connection and therefore
608
            // shouldn't force a connection be established before they run.
609
            case 'qstr':
610
            case 'escape':
611
            case 'binddate':
612
            case 'bindtimestamp':
613
            case 'setfetchmode':
614
            case 'setcustommetatype':
615
                  $type = false; // No connection necessary.
616
                break;
617
 
618
            // Default to assuming write connection is required to be on the safe side.
619
            default:
620
                break;
621
        }
622
 
623
        if ($type === false) {
624
            if (is_array($this->connections) && count($this->connections) > 0) {
625
                foreach ($this->connections as $key => $connection_obj) {
626
                    $adodb_obj = $connection_obj->getADOdbObject();
627
                    return call_user_func_array(array($adodb_obj, $method), $this->makeValuesReferenced($args)); // Just makes the function call on the first object.
628
                }
629
            }
630
        } else {
631
               $adodb_obj = $this->getConnection($type, $pin_connection);
632
            if (is_object($adodb_obj)) {
633
                $result = call_user_func_array(array($adodb_obj, $method), $this->makeValuesReferenced($args));
634
 
635
                return $result;
636
            }
637
        }
638
        return false;
639
    }
640
 
641
    /**
642
     * Magic method to proxy property getter calls back to the proper ADODB object currently in use.
643
     *
644
     * @param  $property
645
     * @return mixed
646
     * @throws Exception
647
     */
648
    public function __get($property)
649
    {
650
        if (is_array($this->connections) && count($this->connections) > 0) {
651
            foreach ($this->connections as $key => $connection_obj) {
652
                // Just returns the property from the first object.
653
                return $connection_obj->getADOdbObject()->$property;
654
            }
655
        }
656
 
657
        return false;
658
    }
659
 
660
    /**
661
     * Magic method to proxy property setter calls back to the proper ADODB object currently in use.
662
     *
663
     * @param  $property
664
     * @param  $value
665
     * @return mixed
666
     * @throws Exception
667
     */
668
    public function __set($property, $value)
669
    {
670
        // Special function to set object properties on all objects
671
        // without initiating a connection to the database.
672
        if (is_array($this->connections) && count($this->connections) > 0) {
673
            foreach ($this->connections as $key => $connection_obj) {
674
                $connection_obj->getADOdbObject()->$property = $value;
675
            }
676
 
677
               return true;
678
        }
679
 
680
        return false;
681
    }
682
 
683
    /**
684
     *  Override the __clone() magic method.
685
     */
686
    private function __clone()
687
    {
688
    }
689
}
690
 
691
/**
692
 * Class ADOdbLoadBalancerConnection
693
 */
694
class ADOdbLoadBalancerConnection
695
{
696
    /**
697
     * @var bool    ADOdb drive name.
698
     */
699
    protected $driver = false;
700
 
701
    /**
702
     * @var bool    ADODB object.
703
     */
704
    protected $adodb_obj = false;
705
 
706
    /**
707
     * @var callable    Closure
708
     */
709
    protected $connection_test_callback = NULL;
710
 
711
    /**
712
     * @var string    Type of connection, either 'write' capable or 'readonly'
713
     */
714
    public $type = 'write';
715
 
716
    /**
717
     * @var int        Weight of connection, lower receives less queries, higher receives more queries.
718
     */
719
    public $weight = 1;
720
 
721
    /**
722
     * @var bool    Determines if the connection persistent.
723
     */
724
    public $persistent_connection = false;
725
 
726
    /**
727
     * @var string    Database connection host
728
     */
729
    public $host = '';
730
 
731
    /**
732
     * @var string    Database connection user
733
     */
734
    public $user = '';
735
 
736
    /**
737
     * @var string    Database connection password
738
     */
739
    public $password = '';
740
 
741
    /**
742
     * @var string    Database connection database name
743
     */
744
    public $database = '';
745
 
746
    /**
747
     * ADOdbLoadBalancerConnection constructor to setup the ADODB object.
748
     *
749
     * @param $driver
750
     * @param string $type
751
     * @param int    $weight
752
     * @param bool   $persistent_connection
753
     * @param string $argHostname
754
     * @param string $argUsername
755
     * @param string $argPassword
756
     * @param string $argDatabaseName
757
     */
758
    public function __construct(
759
        $driver,
760
        $type = 'write',
761
        $weight = 1,
762
        $persistent_connection = false,
763
        $argHostname = '',
764
        $argUsername = '',
765
        $argPassword = '',
766
        $argDatabaseName = ''
767
    ) {
768
        if ($type !== 'write' && $type !== 'readonly') {
769
            return false;
770
        }
771
 
772
        $this->adodb_obj = ADONewConnection($driver);
773
 
774
        $this->type = $type;
775
        $this->weight = $weight;
776
        $this->persistent_connection = $persistent_connection;
777
 
778
        $this->host = $argHostname;
779
        $this->user = $argUsername;
780
        $this->password = $argPassword;
781
        $this->database = $argDatabaseName;
782
 
783
        return true;
784
    }
785
 
786
    /**
787
     * Anonymous function that is called and must return TRUE for the connection to be usable.*
788
     *   The first argument is the type of connection to test.
789
     *   Useful to check things like replication lag.
790
     * @param callable $callback
791
     * @return void
792
     */
793
    function setConnectionTestCallback($callback) {
794
        $this->connection_test_callback = $callback;
795
    }
796
 
797
    /**
798
     * @return callable|null
799
     */
800
    function getConnectionTestCallback() {
801
        return $this->connection_test_callback;
802
    }
803
 
804
    /**
805
     * Returns the ADODB object for this connection.
806
     *
807
     * @return bool
808
     */
809
    public function getADOdbObject()
810
    {
811
        return $this->adodb_obj;
812
    }
813
}