2 namespace TYPO3\CMS\Dbal\Controller;
57 'name' => $this->moduleName,
59 $this->
getLanguageService()->includeLLFile(
'EXT:dbal/Resources/Private/Language/locallang.xlf');
72 $this->MOD_MENU = array(
74 0 => $languageService->getLL(
'Debug_log'),
75 'info' => $languageService->getLL(
'Cached_info'),
76 'sqlcheck' => $languageService->getLL(
'SQL_check')
90 $this->thisScript = BackendUtility::getModuleUrl($this->MCONF[
'name']);
99 $this->content .=
'<h1>' . $languageService->getLL(
'title') .
'</h1>';
101 $shortcutName = $languageService->getLL(
'Debug_log');
103 switch ($this->MOD_SETTINGS[
'function']) {
105 $this->content .=
'<h3>' . $languageService->getLL(
'Cached_info') .
'</h3>';
107 $shortcutName = $languageService->getLL(
'Cached_info');
110 $this->content .=
'<h3>' . $languageService->getLL(
'SQL_check') .
'</h3>';
111 $this->content .=
'<div>' . $this->
printSqlCheck() .
'</div>';
112 $shortcutName = $languageService->getLL(
'SQL_check');
115 $this->content .=
'<h3>' . $languageService->getLL(
'Debug_log') .
'</h3>';
116 $this->content .=
'<div>' . $this->
printLogMgm() .
'</div>';
120 $shortcutButton = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar()->makeShortcutButton()
121 ->setModuleName($this->MCONF[
'name'])
122 ->setDisplayName($shortcutName)
123 ->setSetVariables([
'function']);
124 $this->moduleTemplate->getDocHeaderComponent()->getButtonBar()->addButton($shortcutButton);
140 $this->moduleTemplate->setContent($this->content);
141 $response->
getBody()->write($this->moduleTemplate->renderContent());
154 <form name="sql_check" action="' . $this->thisScript .
'" method="post" enctype="multipart/form-data">
155 <script type="text/javascript">
157 function updateQryForm(s) {
158 document.getElementById(\'tx-dbal-result\').style.display = \'none\';
161 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'none\';
162 document.getElementById(\'tx-dbal-qryfields\').style.display = \'table-row\';
163 document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'none\';
164 document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'none\';
165 document.getElementById(\'tx-dbal-qryfrom\').style.display = \'table-row\';
166 document.getElementById(\'tx-dbal-qryinto\').style.display = \'none\';
167 document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
168 document.getElementById(\'tx-dbal-qrygroup\').style.display = \'table-row\';
169 document.getElementById(\'tx-dbal-qryorder\').style.display = \'table-row\';
170 document.getElementById(\'tx-dbal-qrylimit\').style.display = \'table-row\';
173 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'none\';
174 document.getElementById(\'tx-dbal-qryfields\').style.display = \'none\';
175 document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'table-row\';
176 document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'none\';
177 document.getElementById(\'tx-dbal-qryfrom\').style.display = \'none\';
178 document.getElementById(\'tx-dbal-qryinto\').style.display = \'table-row\';
179 document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
180 document.getElementById(\'tx-dbal-qrygroup\').style.display = \'table-row\';
181 document.getElementById(\'tx-dbal-qryorder\').style.display = \'table-row\';
182 document.getElementById(\'tx-dbal-qrylimit\').style.display = \'table-row\';
185 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'table-row\';
186 document.getElementById(\'tx-dbal-qryfields\').style.display = \'none\';
187 document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'none\';
188 document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'table-row\';
189 document.getElementById(\'tx-dbal-qryfrom\').style.display = \'none\';
190 document.getElementById(\'tx-dbal-qryinto\').style.display = \'none\';
191 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'table-row\';
192 document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
193 document.getElementById(\'tx-dbal-qrygroup\').style.display = \'none\';
194 document.getElementById(\'tx-dbal-qryorder\').style.display = \'none\';
195 document.getElementById(\'tx-dbal-qrylimit\').style.display = \'none\';
198 document.getElementById(\'tx-dbal-qryupdate\').style.display = \'none\';
199 document.getElementById(\'tx-dbal-qryfields\').style.display = \'none\';
200 document.getElementById(\'tx-dbal-qryinsertvalues\').style.display = \'none\';
201 document.getElementById(\'tx-dbal-qryupdatevalues\').style.display = \'none\';
202 document.getElementById(\'tx-dbal-qryfrom\').style.display = \'table-row\';
203 document.getElementById(\'tx-dbal-qryinto\').style.display = \'none\';
204 document.getElementById(\'tx-dbal-qrywhere\').style.display = \'table-row\';
205 document.getElementById(\'tx-dbal-qrygroup\').style.display = \'none\';
206 document.getElementById(\'tx-dbal-qryorder\').style.display = \'none\';
207 document.getElementById(\'tx-dbal-qrylimit\').style.display = \'none\';
214 <tr class="tableheader bgColor5"><th colspan="2">Easy SQL check</th></tr>
216 <select name="tx_dbal[QUERY]"size="1" onchange="updateQryForm(this.options[this.selectedIndex].value)">
217 <option value="SELECT" ' . ($input[
'QUERY'] ===
'SELECT' ?
'selected="selected"' :
'') .
'>SELECT</option>
218 <option value="INSERT" ' . ($input[
'QUERY'] ===
'INSERT' ?
'selected="selected"' :
'') .
'>INSERT</option>
219 <option value="UPDATE" ' . ($input[
'QUERY'] ===
'UPDATE' ?
'selected="selected"' :
'') .
'>UPDATE</option>
220 <option value="DELETE" ' . ($input[
'QUERY'] ===
'DELETE' ?
'selected="selected"' :
'') .
'>DELETE</option>
223 <tr id="tx-dbal-qryupdate" style="display:none;"><td></td><td><input name="tx_dbal[UPDATE]" value="' . $input[
'UPDATE'] .
'" type="text" size="30" maxsize="100" /></td></tr>
224 <tr id="tx-dbal-qryfields"><td></td><td><input name="tx_dbal[FIELDS]" value="' . $input[
'FIELDS'] .
'" type="text" size="30" maxsize="100" /></td></tr>
225 <tr id="tx-dbal-qryinsertvalues" style="display:none;"><td></td><td><textarea name="tx_dbal[INSERTVALUES]" cols="30" rows="4">' . $input[
'INSERTVALUES'] .
'</textarea></td></tr>
226 <tr id="tx-dbal-qryupdatevalues" style="display:none;"><th>SET</th><td><textarea name="tx_dbal[UPDATEVALUES]" cols="30" rows="4">' . $input[
'UPDATEVALUES'] .
'</textarea></td></tr>
227 <tr id="tx-dbal-qryfrom"><th>FROM</th><td><input name="tx_dbal[FROM]" value="' . $input[
'FROM'] .
'" type="text" size="30" maxsize="100" /></td></tr>
228 <tr id="tx-dbal-qryinto" style="display:none;"><th>INTO</th><td><input name="tx_dbal[INTO]" value="' . $input[
'INTO'] .
'" type="text" size="30" maxsize="100" /></td></tr>
229 <tr id="tx-dbal-qrywhere"><th>WHERE</th><td><input name="tx_dbal[WHERE]" value="' . $input[
'WHERE'] .
'" type="text" size="30" maxsize="100" /></td></tr>
230 <tr id="tx-dbal-qrygroup"><th>GROUP BY</th><td><input name="tx_dbal[GROUP]" value="' . $input[
'GROUP'] .
'" type="text" size="30" maxsize="100" /></td></tr>
231 <tr id="tx-dbal-qryorder"><th>ORDER BY</th><td><input name="tx_dbal[ORDER]" value="' . $input[
'ORDER'] .
'" type="text" size="30" maxsize="100" /></td></tr>
232 <tr id="tx-dbal-qrylimit"><th>LIMIT</th><td><input name="tx_dbal[LIMIT]" value="' . $input[
'LIMIT'] .
'" type="text" size="30" maxsize="100" /></td></tr>
235 <td style="text-align:right;">
236 <input class="btn btn-default" type="submit" value="CHECK" />
239 <script type="text/javascript">
241 updateQryForm(\'' . $input[
'QUERY'] .
'\');
245 $out .= '<tr
id=
"tx-dbal-result" class=
"bgColor4"><th>Result:</th><td>
';
246 switch ($input['QUERY
']) {
248 $qry = $this->getDatabaseConnection()->SELECTquery($input['FIELDS
'], $input['FROM
'], $input['WHERE
'], $input['GROUP
'], $input['ORDER
'], $input['LIMIT
']);
251 $qry = $this->getDatabaseConnection()->INSERTquery($input['INTO
'], $this->createFieldsValuesArray($input['INSERTVALUES
']));
254 $qry = $GLOBALS['TYPO3_DB
']->UPDATEquery($input['UPDATE
'], $input['WHERE
'], $this->createFieldsValuesArray($input['UPDATEVALUES
']));
257 $qry = $GLOBALS['TYPO3_DB
']->DELETEquery($input['FROM
'], $input['WHERE
']);
260 $out .= '<pre>
' . htmlspecialchars($qry) . '</pre></td></tr>
';
262 <tr
class=
"tableheader bgColor5">
263 <th colspan=
"2">RAW SQL check</th>
266 <td colspan=
"2" style=
"text-align:right;">
267 <textarea name=
"tx_dbal[RAWSQL]" cols=
"60" rows=
"5">
' . $input['RAWSQL
'] . '</textarea>
269 <input
class=
"btn btn-default" type=
"submit" value=
"CHECK" />
272 if (!empty($input['RAWSQL
'])) {
273 $out .= '<tr
class=
"bgColor4">
';
274 $parseResult = $GLOBALS['TYPO3_DB
']->SQLparser->parseSQL($input['RAWSQL
']);
275 if (is_array($parseResult)) {
276 $newQuery = $GLOBALS['TYPO3_DB
']->SQLparser->compileSQL($parseResult);
277 $testResult = $GLOBALS['TYPO3_DB
']->SQLparser->debug_parseSQLpartCompare($input['RAWSQL
'], $newQuery);
278 if (!is_array($testResult)) {
279 $out .= '<td colspan=
"2">
' . $newQuery;
281 $out .= '<td colspan=
"2">
' . htmlspecialchars($testResult[0]) . '</td></tr>
282 <tr><th>Error:</th><td style=
"border:2px solid #f00;">Input query did not match the parsed and recompiled query exactly (not observing whitespace):<br />
' . htmlspecialchars($testResult[1]);
285 $out .= '<th>Result:</th><td style=
"border:2px solid #f00;">
' . $parseResult;
287 $out .= '</td></tr>
';
289 $out .= '</table></form>
';
302 protected function createFieldsValuesArray($in)
305 $in = explode(LF, $in);
306 foreach ($in as $v) {
307 $fv = explode('=
', $v);
308 $ret[$fv[0]] = $fv[1];
322 protected function printCachedInfo()
325 if ((string)GeneralUtility::_GP('cmd
') === 'clear
') {
326 $this->getDatabaseConnection()->clearCachedFieldInfo();
327 $GLOBALS['TYPO3_DB
']->cacheFieldInfo();
329 $out = '<a name=
"autoincrement"></a><h2>auto_increment</h2>
';
330 $out .= '<table border=
"1" cellspacing=
"0"><tbody><tr><th>Table</th><th>Field</th></tr>
';
331 ksort($GLOBALS['TYPO3_DB
']->cache_autoIncFields);
332 foreach ($GLOBALS['TYPO3_DB
']->cache_autoIncFields as $table => $field) {
334 $out .= '<td>
' . $table . '</td>
';
335 $out .= '<td>
' . $field . '</td>
';
338 $out .= '</tbody></table>
';
339 $out .= '<a name=
"primarykeys"></a><h2>Primary keys</h2>
';
340 $out .= '<table border=
"1" cellspacing=
"0"><tbody><tr><th>Table</th><th>Field(s)</th></tr>
';
341 ksort($GLOBALS['TYPO3_DB
']->cache_primaryKeys);
342 foreach ($GLOBALS['TYPO3_DB
']->cache_primaryKeys as $table => $field) {
344 $out .= '<td>
' . $table . '</td>
';
345 $out .= '<td>
' . $field . '</td>
';
348 $out .= '</tbody></table>
';
349 $out .= '<a name=
"fieldtypes"></a><h2>Field types</h2>
';
351 <table border=
"1" cellspacing=
"0">
354 <th colspan=
"5">Table</th>
359 <a href=
"#metatypes">Metatype</a></th>
361 <th>Default</th></th>
363 ksort($GLOBALS['TYPO3_DB
']->cache_fieldType);
364 foreach ($GLOBALS['TYPO3_DB
']->cache_fieldType as $table => $fields) {
365 $out .= '<th colspan=
"5">
' . $table . '</th>
';
366 foreach ($fields as $field => $data) {
368 $out .= '<td>
' . $field . '</td>
';
369 $out .= '<td>
' . $data['type
'] . '</td>
';
370 $out .= '<td>
' . $data['metaType
'] . '</td>
';
371 $out .= '<td>
' . ($data['notnull
'] ? 'NOT NULL
' : '') . '</td>
';
372 $out .= '<td>
' . $data['default'] . '</td>
';
376 $out .= '</tbody></table>
';
377 $out .= '<a name=
"metatypes"></a><h2>Metatype explanation</h2>
';
379 C: Varchar, capped to 255 characters.
380 X: Larger varchar, capped to 4000 characters (to be compatible with Oracle).
381 XL: For Oracle, returns CLOB, otherwise the largest varchar size.
383 C2: Multibyte varchar
384 X2: Multibyte varchar (largest size)
386 B: BLOB (binary large
object)
388 D: Date (some databases
do not support
this, and we
return a datetime type)
389 T: Datetime or Timestamp
390 L: Integer field suitable
for storing booleans (0 or 1)
391 I: Integer (mapped to I4)
396 F: Floating point number
397 N: Numeric or decimal number</pre>';
398 $menu = '<a href="' . $this->thisScript . '&cmd=clear">CLEAR DATA</a><hr />';
399 $menu .= '<a href="
#autoincrement">auto_increment</a> | <a href="#primarykeys">Primary keys</a> | <a href="#fieldtypes">Field types</a> | <a href="#metatypes">Metatype explanation</a><hr />';
413 $GLOBALS[
'TYPO3_DB']->debug =
false;
418 $res =
$GLOBALS[
'TYPO3_DB']->exec_TRUNCATEquery(
'tx_dbal_debuglog');
419 $res =
$GLOBALS[
'TYPO3_DB']->exec_TRUNCATEquery(
'tx_dbal_debuglog_where');
420 $outStr =
'Log FLUSHED!';
423 $res =
$GLOBALS[
'TYPO3_DB']->exec_SELECTquery(
'table_join,exec_time,query,script',
'tx_dbal_debuglog',
'table_join!=\'\'',
'table_join,script,exec_time,query');
425 $tableIndex = array();
429 <td>Execution time</td>
434 while ($row =
$GLOBALS[
'TYPO3_DB']->sql_fetch_assoc($res)) {
435 $tableArray =
$GLOBALS[
'TYPO3_DB']->SQLparser->parseFromTables($row[
'table_join']);
437 foreach ($tableArray as $a) {
438 foreach ($tableArray as $b) {
439 if ($b[
'table'] != $a[
'table']) {
440 $tableIndex[$a[
'table']][$b[
'table']] = 1;
447 <td>' . htmlspecialchars($row[
'exec_time']) .
'</td>
448 <td>' . htmlspecialchars($row[
'table_join']) .
'</td>
449 <td>' . htmlspecialchars($row[
'script']) .
'</td>
450 <td>' . htmlspecialchars($row[
'query']) .
'</td>
454 $outStr .=
'<h4>Direct joins:</h4>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($tableIndex);
456 foreach ($tableIndex as $priTable => $a) {
457 foreach ($tableIndex as $tableN => $v) {
458 foreach ($v as $tableP => $vv) {
459 if ($tableP == $priTable) {
460 $tableIndex[$priTable] = array_merge($v, $a);
465 $outStr .=
'<h4>Total dependencies:</h4>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($tableIndex);
468 <table border="1" cellspacing="0">' . implode(
'', $tRows) .
'
472 $res =
$GLOBALS[
'TYPO3_DB']->exec_SELECTquery(
'serdata,exec_time,query,script',
'tx_dbal_debuglog',
'errorFlag>0',
'',
'tstamp DESC');
477 <td>Execution time</td>
482 while ($row =
$GLOBALS[
'TYPO3_DB']->sql_fetch_assoc($res)) {
486 <td>' . htmlspecialchars($row[
'exec_time']) .
'</td>
487 <td>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray(unserialize($row[
'serdata'])) .
'</td>
488 <td>' . htmlspecialchars($row[
'script']) .
'</td>
489 <td>' . htmlspecialchars($row[
'query']) .
'</td>
494 <table border="1" cellspacing="0">' . implode(
'', $tRows) .
'
498 $res =
$GLOBALS[
'TYPO3_DB']->exec_SELECTquery(
'query,serdata',
'tx_dbal_debuglog',
'errorFlag&2=2');
500 while ($row =
$GLOBALS[
'TYPO3_DB']->sql_fetch_assoc($res)) {
504 <td>' . htmlspecialchars($row[
'query']) .
'</td>
509 <table border="1" cellspacing="0">' . implode(
'', $tRows) .
'
513 $res =
$GLOBALS[
'TYPO3_DB']->exec_SELECTquery(
'tstamp,script,tablename,whereclause',
'tx_dbal_debuglog_where',
'',
'',
'tstamp DESC');
520 <td>WHERE clause</td>
522 while ($row =
$GLOBALS[
'TYPO3_DB']->sql_fetch_assoc($res)) {
526 <td>' . htmlspecialchars($row[
'script']) .
'</td>
527 <td>' . htmlspecialchars($row[
'tablename']) .
'</td>
528 <td>' . str_replace(array(
'\'\
'',
'""',
'IS NULL',
'IS NOT NULL'), array(
'<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">\'\'</span>',
'<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">""</span>',
'<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NULL</span>',
'<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NOT NULL</span>'), htmlspecialchars($row[
'whereclause'])) .
'</td>
532 <table border="1" cellspacing="0">' . implode(
'', $tRows) .
'
539 $res =
$GLOBALS[
'TYPO3_DB']->exec_SELECTquery(
'exec_time,errorFlag,table_join,serdata,query',
'tx_dbal_debuglog',
'tstamp=' . (
int)$specTime);
543 <td>Execution time</td>
549 while ($row =
$GLOBALS[
'TYPO3_DB']->sql_fetch_assoc($res)) {
552 <td>' . htmlspecialchars($row[
'exec_time']) .
'</td>
553 <td>' . ($row[
'errorFlag'] ? 1 : 0) .
'</td>
554 <td>' . htmlspecialchars($row[
'table_join']) .
'</td>
555 <td>' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray(unserialize($row[
'serdata'])) .
'</td>
556 <td>' . str_replace(array(
'\'\
'',
'""',
'IS NULL',
'IS NOT NULL'), array(
'<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">\'\'</span>',
'<span style="background-color:#ff0000;color:#ffffff;padding:2px;font-weight:bold;">""</span>',
'<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NULL</span>',
'<span style="background-color:#00ff00;color:#ffffff;padding:2px;font-weight:bold;">IS NOT NULL</span>'), htmlspecialchars($row[
'query'])) .
'</td>
560 $res =
$GLOBALS[
'TYPO3_DB']->exec_SELECTquery(
'tstamp,script, SUM(exec_time) as calc_sum, count(*) AS qrycount, MAX(errorFlag) as error',
'tx_dbal_debuglog',
'',
'tstamp,script',
'tstamp DESC');
565 <td># of queries</td>
570 while ($row =
$GLOBALS[
'TYPO3_DB']->sql_fetch_assoc($res)) {
574 <td>' . htmlspecialchars($row[
'qrycount']) .
'</td>
575 <td>' . ($row[
'error'] ?
'<strong style="color:#f00">ERR</strong>' :
'') .
'</td>
576 <td>' . htmlspecialchars($row[
'calc_sum']) .
'</td>
577 <td><a href="' . $this->thisScript .
'&specTime=' . (int)$row[
'tstamp'] .
'">' . htmlspecialchars($row[
'script']) .
'</a></td>
582 <table border="1" cellspacing="0">' . implode(
'', $tRows) .
'
586 <a href="' . $this->thisScript .
'&cmd=flush">FLUSH LOG</a> -
587 <a href="' . $this->thisScript .
'&cmd=joins">JOINS</a> -
588 <a href="' . $this->thisScript .
'&cmd=errors">ERRORS</a> -
589 <a href="' . $this->thisScript .
'&cmd=parsing">PARSING</a> -
590 <a href="' . $this->thisScript .
'">LOG</a> -
591 <a href="' . $this->thisScript .
'&cmd=where">WHERE</a> -
596 return $menu . $outStr;
604 $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
605 $menu->setIdentifier(
'DBALJumpMenu');
606 foreach ($this->MOD_MENU[
'function'] as $controller => $title) {
610 BackendUtility::getModuleUrl(
615 'function' => $controller
621 if ($controller === $this->MOD_SETTINGS[
'function']) {
622 $item->setActive(
true);
624 $menu->addMenuItem($item);
626 $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);