Bug #21017 » 0011903_v4.patch

Administrator Admin, 2009-09-18 16:55

View differences:

tests/t3lib/cache/backend/t3lib_cache_backend_dbbackendtestcase.php (Arbeitskopie)
63 63
	protected $backend;
64 64

  
65 65
	protected $testingCacheTable;
66
	protected $testingTagsTable;
66 67

  
67 68
	/**
68 69
	 * Sets up this testcase
......
72 73
	 */
73 74
	public function setUp() {
74 75
		$this->testingCacheTable = 'test_cache_dbbackend';
76
		$this->testingTagsTable = 'test_cache_dbbackend_tags';
75 77

  
76 78
		$GLOBALS['TYPO3_DB']->sql_query('CREATE TABLE ' . $this->testingCacheTable . ' (
77 79
			id int(11) unsigned NOT NULL auto_increment,
......
85 87
		) ENGINE=InnoDB;
86 88
		');
87 89

  
90
		$GLOBALS['TYPO3_DB']->sql_query('CREATE TABLE ' . $this->testingTagsTable . ' (
91
			id int(11) unsigned NOT NULL auto_increment,
92
			identifier varchar(128) DEFAULT \'\' NOT NULL,
93
			tag varchar(128) DEFAULT \'\' NOT NULL,
94
			PRIMARY KEY (id),
95
			KEY cache_id (identifier),
96
			KEY cache_tag (tag)
97
		) ENGINE=InnoDB;
98
		');
99

  
88 100
		$this->backend = t3lib_div::makeInstance(
89 101
			't3lib_cache_backend_DbBackend',
90
			array('cacheTable' => $this->testingCacheTable)
102
			array(
103
				'cacheTable' => $this->testingCacheTable,
104
				'tagsTable' => $this->testingTagsTable,
105
			)
91 106
		);
92 107
	}
93 108

  
......
586 601
		$GLOBALS['TYPO3_DB']->sql_query(
587 602
			'DROP TABLE ' . $this->testingCacheTable . ';'
588 603
		);
604

  
605
		$GLOBALS['TYPO3_DB']->sql_query(
606
			'DROP TABLE ' . $this->testingTagsTable . ';'
607
		);
589 608
	}
590 609

  
591 610
}
t3lib/config_default.php (Arbeitskopie)
123 123
				'cache_hash' => array(
124 124
					'backend' => 't3lib_cache_backend_DbBackend',
125 125
					'options' => array(
126
						'cacheTable' => 'cachingframework_cache_hash'
126
						'cacheTable' => 'cachingframework_cache_hash',
127
						'tagsTable' => 'cachingframework_cache_hash_tags',
127 128
					)
128 129
				),
129 130
				'cache_pages' => array(
130 131
					'backend' => 't3lib_cache_backend_DbBackend',
131 132
					'options' => array(
132
						'cacheTable' => 'cachingframework_cache_pages'
133
						'cacheTable' => 'cachingframework_cache_pages',
134
						'tagsTable' => 'cachingframework_cache_pages_tags',
133 135
					)
134 136
				),
135 137
				'cache_pagesection' => array(
136 138
					'backend' => 't3lib_cache_backend_DbBackend',
137 139
					'options' => array(
138
						'cacheTable' => 'cachingframework_cache_pagesection'
140
						'cacheTable' => 'cachingframework_cache_pagesection',
141
						'tagsTable' => 'cachingframework_cache_pagesection_tags',
139 142
					)
140 143
				)
141 144
				/*
t3lib/stddb/tables.sql (Arbeitskopie)
138 138
#
139 139
CREATE TABLE cachingframework_cache_hash (
140 140
  id int(11) unsigned NOT NULL auto_increment,
141
  identifier varchar(250) DEFAULT '' NOT NULL,
141
  identifier varchar(128) DEFAULT '' NOT NULL,
142 142
  crdate int(11) unsigned DEFAULT '0' NOT NULL,
143 143
  content mediumtext,
144
  tags mediumtext,
145 144
  lifetime int(11) unsigned DEFAULT '0' NOT NULL,
146 145
  PRIMARY KEY (id),
147 146
  KEY cache_id (identifier)
148 147
) ENGINE=InnoDB;
149 148

  
149

  
150 150
#
151
# Table structure for table 'cachingframework_cache_hash_tags'
152
#
153
CREATE TABLE cachingframework_cache_hash_tags (
154
  id int(11) unsigned NOT NULL auto_increment,
155
  identifier varchar(128) DEFAULT '' NOT NULL,
156
  tag varchar(128) DEFAULT '' NOT NULL,
157
  PRIMARY KEY (id),
158
  KEY cache_id (identifier),
159
  KEY cache_tag (tag)
160
) ENGINE=InnoDB;
161

  
162

  
163
#
151 164
# Table structure for table 'cache_imagesizes'
152 165
#
153 166
CREATE TABLE cache_imagesizes (
t3lib/cache/backend/class.t3lib_cache_backend_dbbackend.php (Arbeitskopie)
33 33
class t3lib_cache_backend_DbBackend extends t3lib_cache_backend_AbstractBackend {
34 34

  
35 35
	protected $cacheTable;
36
	protected $tagsTable;
36 37

  
38
	protected $identifierField;
39
	protected $creationField;
40
	protected $lifetimeField;
41
	protected $notExpiredStatement;
42
	protected $tableList;
43
	protected $tableJoin;
44

  
37 45
	/**
46
	 * Constructs this backend
47
	 *
48
	 * @param mixed Configuration options - depends on the actual backend
49
	 */
50
	public function __construct(array $options = array()) {
51
		parent::__construct($options);
52
		$this->initializeCommonReferences();
53
	}
54

  
55
	/**
56
	 * Initializes common references used in this backend.
57
	 *
58
	 * @return	void
59
	 */
60
	protected function initializeCommonReferences() {
61
		$this->identifierField = $this->cacheTable . '.identifier';
62
		$this->creationField = $this->cacheTable . '.crdate';
63
		$this->lifetimeField = $this->cacheTable . '.lifetime';
64
		$this->tableList = $this->cacheTable . ', ' . $this->tagsTable;
65
		$this->tableJoin = $this->identifierField . ' = ' . $this->tagsTable . '.identifier';
66
		$this->notExpiredStatement = '(' . $this->creationField . ' + ' . $this->lifetimeField .
67
			' >= ' . $GLOBALS['EXEC_TIME'] . ' OR ' . $this->lifetimeField . ' = 0)';
68
	}
69

  
70
	/**
38 71
	 * Saves data in a cache file.
39 72
	 *
40 73
	 * @param string An identifier for this specific cache entry
......
73 106
				'identifier' => $entryIdentifier,
74 107
				'crdate'     => $GLOBALS['EXEC_TIME'],
75 108
				'content'    => $data,
76
				'tags'       => implode(',', $tags),
77 109
				'lifetime'   => $lifetime
78 110
			)
79 111
		);
112

  
113
		foreach ($tags as $tag) {
114
			$GLOBALS['TYPO3_DB']->exec_INSERTquery(
115
				$this->tagsTable,
116
				array(
117
					'identifier' => $entryIdentifier,
118
					'tag'        => $tag,
119
				)
120
			);
121
		}
80 122
	}
81 123

  
82 124
	/**
......
138 180
	public function remove($entryIdentifier) {
139 181
		$entryRemoved = false;
140 182

  
141
		$res = $GLOBALS['TYPO3_DB']->exec_DELETEquery(
142
			$this->cacheTable,
143
			'identifier = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($entryIdentifier, $this->cacheTable)
183
		$res = $GLOBALS['TYPO3_DB']->exec_DELETEmultipleTablesQuery(
184
			$this->tableList,
185
			$this->tableList,
186
			$this->tableJoin .
187
				' AND ' . $this->identifierField . ' = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($entryIdentifier, $this->cacheTable)
144 188
		);
145 189

  
146 190
		if($GLOBALS['TYPO3_DB']->sql_affected_rows($res) == 1) {
......
161 205
		$cacheEntryIdentifiers = array();
162 206

  
163 207
		$cacheEntryIdentifierRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
164
			'identifier',
165
			$this->cacheTable,
166
			$this->getListQueryForTag($tag) . ' AND (crdate + lifetime >= ' . $GLOBALS['EXEC_TIME'] . ' OR lifetime = 0)'
208
			$this->identifierField,
209
			$this->tableList,
210
			$this->getQueryForTag($tag) .
211
				' AND ' . $this->tableJoin .
212
				' AND ' . $this->notExpiredStatement,
213
			$this->identifierField
167 214
		);
168 215

  
169 216
		foreach ($cacheEntryIdentifierRows as $cacheEntryIdentifierRow) {
......
186 233
		$whereClause  = array();
187 234

  
188 235
		foreach ($tags as $tag) {
189
			$whereClause[] = $this->getListQueryForTag($tag);
236
			$whereClause[] = $this->getQueryForTag($tag);
190 237
		}
191
		$whereClause[] = '(crdate + lifetime >= ' . $GLOBALS['EXEC_TIME'] . ' OR lifetime = 0)';
192 238

  
239
		$whereClause[] = $this->tableJoin;
240
		$whereClause[] = $this->notExpiredStatement;
241

  
193 242
		$cacheEntryIdentifierRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
194
			'identifier',
195
			$this->cacheTable,
196
			implode(' AND ', $whereClause)
243
			$this->identifierField,
244
			$this->tableList,
245
			implode(' AND ', $whereClause),
246
			$this->identifierField
197 247
		);
198 248

  
199 249
		foreach ($cacheEntryIdentifierRows as $cacheEntryIdentifierRow) {
......
211 261
	 */
212 262
	public function flush() {
213 263
		$GLOBALS['TYPO3_DB']->sql_query('TRUNCATE ' . $this->cacheTable);
264
		$GLOBALS['TYPO3_DB']->sql_query('TRUNCATE ' . $this->tagsTable);
214 265
	}
215 266

  
216 267
	/**
......
220 271
	 * @return void
221 272
	 */
222 273
	public function flushByTag($tag) {
223
		$GLOBALS['TYPO3_DB']->exec_DELETEquery(
224
			$this->cacheTable,
225
			$this->getListQueryForTag($tag)
274
		$GLOBALS['TYPO3_DB']->exec_DELETEmultipleTablesQuery(
275
			$this->tableList,
276
			$this->tableList,
277
			$this->tableJoin .
278
				' AND ' . $this->getQueryForTag($tag)
226 279
		);
227 280
	}
228 281

  
......
233 286
	 * @return void
234 287
	 */
235 288
	public function flushByTags(array $tags) {
236
		$listQueryConditions = array();
237
		foreach ($tags as $tag) {
238
			$listQueryConditions[$tag] = $this->getListQueryForTag($tag);
289
		if (count($tags)) {
290
			$listQueryConditions = array();
291
			foreach ($tags as $tag) {
292
				$listQueryConditions[$tag] = $this->getQueryForTag($tag);
293
			}
294
	
295
			$GLOBALS['TYPO3_DB']->exec_DELETEmultipleTablesQuery(
296
				$this->tableList,
297
				$this->tableList,
298
				$this->tableJoin .
299
					' AND (' . implode(' OR ', $listQueryConditions) . ')'
300
			);
239 301
		}
240

  
241
		$listQuery = implode(' OR ', $listQueryConditions);
242
		$GLOBALS['TYPO3_DB']->exec_DELETEquery(
243
			$this->cacheTable,
244
			$listQuery
245
		);
246 302
	}
247 303

  
248 304
	/**
......
252 308
	 * @author Ingo Renner <ingo@typo3.org>
253 309
	 */
254 310
	public function collectGarbage() {
255
		$GLOBALS['TYPO3_DB']->exec_DELETEquery(
256
			$this->cacheTable,
257
			'crdate + lifetime < ' . $GLOBALS['EXEC_TIME'] . ' AND lifetime > 0'
311
		$GLOBALS['TYPO3_DB']->exec_DELETEmultipleTablesQuery(
312
			$this->tableList,
313
			$this->tableList,
314
			$this->tableJoin .
315
				' AND ' . $this->cacheTable . '.crdate + ' . $this->cacheTable . '.lifetime < ' . $GLOBALS['EXEC_TIME'] .
316
				' AND ' . $this->cacheTable . '.lifetime > 0'
258 317
		);
259 318
	}
260 319

  
......
300 359
		}
301 360
*/
302 361
		$this->cacheTable = $cacheTable;
362
		$this->initializeCommonReferences();
303 363
	}
304 364

  
305 365
	/**
......
313 373
	}
314 374

  
315 375
	/**
376
	 * Sets the table where cache tags are stored.
377
	 *
378
	 * @param	string		$tagsTabls: Name of the table
379
	 * @return	void
380
	 */
381
	public function setTagsTable($tagsTable) {
382
		$this->tagsTable = $tagsTable;
383
		$this->initializeCommonReferences();
384
	}
385

  
386
	/**
387
	 * Gets the table where cache tags are stored.
388
	 *
389
	 * @return	string		Name of the table storing tags
390
	 */
391
	public function getTagsTable() {
392
		return $this->tagsTable;
393
	}
394

  
395
	/**
316 396
	 * Gets the query to be used for selecting entries by a tag. The asterisk ("*")
317 397
	 * is allowed as a wildcard at the beginning and the end of a tag.
318 398
	 *
......
320 400
	 * @return string the query to be used for selecting entries
321 401
	 * @author Oliver Hader <oliver@typo3.org>
322 402
	 */
323
	protected function getListQueryForTag($tag) {
324
		return str_replace('*', '%', $GLOBALS['TYPO3_DB']->listQuery('tags', $tag, $this->cacheTable));
403
	protected function getQueryForTag($tag) {
404
		if (strpos($tag, '*') === false) {
405
			$query = $this->tagsTable . '.tag = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($tag, $this->tagsTable);
406
		} else {
407
			$patternForLike = $GLOBALS['TYPO3_DB']->escapeStrForLike(
408
				$GLOBALS['TYPO3_DB']->quoteStr($tag, $this->tagsTable),
409
				$this->tagsTable
410
			);
411
			$query = $this->tagsTable . '.tag LIKE \'' . $patternForLike . '\'';
412
		}
413

  
414
		return $query;
325 415
	}
326 416
}
327 417

  
t3lib/class.t3lib_db.php (Arbeitskopie)
216 216
	}
217 217

  
218 218
	/**
219
	 * Creates and executes a DELETE SQL-statement for multiple tables.
220
	 *
221
	 * @param	string		$tablesToDeleteFrom: Name of the tables to delete from
222
	 * @param	string		$tablesReference: Name of the tables references join the results
223
	 * @param	string		$where: WHERE clause, eg. "uid=1". NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
224
	 * @return	pointer		MySQL result pointer
225
	 */
226
	public function exec_DELETEmultipleTablesQuery($tablesToDeleteFrom, $tablesReference, $where) {
227
		$res = mysql_query($this->DELETEmultipleTablesQuery($tablesToDeleteFrom, $tablesReference, $where), $this->link);
228
		if ($this->debugOutput) {
229
			$this->debug('exec_DELETEquery');
230
		}
231
		return $res;
232
	}
233

  
234
	/**
219 235
	 * Creates and executes a SELECT SQL-statement
220 236
	 * Using this function specifically allow us to handle the LIMIT feature independently of DB.
221 237
	 * Usage count/core: 340
......
466 482
	}
467 483

  
468 484
	/**
485
	 * Creates a DELETE SQL-statement for multiple tables
486
	 * Usage count/core: 3
487
	 *
488
	 * @param	string		See exec_DELETEmultipleTablesQuery()
489
	 * @param	string		See exec_DELETEmultipleTablesQuery()
490
	 * @param	string		See exec_DELETEmultipleTablesQuery()
491
	 * @return	string		Full SQL query for DELETE from multiple tables
492
	 */
493
	public function DELETEmultipleTablesQuery($tablesToDeleteFrom, $tablesReference, $where) {
494
		if (is_string($where)) {
495
				// Table and fieldnames should be "SQL-injection-safe" when supplied to this function
496
			$query = 'DELETE ' . $tablesToDeleteFrom . ' FROM ' . $tablesReference .
497
				(strlen($where) > 0 ? ' WHERE ' . $where : '');
498

  
499
			if ($this->debugOutput || $this->store_lastBuiltQuery) {
500
				$this->debug_lastBuiltQuery = $query;
501
			}
502

  
503
			return $query;
504
		} else {
505
			die('<strong>TYPO3 Fatal Error:</strong> "Where" clause argument for DELETE query was not a string in $this->DELETEmultipleTablesQuery() !');
506
		}
507
	}
508

  
509
	/**
469 510
	 * Creates a SELECT SQL-statement
470 511
	 * Usage count/core: 11
471 512
	 *
typo3/sysext/cms/ext_tables.sql (Arbeitskopie)
41 41
#
42 42
CREATE TABLE cachingframework_cache_pages (
43 43
  id int(11) unsigned NOT NULL auto_increment,
44
  identifier varchar(250) DEFAULT '' NOT NULL,
44
  identifier varchar(128) DEFAULT '' NOT NULL,
45 45
  crdate int(11) unsigned DEFAULT '0' NOT NULL,
46 46
  content mediumtext,
47
  tags mediumtext,
48 47
  lifetime int(11) unsigned DEFAULT '0' NOT NULL,
49 48
  PRIMARY KEY (id),
50 49
  KEY cache_id (identifier)
......
52 51

  
53 52

  
54 53
#
54
# Table structure for table 'cachingframework_cache_pages_tags'
55
#
56
CREATE TABLE cachingframework_cache_pages_tags (
57
  id int(11) unsigned NOT NULL auto_increment,
58
  identifier varchar(128) DEFAULT '' NOT NULL,
59
  tag varchar(128) DEFAULT '' NOT NULL,
60
  PRIMARY KEY (id),
61
  KEY cache_id (identifier),
62
  KEY cache_tag (tag)
63
) ENGINE=InnoDB;
64

  
65

  
66
#
55 67
# Table structure for table 'cachingframework_cache_pagesection'
56 68
#
57 69
CREATE TABLE cachingframework_cache_pagesection (
58 70
  id int(11) unsigned NOT NULL auto_increment,
59
  identifier varchar(250) DEFAULT '' NOT NULL,
71
  identifier varchar(128) DEFAULT '' NOT NULL,
60 72
  crdate int(11) unsigned DEFAULT '0' NOT NULL,
61 73
  content mediumtext,
62
  tags mediumtext,
63 74
  lifetime int(11) unsigned DEFAULT '0' NOT NULL,
64 75
  PRIMARY KEY (id),
65 76
  KEY cache_id (identifier)
......
67 78

  
68 79

  
69 80
#
81
# Table structure for table 'cachingframework_cache_pagesection_tags'
82
#
83
CREATE TABLE cachingframework_cache_pagesection_tags (
84
  id int(11) unsigned NOT NULL auto_increment,
85
  identifier varchar(128) DEFAULT '' NOT NULL,
86
  tag varchar(128) DEFAULT '' NOT NULL,
87
  PRIMARY KEY (id),
88
  KEY cache_id (identifier),
89
  KEY cache_tag (tag)
90
) ENGINE=InnoDB;
91

  
92

  
93
#
70 94
# Table structure for table 'cache_typo3temp_log'
71 95
#
72 96
CREATE TABLE cache_typo3temp_log (
(4-4/5)