Completed
Push — release-2.1 ( 8bc4bf...08aa48 )
by Mathias
07:00
created

DbExtra-mysql.php ➔ smf_db_insert_sql()   C

Complexity

Conditions 10
Paths 33

Size

Total Lines 68
Code Lines 36

Duplication

Lines 28
Ratio 41.18 %

Importance

Changes 0
Metric Value
cc 10
eloc 36
nc 33
nop 2
dl 28
loc 68
rs 6.0995
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file contains rarely used extended database functionality.
5
 *
6
 * Simple Machines Forum (SMF)
7
 *
8
 * @package SMF
9
 * @author Simple Machines http://www.simplemachines.org
10
 * @copyright 2016 Simple Machines and individual contributors
11
 * @license http://www.simplemachines.org/about/smf/license.php BSD
12
 *
13
 * @version 2.1 Beta 3
14
 */
15
16
if (!defined('SMF'))
17
	die('No direct access...');
18
19
/**
20
 * Add the functions implemented in this file to the $smcFunc array.
21
 */
22
function db_extra_init()
23
{
24
	global $smcFunc;
25
26
	if (!isset($smcFunc['db_backup_table']) || $smcFunc['db_backup_table'] != 'smf_db_backup_table')
27
		$smcFunc += array(
28
			'db_backup_table' => 'smf_db_backup_table',
29
			'db_optimize_table' => 'smf_db_optimize_table',
30
			'db_table_sql' => 'smf_db_table_sql',
31
			'db_list_tables' => 'smf_db_list_tables',
32
			'db_get_version' => 'smf_db_get_version',
33
			'db_get_engine' => 'smf_db_get_engine',
34
		);
35
}
36
37
/**
38
 * Backup $table to $backup_table.
39
 * @param string $table The name of the table to backup
40
 * @param string $backup_table The name of the backup table for this table
41
 * @return resource -the request handle to the table creation query
42
 */
43
function smf_db_backup_table($table, $backup_table)
44
{
45
	global $smcFunc, $db_prefix;
46
47
	$table = str_replace('{db_prefix}', $db_prefix, $table);
48
49
	// First, get rid of the old table.
50
	$smcFunc['db_query']('', '
51
		DROP TABLE IF EXISTS {raw:backup_table}',
52
		array(
53
			'backup_table' => $backup_table,
54
		)
55
	);
56
57
	// Can we do this the quick way?
58
	$result = $smcFunc['db_query']('', '
59
		CREATE TABLE {raw:backup_table} LIKE {raw:table}',
60
		array(
61
			'backup_table' => $backup_table,
62
			'table' => $table
63
	));
64
	// If this failed, we go old school.
65
	if ($result)
66
	{
67
		$request = $smcFunc['db_query']('', '
68
			INSERT INTO {raw:backup_table}
69
			SELECT *
70
			FROM {raw:table}',
71
			array(
72
				'backup_table' => $backup_table,
73
				'table' => $table
74
			));
75
76
		// Old school or no school?
77
		if ($request)
78
			return $request;
79
	}
80
81
	// At this point, the quick method failed.
82
	$result = $smcFunc['db_query']('', '
83
		SHOW CREATE TABLE {raw:table}',
84
		array(
85
			'table' => $table,
86
		)
87
	);
88
	list (, $create) = $smcFunc['db_fetch_row']($result);
89
	$smcFunc['db_free_result']($result);
90
91
	$create = preg_split('/[\n\r]/', $create);
92
93
	$auto_inc = '';
94
	// Default engine type.
95
	$engine = 'MyISAM';
96
	$charset = '';
97
	$collate = '';
98
99
	foreach ($create as $k => $l)
100
	{
101
		// Get the name of the auto_increment column.
102
		if (strpos($l, 'auto_increment'))
103
			$auto_inc = trim($l);
104
105
		// For the engine type, see if we can work out what it is.
106
		if (strpos($l, 'ENGINE') !== false || strpos($l, 'TYPE') !== false)
107
		{
108
			// Extract the engine type.
109
			preg_match('~(ENGINE|TYPE)=(\w+)(\sDEFAULT)?(\sCHARSET=(\w+))?(\sCOLLATE=(\w+))?~', $l, $match);
110
111
			if (!empty($match[1]))
112
				$engine = $match[1];
113
114
			if (!empty($match[2]))
115
				$engine = $match[2];
116
117
			if (!empty($match[5]))
118
				$charset = $match[5];
119
120
			if (!empty($match[7]))
121
				$collate = $match[7];
122
		}
123
124
		// Skip everything but keys...
125
		if (strpos($l, 'KEY') === false)
126
			unset($create[$k]);
127
	}
128
129
	if (!empty($create))
130
		$create = '(
131
			' . implode('
132
			', $create) . ')';
133
	else
134
		$create = '';
135
136
	$request = $smcFunc['db_query']('', '
137
		CREATE TABLE {raw:backup_table} {raw:create}
138
		ENGINE={raw:engine}' . (empty($charset) ? '' : ' CHARACTER SET {raw:charset}' . (empty($collate) ? '' : ' COLLATE {raw:collate}')) . '
139
		SELECT *
140
		FROM {raw:table}',
141
		array(
142
			'backup_table' => $backup_table,
143
			'table' => $table,
144
			'create' => $create,
145
			'engine' => $engine,
146
			'charset' => empty($charset) ? '' : $charset,
147
			'collate' => empty($collate) ? '' : $collate,
148
		)
149
	);
150
151
	if ($auto_inc != '')
152
	{
153
		if (preg_match('~\`(.+?)\`\s~', $auto_inc, $match) != 0 && substr($auto_inc, -1, 1) == ',')
154
			$auto_inc = substr($auto_inc, 0, -1);
155
156
		$smcFunc['db_query']('', '
157
			ALTER TABLE {raw:backup_table}
158
			CHANGE COLUMN {raw:column_detail} {raw:auto_inc}',
159
			array(
160
				'backup_table' => $backup_table,
161
				'column_detail' => $match[1],
162
				'auto_inc' => $auto_inc,
163
			)
164
		);
165
	}
166
167
	return $request;
168
}
169
170
/**
171
 * This function optimizes a table.
172
 * @param string $table The table to be optimized
173
 * @return int How much space was gained
174
 */
175
function smf_db_optimize_table($table)
176
{
177
	global $smcFunc, $db_prefix;
178
179
	$table = str_replace('{db_prefix}', $db_prefix, $table);
180
181
	// Get how much overhead there is.
182
	$request = $smcFunc['db_query']('', '
183
			SHOW TABLE STATUS LIKE {string:table_name}',
184
			array(
185
				'table_name' => str_replace('_', '\_', $table),
186
			)
187
		);
188
	$row = $smcFunc['db_fetch_assoc']($request);
189
	$smcFunc['db_free_result']($request);
190
191
	$data_before = isset($row['Data_free']) ? $row['Data_free'] : 0;
192
	$request = $smcFunc['db_query']('', '
193
			OPTIMIZE TABLE `{raw:table}`',
194
			array(
195
				'table' => $table,
196
			)
197
		);
198
	if (!$request)
199
		return -1;
200
201
	// How much left?
202
	$request = $smcFunc['db_query']('', '
203
			SHOW TABLE STATUS LIKE {string:table}',
204
			array(
205
				'table' => str_replace('_', '\_', $table),
206
			)
207
		);
208
	$row = $smcFunc['db_fetch_assoc']($request);
209
	$smcFunc['db_free_result']($request);
210
211
	$total_change = isset($row['Data_free']) && $data_before > $row['Data_free'] ? $data_before / 1024 : 0;
212
213
	return $total_change;
214
}
215
216
/**
217
 * This function lists all tables in the database.
218
 * The listing could be filtered according to $filter.
219
 *
220
 * @param string|boolean $db string The database name or false to use the current DB
221
 * @param string|boolean $filter String to filter by or false to list all tables
222
 * @return array An array of table names
223
 */
224
function smf_db_list_tables($db = false, $filter = false)
0 ignored issues
show
Unused Code introduced by
The parameter $db is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
225
{
226
	global $db_name, $smcFunc;
227
228
	$db = $db == false ? $db_name : $db;
229
	$db = trim($db);
230
	$filter = $filter == false ? '' : ' LIKE \'' . $filter . '\'';
231
232
	$request = $smcFunc['db_query']('', '
233
		SHOW TABLES
234
		FROM `{raw:db}`
235
		{raw:filter}',
236
		array(
237
			'db' => $db[0] == '`' ? strtr($db, array('`' => '')) : $db,
238
			'filter' => $filter,
239
		)
240
	);
241
	$tables = array();
242
	while ($row = $smcFunc['db_fetch_row']($request))
243
		$tables[] = $row[0];
244
	$smcFunc['db_free_result']($request);
245
246
	return $tables;
247
}
248
249
/**
250
 * Dumps the schema (CREATE) for a table.
251
 * @todo why is this needed for?
252
 * @param string $tableName The name of the table
253
 * @return string The "CREATE TABLE" SQL string for this table
254
 */
255
function smf_db_table_sql($tableName)
256
{
257
	global $smcFunc, $db_prefix;
258
259
	$tableName = str_replace('{db_prefix}', $db_prefix, $tableName);
260
261
	// This will be needed...
262
	$crlf = "\r\n";
263
264
	// Drop it if it exists.
265
	$schema_create = 'DROP TABLE IF EXISTS `' . $tableName . '`;' . $crlf . $crlf;
266
267
	// Start the create table...
268
	$schema_create .= 'CREATE TABLE `' . $tableName . '` (' . $crlf;
269
270
	// Find all the fields.
271
	$result = $smcFunc['db_query']('', '
272
		SHOW FIELDS
273
		FROM `{raw:table}`',
274
		array(
275
			'table' => $tableName,
276
		)
277
	);
278
	while ($row = $smcFunc['db_fetch_assoc']($result))
279
	{
280
		// Make the CREATE for this column.
281
		$schema_create .= ' `' . $row['Field'] . '` ' . $row['Type'] . ($row['Null'] != 'YES' ? ' NOT NULL' : '');
282
283
		// Add a default...?
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
284
		if (!empty($row['Default']) || $row['Null'] !== 'YES')
285
		{
286
			// Make a special case of auto-timestamp.
287
			if ($row['Default'] == 'CURRENT_TIMESTAMP')
288
				$schema_create .= ' /*!40102 NOT NULL default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP */';
289
			// Text shouldn't have a default.
290
			elseif ($row['Default'] !== null)
291
			{
292
				// If this field is numeric the default needs no escaping.
293
				$type = strtolower($row['Type']);
294
				$isNumericColumn = strpos($type, 'int') !== false || strpos($type, 'bool') !== false || strpos($type, 'bit') !== false || strpos($type, 'float') !== false || strpos($type, 'double') !== false || strpos($type, 'decimal') !== false;
295
296
				$schema_create .= ' default ' . ($isNumericColumn ? $row['Default'] : '\'' . $smcFunc['db_escape_string']($row['Default']) . '\'');
297
			}
298
		}
299
300
		// And now any extra information. (such as auto_increment.)
301
		$schema_create .= ($row['Extra'] != '' ? ' ' . $row['Extra'] : '') . ',' . $crlf;
302
	}
303
	$smcFunc['db_free_result']($result);
304
305
	// Take off the last comma.
306
	$schema_create = substr($schema_create, 0, -strlen($crlf) - 1);
307
308
	// Find the keys.
309
	$result = $smcFunc['db_query']('', '
310
		SHOW KEYS
311
		FROM `{raw:table}`',
312
		array(
313
			'table' => $tableName,
314
		)
315
	);
316
	$indexes = array();
317
	while ($row = $smcFunc['db_fetch_assoc']($result))
318
	{
319
		// IS this a primary key, unique index, or regular index?
320
		$row['Key_name'] = $row['Key_name'] == 'PRIMARY' ? 'PRIMARY KEY' : (empty($row['Non_unique']) ? 'UNIQUE ' : ($row['Comment'] == 'FULLTEXT' || (isset($row['Index_type']) && $row['Index_type'] == 'FULLTEXT') ? 'FULLTEXT ' : 'KEY ')) . '`' . $row['Key_name'] . '`';
321
322
		// Is this the first column in the index?
323
		if (empty($indexes[$row['Key_name']]))
324
			$indexes[$row['Key_name']] = array();
325
326
		// A sub part, like only indexing 15 characters of a varchar.
327
		if (!empty($row['Sub_part']))
328
			$indexes[$row['Key_name']][$row['Seq_in_index']] = '`' . $row['Column_name'] . '`(' . $row['Sub_part'] . ')';
329
		else
330
			$indexes[$row['Key_name']][$row['Seq_in_index']] = '`' . $row['Column_name'] . '`';
331
	}
332
	$smcFunc['db_free_result']($result);
333
334
	// Build the CREATEs for the keys.
335
	foreach ($indexes as $keyname => $columns)
336
	{
337
		// Ensure the columns are in proper order.
338
		ksort($columns);
339
340
		$schema_create .= ',' . $crlf . ' ' . $keyname . ' (' . implode($columns, ', ') . ')';
341
	}
342
343
	// Now just get the comment and engine... (MyISAM, etc.)
344
	$result = $smcFunc['db_query']('', '
345
		SHOW TABLE STATUS
346
		LIKE {string:table}',
347
		array(
348
			'table' => strtr($tableName, array('_' => '\\_', '%' => '\\%')),
349
		)
350
	);
351
	$row = $smcFunc['db_fetch_assoc']($result);
352
	$smcFunc['db_free_result']($result);
353
354
	// Probably MyISAM.... and it might have a comment.
355
	$schema_create .= $crlf . ') ENGINE=' . $row['Engine'] . ($row['Comment'] != '' ? ' COMMENT="' . $row['Comment'] . '"' : '');
356
357
	return $schema_create;
358
}
359
360
/**
361
 *  Get the version number.
362
 *  @return string The version
363
 */
364
function smf_db_get_version()
365
{
366
	static $ver;
367
368
	if(!empty($ver))
369
		return $ver;
370
371
	global $smcFunc;
372
373
	$request = $smcFunc['db_query']('', '
374
		SELECT VERSION()',
375
		array(
376
		)
377
	);
378
	list ($ver) = $smcFunc['db_fetch_row']($request);
379
	$smcFunc['db_free_result']($request);
380
381
	return $ver;
382
}
383
384
/**
385
 * Figures out if we are using MySQL, Percona or MariaDB
386
 *
387
 * @return string The database engine we are using
388
*/
389
function smf_db_get_engine()
390
{
391
	global $smcFunc;
392
	static $db_type;
393
394
	if (!empty($db_type))
395
		return $db_type;
396
397
	$request = $smcFunc['db_query']('', 'SELECT @@version_comment');
398
	list ($comment) = $smcFunc['db_fetch_row']($request);
399
	$smcFunc['db_free_result']($request);
400
401
	// Skip these if we don't have a comment.
402
	if (!empty($comment))
403
	{
404
		if (stripos($comment, 'percona') !== false)
405
			return 'Percona';
406
		if (stripos($comment, 'mariadb') !== false)
407
			return 'MariaDB';
408
	}
409
	else
410
		return 'fail';
411
412
	return 'MySQL';
413
}
414
415
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...