00001 <?php
00002 require_once dirname(__FILE__) . '/dataobjectbase.cls.php';
00003
00004
00005
00006
00007
00008
00009
00010 class DB {
00011 const DEFAULT_CONNECTION = 'default';
00012
00013
00014
00015 const DEFAULT_CONNNECTION = 'default';
00016
00017
00018
00019
00020
00021
00022 private static $db;
00023
00024 private static $connections = array();
00025 public static $query_log = array();
00026 public static $queries_total_time = 0;
00027 public static $db_connect_time= 0;
00028
00029
00030
00031
00032
00033
00034
00035 public static function get_connection($name_or_object = self::DEFAULT_CONNECTION) {
00036 if ($name_or_object instanceof IDBDriver) {
00037 return $name_or_object;
00038 }
00039 else if (isset(self::$connections[$name_or_object])) {
00040 return self::$connections[$name_or_object];
00041 }
00042 throw new Exception("Connection $name_or_object not found");
00043 }
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 public static function create_connection($connection_name, $driver, $db_name, $db_user, $db_pwd, $db_host, $params = false) {
00058
00059 Load::directories('model/drivers/' . $driver);
00060
00061 $drivername = 'DBDriver' . ucfirst($driver);
00062 $db = new $drivername();
00063 $db->initialize($db_name, $db_user, $db_pwd, $db_host, $params);
00064 self::$connections[$connection_name] = $db;
00065
00066 return $db;
00067 }
00068
00069
00070
00071
00072
00073
00074 public static function create($model) {
00075 Load::models($model);
00076 $classname = 'DAO' . ucfirst($model);
00077 if (class_exists($classname)) {
00078 return new $classname();
00079 }
00080
00081 throw new Exception(tr('Model %s not found', 'core', array('%s' => $model)));
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091 public static function get_item_by_pk($table, $value) {
00092 $model = self::create($table);
00093
00094 $pks = $model->get_table_keys();
00095 if (count($pks) != 1) {
00096 throw new Exception(tr('No or more than 1 keys on model %s: get_item_by_pk() cannot be applied', 'core', array('%s' => $table)));
00097 }
00098 $pk_name = array_shift(array_keys($pks));
00099 return self::get_item($table, $pk_name, $value);
00100 }
00101
00102
00103
00104
00105
00106
00107 public static function get_item($table, $key, $value) {
00108 $ret = false;
00109 if (!empty($value) && !$value instanceof DBNull) {
00110 $ret = self::get_item_multi($table, array($key => $value));
00111 }
00112 return $ret;
00113 }
00114
00115
00116
00117
00118
00119
00120
00121
00122 public static function get_item_multi($table, $arr_values) {
00123 ksort($arr_values);
00124 $keys = array('db', $table, strtr(http_build_query($arr_values), '[]', '__'));
00125 $ret = RuntimeCache::get($keys, null);
00126 if (is_null($ret)) {
00127 $ret = false;
00128 $dao = self::create($table);
00129 foreach($arr_values as $col => $value) {
00130 $dao->$col = $value;
00131 }
00132 $dao->limit(1);
00133 if ($dao->find(IDataObject::AUTOFETCH)) {
00134 $ret = clone($dao);
00135 }
00136 RuntimeCache::set($keys, $ret);
00137 }
00138 return $ret;
00139 }
00140
00141
00142
00143
00144 public static function initialize() {
00145
00146 self::$db = self::create_connection(self::DEFAULT_CONNECTION, APP_DB_TYPE, APP_DB_NAME, APP_DB_USER, APP_DB_PWD, APP_DB_HOST);
00147 }
00148
00149
00150
00151
00152
00153
00154
00155 public static function escape($value, $connection = self::DEFAULT_CONNECTION) {
00156 $conn = self::get_connection($connection);
00157 return $conn->escape($value);
00158 }
00159
00160
00161
00162
00163
00164
00165 public static function escape_database_entity($obj, $connection = self::DEFAULT_CONNECTION, $type = IDBDriver::FIELD) {
00166 $conn = self::get_connection($connection);
00167 return $conn->escape_database_entity($obj, $type);
00168 }
00169
00170
00171
00172
00173
00174
00175
00176 public static function quote($val, $connection = self::DEFAULT_CONNECTION) {
00177 $conn = self::get_connection($connection);
00178 return $conn->quote($val);
00179 }
00180
00181
00182
00183
00184
00185
00186
00187
00188 public static function format($value, $table = null, $column = '') {
00189 if ($value instanceof DBExpression) {
00190 return $value->format();
00191 } else {
00192 $field = self::find_field($table, $column);
00193 return $field->format($value);
00194 }
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204 public static function format_where($value, $table = null, $column = '') {
00205 $field = self::find_field($table, $column);
00206 return $field->format_where($value);
00207 }
00208
00209
00210
00211
00212 private static function find_field($table, $column) {
00213 $field = null;
00214 if ($table) {
00215 $field = $table->get_table_field($column);
00216 }
00217 if (empty($field)) {
00218
00219 $table_and_field = explode('.', $column);
00220 if (count($table_and_field) == 2) {
00221 $forced_table = self::create($table_and_field[0]);
00222 if ($forced_table) {
00223 $field = $forced_table->get_table_field($table_and_field[1]);
00224 }
00225 }
00226 }
00227 if (empty($field)) {
00228 $field = new DBField($column);
00229 if ($table) {
00230 $field->set_connection($table->get_table_driver());
00231 }
00232 }
00233 return $field;
00234 }
00235
00236
00237
00238
00239
00240
00241
00242 public static function query($query, $connection = self::DEFAULT_CONNECTION) {
00243 $timer = new Timer();
00244 if ($query instanceof IDBQuery) {
00245 $connection = $query->get_table()->get_table_driver();
00246 $query = $query->get_sql();
00247 }
00248 $conn = self::get_connection($connection);
00249 $ret = $conn->query($query);
00250 self::log_query($query, $timer->seconds_elapsed(), $ret->get_status(), $conn);
00251 return $ret;
00252 }
00253
00254
00255
00256
00257
00258
00259
00260 public static function execute($query, $connection = self::DEFAULT_CONNECTION) {
00261 $timer = new Timer();
00262 if ($query instanceof IDBQuery) {
00263 $connection = $query->get_table()->get_table_driver();
00264 $query = $query->get_sql();
00265 }
00266 $conn = self::get_connection($connection);
00267 $ret = $conn->execute($query);
00268 self::log_query($query, $timer->seconds_elapsed(), $ret, $conn);
00269 return $ret;
00270 }
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 public static function explain($sql, $connection = self::DEFAULT_CONNECTION) {
00281 $conn = self::get_connection($connection);
00282 return $conn->explain($sql);
00283 }
00284
00285
00286
00287
00288 public static function last_insert_id($connection = self::DEFAULT_CONNECTION) {
00289 $conn = self::get_connection($connection);
00290 return $conn->last_insert_id();
00291 }
00292
00293
00294
00295
00296
00297
00298
00299 public static function execute_script($file, $connection = self::DEFAULT_CONNECTION) {
00300 $status = new Status();
00301 if (file_exists($file)) {
00302 $conn = self::get_connection($connection);
00303 $conn->make_default();
00304 $handle = fopen($file, 'r');
00305 $dao = self::create('cache');
00306 while($query = self::extract_next_sql_statement($handle)) {
00307 if ($query != ';') {
00308 $status->merge($conn->execute($query));
00309 }
00310 }
00311 fclose($handle);
00312 $def = self::get_connection();
00313 $def->make_default();
00314 }
00315 else {
00316 $status->append(tr('File %file not found', 'core', array('%file' => $file)));
00317 }
00318 return $status;
00319 }
00320
00321 public static function extract_next_sql_statement($handle) {
00322 $ret = '';
00323 $last = '';
00324 $continue = true;
00325 while ($continue) {
00326 $char = self::read_next($handle, $ret);
00327 if ($char === false) {
00328 break;
00329 }
00330
00331 switch($char) {
00332 case ';':
00333 $continue = false;
00334 break;
00335 case "'":
00336 case '"':
00337 $ret .= self::extract_until($handle, $char);
00338 break;
00339 case '#':
00340
00341 $ret = substr($ret, 0, -1);
00342 self::extract_until($handle, "\n");
00343 break;
00344 case '-':
00345
00346 if ($last == '-') {
00347 $ret = substr($ret, 0, -2);
00348 self::extract_until($handle, "\n");
00349 }
00350 break;
00351 case '*':
00352
00353 if ($last == '/') {
00354 $ret = substr($ret, 0, -2);
00355 self::extract_until($handle, "*/");
00356 }
00357 break;
00358 }
00359 $last = $char;
00360 }
00361
00362 $ret = str_replace("\n", ' ', $ret);
00363 $ret = str_replace("\r", ' ', $ret);
00364 $ret = trim($ret);
00365 return $ret;
00366 }
00367
00368 private static function extract_until($handle, $chars) {
00369 $ret = '';
00370 $s = strlen($chars);
00371 $char_compare = ($s == 1) ? $chars : substr($chars, -1);
00372 $last_compare = ($s == 1) ? false : substr($chars, 0, 1);
00373 $last = '';
00374
00375 do {
00376 $c = self::read_next($handle, $ret);
00377 if ($c === $char_compare) {
00378 if ($last_compare === false) {
00379 break;
00380 }
00381 else {
00382 if ($last === $last_compare) {
00383 break;
00384 }
00385 }
00386 }
00387 $last = $c;
00388 } while ($c !== false);
00389
00390 return $ret;
00391 }
00392
00393 private static function read_next($handle, &$result) {
00394 $c = fgetc($handle);
00395 if ($c !== false) {
00396 $result .= $c;
00397 if ($c == "\\") {
00398
00399 $c .= self::read_next($handle, $result);
00400 }
00401 }
00402 return $c;
00403 }
00404
00405 public static function start_trans($connection = self::DEFAULT_CONNECTION) {
00406 $conn = self::get_connection($connection);
00407 $conn->trans_start();
00408 }
00409
00410 public static function end_trans($status, $connection = self::DEFAULT_CONNECTION) {
00411 if ($status->is_ok()) {
00412 self::commit($connection);
00413 }
00414 else {
00415 self::rollback($connection);
00416 }
00417 }
00418
00419 public static function commit($connection = self::DEFAULT_CONNECTION) {
00420 $conn = self::get_connection($connection);
00421 $conn->trans_commit();
00422 }
00423
00424 public static function rollback($connection = self::DEFAULT_CONNECTION) {
00425 $conn = self::get_connection($connection);
00426 $conn->trans_rollback();
00427 }
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437 public static function log_query($query, $seconds, $status, $conn = self::DEFAULT_CONNECTION) {
00438 if (Config::has_feature(Config::LOG_QUERIES)) {
00439 $c = self::get_connection($conn);
00440 $log = array(
00441 'query' => $query,
00442 'seconds' => $seconds,
00443 'success' => $status->is_ok(),
00444 'message' => $status->to_string(Status::OUTPUT_PLAIN)
00445 );
00446 Load::components('logger');
00447 Logger::log('queries', $log);
00448
00449 $log['connection'] = $c;
00450 self::$query_log[] = $log;
00451 self::$queries_total_time += $seconds;
00452 }
00453
00454 if (Config::has_feature(Config::LOG_SLOW_QUERIES)) {
00455 if ($seconds > Config::get_value(Config::DB_SLOW_QUERY_THRESHOLD, false, 0.0100)) {
00456 $log = array(
00457 'query' => $query,
00458 'seconds' => $seconds,
00459 );
00460 Load::components('logger');
00461 Logger::log('slow_queries', $log);
00462 }
00463 }
00464
00465 if ($status->is_error()) {
00466 if (Config::has_feature(Config::LOG_FAILED_QUERIES)) {
00467 $log = array(
00468 'query' => $query,
00469 'message' => $status->to_string(Status::OUTPUT_PLAIN)
00470 );
00471 Load::components('logger');
00472 Logger::log('failed_queries', $log);
00473 }
00474 if (Config::has_feature(Config::THROW_ON_DB_ERROR)) {
00475 $text = $status->to_string(Status::OUTPUT_PLAIN) . " [$query]";
00476 throw new Exception($text);
00477 }
00478 }
00479 }
00480 }