/** * Important: YOU HAVE TO make sure $tables and $where_conds don't contain * unescaped user-supplied data! */ public static function get_set($tables, $joins, $where_conds, $min_store, $ref_max_age) { # Compute the "params hash". $params_hash = md5(serialize(array($tables, $joins, $where_conds))); # Check if there exists an entry for this hash, which also meets the # given freshness criteria. list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age); if ($set_id === null) { # To avoid generating the same results by multiple threads at once # (the "tile" method uses the "save" method, so the problem is # quite real!), we will acquire a write-lock here. $lock = OkapiLock::get("search-results-writer"); $lock->acquire(); try { # Make sure we were the first to acquire the lock. list($set_id, $date_created, $expires) = self::find_param_set($params_hash, $ref_max_age); if ($set_id === null) { # We are in the first thread which have acquired the lock. # We will proceed with result-set creation. Other threads # will be waiting until we finish. Db::execute("\n insert into okapi_search_sets (params_hash, date_created, expires)\n values (\n 'processing in progress',\n now(),\n date_add(now(), interval '" . mysql_real_escape_string($min_store + 60) . "' second)\n )\n "); $set_id = Db::last_insert_id(); $date_created = time(); $expires = $date_created + $min_store + 60; Db::execute("\n insert into okapi_search_results (set_id, cache_id)\n select distinct\n '" . mysql_real_escape_string($set_id) . "',\n caches.cache_id\n from\n " . implode(", ", $tables) . "\n " . implode(" ", $joins) . "\n where (" . implode(") and (", $where_conds) . ")\n "); # Lock barrier, to make sure the data is visible by other # sessions. See http://bugs.mysql.com/bug.php?id=36618 Db::execute("lock table okapi_search_results write"); Db::execute("unlock tables"); Db::execute("\n update okapi_search_sets\n set params_hash = '" . mysql_real_escape_string($params_hash) . "'\n where id = '" . mysql_real_escape_string($set_id) . "'\n "); } else { # Some other thread acquired the lock before us and it has # generated the result set. We don't need to do anything. } $lock->release(); } catch (Exception $e) { # SQL error? Make sure the lock is released and rethrow. $lock->release(); throw $e; } } # If we got an old set, we may need to expand its lifetime in order to # meet user's "min_store" criterium. if (time() + $min_store > $expires) { Db::execute("\n update okapi_search_sets\n set expires = date_add(now(), interval '" . mysql_real_escape_string($min_store + 60) . "' second)\n where id = '" . mysql_real_escape_string($set_id) . "'\n "); } return array('set_id' => "{$set_id}", 'generated_at' => date('c', $date_created), 'expires' => date('c', $expires)); }
private static function insert_log_row($consumer_key, $cache_internal_id, $user_internal_id, $logtype, $when, $formatted_comment, $text_html, $needs_maintenance2) { if (Settings::get('OC_BRANCH') == 'oc.de') { $needs_maintenance_field_SQL = ', needs_maintenance'; if ($needs_maintenance2 == 'true') { $needs_maintenance_SQL = ',2'; } else { if ($needs_maintenance2 == 'false') { $needs_maintenance_SQL = ',1'; } else { // 'null' $needs_maintenance_SQL = ',0'; } } } else { $needs_maintenance_field_SQL = ''; $needs_maintenance_SQL = ''; } $log_uuid = Okapi::create_uuid(); Db::execute("\n insert into cache_logs (\n uuid, cache_id, user_id, type, date, text, text_html,\n last_modified, date_created, node" . $needs_maintenance_field_SQL . "\n ) values (\n '" . Db::escape_string($log_uuid) . "',\n '" . Db::escape_string($cache_internal_id) . "',\n '" . Db::escape_string($user_internal_id) . "',\n '" . Db::escape_string(Okapi::logtypename2id($logtype)) . "',\n from_unixtime('" . Db::escape_string($when) . "'),\n '" . Db::escape_string($formatted_comment) . "',\n '" . Db::escape_string($text_html) . "',\n now(),\n now(),\n '" . Db::escape_string(Settings::get('OC_NODE_ID')) . "'\n " . $needs_maintenance_SQL . "\n );\n "); $log_internal_id = Db::last_insert_id(); # Store additional information on consumer_key which has created this log entry. # (Maybe we'll want to display this somewhen later.) Db::execute("\n insert into okapi_submitted_objects (object_type, object_id, consumer_key)\n values (\n " . Okapi::OBJECT_TYPE_CACHE_LOG . ",\n '" . Db::escape_string($log_internal_id) . "',\n '" . Db::escape_string($consumer_key) . "'\n );\n "); return $log_uuid; }
private static function insert_log_row($consumer_key, $cache_internal_id, $user_internal_id, $logtype, $when, $formatted_comment, $text_html) { $log_uuid = self::create_uuid(); Db::execute("\n insert into cache_logs (uuid, cache_id, user_id, type, date, text, text_html, last_modified, date_created, node)\n values (\n '" . mysql_real_escape_string($log_uuid) . "',\n '" . mysql_real_escape_string($cache_internal_id) . "',\n '" . mysql_real_escape_string($user_internal_id) . "',\n '" . mysql_real_escape_string(Okapi::logtypename2id($logtype)) . "',\n from_unixtime('" . mysql_real_escape_string($when) . "'),\n '" . mysql_real_escape_string($formatted_comment) . "',\n '" . mysql_real_escape_string($text_html) . "',\n now(),\n now(),\n '" . mysql_real_escape_string(Settings::get('OC_NODE_ID')) . "'\n );\n "); $log_internal_id = Db::last_insert_id(); # Store additional information on consumer_key which have created this log entry. # (Maybe we'll want to display this somewhere later.) Db::execute("\n insert into okapi_cache_logs (log_id, consumer_key)\n values (\n '" . mysql_real_escape_string($log_internal_id) . "',\n '" . mysql_real_escape_string($consumer_key) . "'\n );\n "); return $log_uuid; }
private static function db_insert_image($consumer_key, $user_id, $log_internal_id, $image_uuid, $position, $caption, $is_spoiler, $file_ext) { require_once 'log_images_common.inc.php'; list($position, $seq, $log_images_count) = LogImagesCommon::prepare_position($log_internal_id, $position, +1); # For OCDE the pictures table is write locked now. # Transactions do not work on OCDE MyISAM tables. However, the worst # thing that can happen on OCDE is creating a sequence number gap, # which is allowed. # # For OCPL InnoDB tables, the transactions DO and MUST work, because # we write to two dependent tables. Db::execute('start transaction'); # shift positions of existing images to make space for the new one if ($position < $log_images_count && Settings::get('OC_BRANCH') == 'oc.de') { Db::execute("\n update pictures\n set seq = seq + 1\n where\n object_type = 1\n and object_id = '" . Db::escape_string($log_internal_id) . "'\n and seq >= '" . Db::escape_string($seq) . "'\n order by seq desc\n "); } if (Settings::get('OC_BRANCH') == 'oc.de') { $local_fields_SQL = "seq"; $local_values_escaped_SQL = "'" . Db::escape_string($seq) . "'"; # All other fields are set by trigger or defaults for OCDE. } else { # These are the additional fields that OCPL newpic.php supplies # (seq is set from default): $local_fields_SQL = "date_created, last_modified, description, desc_html, last_url_check, user_id"; $local_values_escaped_SQL = "NOW(), NOW(), '', 0, NOW(), '" . Db::escape_string($user_id) . "'"; } Db::execute("\n insert into pictures (\n uuid, node, local, title, spoiler, url, object_type, object_id,\n unknown_format, display,\n " . $local_fields_SQL . "\n )\n values (\n '" . Db::escape_string($image_uuid) . "',\n '" . Db::escape_string(Settings::get('OC_NODE_ID')) . "',\n 1,\n '" . Db::escape_string($caption) . "',\n '" . ($is_spoiler == 'true' ? 1 : 0) . "',\n '" . Db::escape_string(Settings::get('IMAGES_URL') . $image_uuid . $file_ext) . "',\n 1,\n '" . Db::escape_string($log_internal_id) . "',\n 0,\n 1,\n " . $local_values_escaped_SQL . "\n )\n "); $image_internal_id = Db::last_insert_id(); # update OCPL log entry properties; OCDE does everything necessary by triggers if (Settings::get('OC_BRANCH') == 'oc.pl') { # This will also update cache_logs.okapi_syncbase, so that replication # can output the updated log entry with one image less. For OCDE # that's done by DB triggers. Db::execute("\n update cache_logs\n set\n picturescount = picturescount + 1,\n last_modified = NOW()\n where id = '" . Db::escape_string($log_internal_id) . "'\n "); } # Store information on the consumer_key which uploaded this image. # (Maybe we'll want to display this somewhen later.) Db::execute("\n insert into okapi_submitted_objects (object_type, object_id, consumer_key)\n values (\n '" . Okapi::OBJECT_TYPE_CACHE_LOG_IMAGE . "',\n '" . Db::escape_string($image_internal_id) . "',\n '" . Db::escape_string($consumer_key) . "'\n );\n "); Db::execute('commit'); Db::execute('unlock tables'); return $position; }