mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
refactor StatServlet and add api page
This commit is contained in:
@@ -7,7 +7,7 @@ import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.alibaba.druid.VERSION;
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.stat.DruidDataSourceStatManager;
|
||||
import com.alibaba.druid.stat.JdbcSqlStat;
|
||||
import com.alibaba.druid.stat.JdbcStatManager;
|
||||
import com.alibaba.druid.util.IOUtils;
|
||||
import com.alibaba.druid.util.JdbcUtils;
|
||||
import com.alibaba.druid.util.StringUtils;
|
||||
@@ -58,15 +59,18 @@ public class StatServlet extends HttpServlet {
|
||||
returnJSONBasicStat(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.equals("/datasource.html")) {
|
||||
returnResourceFile(path, response);
|
||||
|
||||
if (path.equals("/reset-all.json")) {
|
||||
resetAllStat();
|
||||
returnJSONResult(request, response, RESULT_CODE_SUCCESS, null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.equals("/datasource.json")) {
|
||||
returnJSONResult(request, response, RESULT_CODE_SUCCESS, getJSONDataSourceStatList());
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.startsWith("/datasource-")) {
|
||||
Integer id = StringUtils.subStringToInteger(path, "datasource-", ".");
|
||||
Object result = getJSONDataSourceStat(id);
|
||||
@@ -78,6 +82,7 @@ public class StatServlet extends HttpServlet {
|
||||
returnJSONResult(request, response, RESULT_CODE_SUCCESS, getJSONSqlStat());
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.startsWith("/sql-")) {
|
||||
Integer id = StringUtils.subStringToInteger(path, "sql-", ".");
|
||||
Object result = getJSONSqlStat(id);
|
||||
@@ -89,6 +94,11 @@ public class StatServlet extends HttpServlet {
|
||||
returnResourceFile(path, response);
|
||||
}
|
||||
|
||||
private void resetAllStat() {
|
||||
JdbcStatManager.getInstance().reset();
|
||||
DruidDataSourceStatManager.getInstance().reset();
|
||||
}
|
||||
|
||||
private List<String> getJSONDrivers() {
|
||||
List<String> drivers = new ArrayList<String>();
|
||||
for (Enumeration<Driver> e = DriverManager.getDrivers(); e.hasMoreElements();) {
|
||||
@@ -99,7 +109,7 @@ public class StatServlet extends HttpServlet {
|
||||
}
|
||||
|
||||
private void returnJSONBasicStat(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
Map<String, Object> json = new HashMap<String, Object>();
|
||||
Map<String, Object> json = new LinkedHashMap<String, Object>();
|
||||
json.put("Version", VERSION.getVersionNumber());
|
||||
json.put("Drivers", getJSONDrivers());
|
||||
|
||||
@@ -143,9 +153,9 @@ public class StatServlet extends HttpServlet {
|
||||
if (identity == null) {
|
||||
return null;
|
||||
}
|
||||
for (DruidDataSource ds : DruidDataSourceStatManager.getDruidDataSourceInstances()) {
|
||||
if (System.identityHashCode(ds) == identity) {
|
||||
return ds;
|
||||
for (DruidDataSource datasource : DruidDataSourceStatManager.getDruidDataSourceInstances()) {
|
||||
if (System.identityHashCode(datasource) == identity) {
|
||||
return datasource;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -162,19 +172,23 @@ public class StatServlet extends HttpServlet {
|
||||
}
|
||||
|
||||
private Map<String, Object> toJSONSqlStat(JdbcSqlStat sqlStat) {
|
||||
Map<String, Object> json = new HashMap<String, Object>();
|
||||
Map<String, Object> json = new LinkedHashMap<String, Object>();
|
||||
|
||||
json.put("SQL", sqlStat.getSql());
|
||||
json.put("File", sqlStat.getFile());
|
||||
json.put("Name", sqlStat.getName());
|
||||
|
||||
json.put("ExecuteCount", sqlStat.getExecuteCount());
|
||||
json.put("ExecuteMillisTotal", sqlStat.getExecuteMillisTotal());
|
||||
json.put("ExecuteMillisMax", sqlStat.getExecuteMillisMax());
|
||||
|
||||
json.put("InTxnCount", sqlStat.getInTransactionCount());
|
||||
json.put("ErrorCount", sqlStat.getErrorCount());
|
||||
json.put("UpdateCount", sqlStat.getUpdateCount());
|
||||
json.put("FetchRowCount", sqlStat.getFetchRowCount());
|
||||
json.put("RunningCount", sqlStat.getRunningCount());
|
||||
json.put("ConcurrentMax", sqlStat.getConcurrentMax());
|
||||
|
||||
json.put("ExecHistogram", sqlStat.getHistogram().toArray());
|
||||
json.put("FetchRowHistogram", sqlStat.getFetchRowCountHistogram().toArray());
|
||||
json.put("UpdateCountHistogram", sqlStat.getUpdateCountHistogram().toArray());
|
||||
@@ -185,24 +199,30 @@ public class StatServlet extends HttpServlet {
|
||||
|
||||
private Map<String, Object> toJSONDataSource(DruidDataSource dataSource) {
|
||||
|
||||
Map<String, Object> json = new HashMap<String, Object>();
|
||||
Map<String, Object> json = new LinkedHashMap<String, Object>();
|
||||
json.put("Identity", System.identityHashCode(dataSource));
|
||||
json.put("Name", dataSource.getName());
|
||||
json.put("URL", dataSource.getUrl());
|
||||
json.put("DbType", dataSource.getDbType());
|
||||
json.put("UserName", dataSource.getUsername());
|
||||
json.put("DriverClassName", dataSource.getDriverClassName());
|
||||
|
||||
json.put("URL", dataSource.getUrl());
|
||||
json.put("UserName", dataSource.getUsername());
|
||||
|
||||
json.put("InitialSize", dataSource.getInitialSize());
|
||||
json.put("MinIdle", dataSource.getMinIdle());
|
||||
json.put("MaxActive", dataSource.getMaxActive());
|
||||
|
||||
json.put("TestOnBorrow", dataSource.isTestOnBorrow());
|
||||
json.put("TestWhileIdle", dataSource.isTestWhileIdle());
|
||||
|
||||
json.put("LogicConnectCount", dataSource.getConnectCount());
|
||||
json.put("LogicCloseCount", dataSource.getCloseCount());
|
||||
json.put("LogicConnectErrorCount", dataSource.getConnectErrorCount());
|
||||
|
||||
json.put("PhysicalConnectCount", dataSource.getCreateCount());
|
||||
json.put("PhysicalCloseCount", dataSource.getDestroyCount());
|
||||
json.put("PhysicalConnectErrorCount", dataSource.getCreateErrorCount());
|
||||
|
||||
json.put("PSCacheAccessCount", dataSource.getCachedPreparedStatementAccessCount());
|
||||
json.put("PSCacheHitCount", dataSource.getCachedPreparedStatementHitCount());
|
||||
json.put("PSCacheMissCount", dataSource.getCachedPreparedStatementMissCount());
|
||||
@@ -213,7 +233,7 @@ public class StatServlet extends HttpServlet {
|
||||
Object content) throws IOException {
|
||||
PrintWriter out = response.getWriter();
|
||||
|
||||
Map<String, Object> json = new HashMap<String, Object>();
|
||||
Map<String, Object> json = new LinkedHashMap<String, Object>();
|
||||
json.put("ResultCode", resultCode);
|
||||
json.put("Content", content);
|
||||
|
||||
|
||||
@@ -28,11 +28,10 @@ public class StringUtils {
|
||||
public static String subString(String src, String start, String to) {
|
||||
int indexFrom = src.indexOf(start);
|
||||
int indexTo = src.indexOf(to);
|
||||
if (indexFrom < 0 || indexTo < 0 || indexFrom < indexTo) {
|
||||
if (indexFrom < 0 || indexTo < 0 || indexFrom > indexTo) {
|
||||
return null;
|
||||
}
|
||||
indexFrom += start.length();
|
||||
indexTo += to.length();
|
||||
return src.substring(indexFrom, indexTo);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Druid Stat JSON API</title>
|
||||
<link href="style.css" type="text/css" rel="stylesheet"/>
|
||||
<script src="js.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
</br>
|
||||
<div id="menu" >
|
||||
<a href="index.html">Index</a> | <a href="datasource.html">DataSource</a> | <a href="sql.html">Sql</a> | <a href="#" onclick="ajaxRequestForReset()">Reset All</a> | <a href="api.html">JSON API</a>
|
||||
</div>
|
||||
</br>
|
||||
<div id="main">
|
||||
<h2>JSON API</h2>
|
||||
<table cellspacing="1" cellpadding="5" id="SqlStatTable" width="99%">
|
||||
<thead>
|
||||
<th class="td_lable">Name</th>
|
||||
<th class="td_lable">Description</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="basic.json" target="_blank">basic.json</a>
|
||||
</td>
|
||||
<td>
|
||||
basic info.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="datasource.json" target="_blank">datasource.json</a>
|
||||
</td>
|
||||
<td>
|
||||
DatsSourceStat List
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
datasource-{id}.json
|
||||
</td>
|
||||
<td>
|
||||
DatasourceStat for id={id},id is DatsSourceStat.ID</br>
|
||||
Example: druid/datasource-1.json
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="sql.json" target="_blank">sql.json</a>
|
||||
</td>
|
||||
<td>
|
||||
SqlStat info List.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
sql-{id}.json
|
||||
</td>
|
||||
<td>
|
||||
SqlStat for id={id} ,id is SqlStat.ID</br>
|
||||
Example: druid/sql-1.json
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="reset-all.json" target="_blank">reset-all.json</a>
|
||||
</td>
|
||||
<td>
|
||||
Reset all stat
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Druid DataSource Stat List</title>
|
||||
<title>Druid DataSourceStat</title>
|
||||
<link href="style.css" type="text/css" rel="stylesheet"/>
|
||||
<script src="js.js" type="text/javascript"></script>
|
||||
<script >
|
||||
@@ -14,10 +14,11 @@
|
||||
<body onload="init()">
|
||||
</br>
|
||||
<div id="menu" >
|
||||
<a href="index.html">Index</a> | <a href="datasource.html">DataSourceStatList</a> | <a href="sql.html">SqlStatList</a>
|
||||
<a href="index.html">Index</a> | <a href="datasource.html">DataSource</a> | <a href="sql.html">Sql</a> | <a href="#" onclick="ajaxRequestForReset()">Reset All</a> | <a href="api.html">JSON API</a>
|
||||
</div>
|
||||
</br>
|
||||
<div id="main">
|
||||
<h2>DataSourceStat List<a href="datasource.json" target="_blank">[View JSON API]</a></h2>
|
||||
<div id="dataSourceStatList">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
<body onload="init()">
|
||||
</br>
|
||||
<div id="menu" >
|
||||
<a href="index.html">Index</a> | <a href="datasource.html">DataSourceStatList</a> | <a href="sql.html">SqlStatList</a>
|
||||
<a href="index.html">Index</a> | <a href="datasource.html">DataSource</a> | <a href="sql.html">Sql</a> | <a href="#" onclick="ajaxRequestForReset()">Reset All</a> | <a href="api.html">JSON API</a>
|
||||
</div>
|
||||
</br>
|
||||
<div id="main">
|
||||
<h2>Stat Index</h2>
|
||||
<h2>Stat Index<a href="basic.json" target="_blank">[View JSON API]</a></h2>
|
||||
<table cellspacing="1" cellpadding="5">
|
||||
<tr >
|
||||
<td valign="top" width="100" class="td_lable">
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
|
||||
|
||||
var xmlHttpForBasicInfo;
|
||||
var xmlHttpForDataSourceInfo;
|
||||
var xmlHttpForDataSourceSqlStatInfo;
|
||||
var xmlHttpForReset;
|
||||
|
||||
function ajaxRequestForReset() {
|
||||
if (window.XMLHttpRequest)
|
||||
xmlHttpForReset = new XMLHttpRequest();
|
||||
else if (window.ActiveXObject)
|
||||
xmlHttpForReset = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
xmlHttpForReset.onreadystatechange = ajaxResponseForReset;
|
||||
xmlHttpForReset.open("GET", 'reset-all.json', true);
|
||||
xmlHttpForReset.send(null);
|
||||
return false;
|
||||
}
|
||||
function ajaxRequestForBasicInfo() {
|
||||
if (window.XMLHttpRequest)
|
||||
xmlHttpForBasicInfo = new XMLHttpRequest();
|
||||
@@ -28,6 +42,17 @@ function ajaxRequestForDataSourceInfo() {
|
||||
xmlHttpForDataSourceInfo.open("GET", 'datasource.json', true);
|
||||
xmlHttpForDataSourceInfo.send(null);
|
||||
}
|
||||
function ajaxResponseForReset() {
|
||||
var html = '';
|
||||
if (xmlHttpForReset.readyState == 4) {
|
||||
if (xmlHttpForReset.status == 200) {
|
||||
var jsonResp = eval("(" + xmlHttpForReset.responseText + ")");
|
||||
if (jsonResp.ResultCode == 1) {
|
||||
alert("already reset all stat");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function ajaxResponseForBasicInfo() {
|
||||
var html = '';
|
||||
if (xmlHttpForBasicInfo.readyState == 4) {
|
||||
@@ -88,41 +113,26 @@ function ajaxResponseForDataSourceInfo() {
|
||||
var listHtml = '';
|
||||
var datasourceId = datasource.Identity;
|
||||
listHtml += '<div id="dataSourceStat' + datasourceId + '">';
|
||||
listHtml += '<h2>Basic Info For <span id="DS-Info-Title' + datasourceId + '"></span></h2>';
|
||||
listHtml += '<table cellpadding="5" cellspacing="1" width="960">';
|
||||
listHtml += '<tr>';
|
||||
listHtml += '<td class="td_lable" width="150">UserName</td><td width="150" id="DS-Info-UserName' + datasourceId + '"> </td>';
|
||||
listHtml += '<td class="td_lable" width="140">URL</td><td id="DS-Info-URL' + datasourceId + '" colspan="3"> </td>';
|
||||
listHtml += '</tr>';
|
||||
|
||||
listHtml += '<tr >';
|
||||
listHtml += '<td class="td_lable">DbType</td><td id="DS-Info-DbType' + datasourceId + '"> </td>';
|
||||
listHtml += '<td class="td_lable">DriverClassName</td><td id="DS-Info-DriverClassName' + datasourceId + '" colspan="3"> </td>';
|
||||
listHtml += '</tr>';
|
||||
listHtml += '<tr>';
|
||||
listHtml += '<td class="td_lable">TestOnBorrow</td><td id="DS-Info-TestOnBorrow' + datasourceId + '"> </td>';
|
||||
listHtml += '<td class="td_lable">TestWhileIdle</td><td id="DS-Info-TestWhileIdle' + datasourceId + '" colspan="3"> </td>';
|
||||
listHtml += '</tr>';
|
||||
listHtml += '<tr>';
|
||||
listHtml += '<td class="td_lable">InitialSize</td><td id="DS-Info-InitialSize' + datasourceId + '"> </td>';
|
||||
listHtml += '<td class="td_lable">MinIdle</td><td id="DS-Info-MinIdle' + datasourceId + '" width="150"> </td>';
|
||||
listHtml += '<td class="td_lable" width="190">MaxActive</td><td id="DS-Info-MaxActive' + datasourceId + '"> </td>';
|
||||
listHtml += '</tr>';
|
||||
listHtml += '<tr>';
|
||||
listHtml += '<td class="td_lable">LogicConnectCount</td><td id="DS-Info-LogicConnectCount' + datasourceId + '"> </td>';
|
||||
listHtml += '<td class="td_lable">LogicCloseCount</td><td id="DS-Info-LogicCloseCount' + datasourceId + '"> </td>';
|
||||
listHtml += '<td class="td_lable">LogicConnectErrorCount</td><td id="DS-Info-LogicConnectErrorCount' + datasourceId + '"> </td>';
|
||||
listHtml += '</tr>';
|
||||
listHtml += '<tr>';
|
||||
listHtml += '<td class="td_lable">PhysicalConnectCount</td><td id="DS-Info-PhysicalConnectCount' + datasourceId + '"> </td>';
|
||||
listHtml += '<td class="td_lable">PhysicalCloseCount</td><td id="DS-Info-PhysicalCloseCount' + datasourceId + '"> </td>';
|
||||
listHtml += '<td class="td_lable">PhysicalConnectErrorCount</td><td id="DS-Info-PhysicalConnectErrorCount' + datasourceId + '"> </td>';
|
||||
listHtml += '</tr>';
|
||||
listHtml += '<tr>';
|
||||
listHtml += '<td class="td_lable">PSCacheAccessCount</td><td id="DS-Info-PSCacheAccessCount' + datasourceId + '"> </td>';
|
||||
listHtml += '<td class="td_lable">PSCacheHitCount</td><td id="DS-Info-PSCacheHitCount' + datasourceId + '"> </td>';
|
||||
listHtml += '<td class="td_lable">PSCacheMissCount</td><td id="DS-Info-PSCacheMissCount' + datasourceId + '"> </td>';
|
||||
listHtml += '</tr>';
|
||||
listHtml += '<h2>Basic Info For <span id="DS-Info-Title' + datasourceId + '"></span><a href="datasource-'+datasourceId+'.json" target="_blank">[View JSON API]</a></h2>';
|
||||
listHtml += '<table cellpadding="5" cellspacing="1" width="99%">';
|
||||
listHtml += '<tr><td class="td_lable" width="230">UserName</td><td id="DS-Info-UserName' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">URL</td><td id="DS-Info-URL' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">DbType</td><td id="DS-Info-DbType' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">DriverClassName</td><td id="DS-Info-DriverClassName' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">TestOnBorrow</td><td id="DS-Info-TestOnBorrow' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">TestWhileIdle</td><td id="DS-Info-TestWhileIdle' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">InitialSize</td><td id="DS-Info-InitialSize' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">MinIdle</td><td id="DS-Info-MinIdle' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">MaxActive</td><td id="DS-Info-MaxActive' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">LogicConnectCount</td><td id="DS-Info-LogicConnectCount' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">LogicCloseCount</td><td id="DS-Info-LogicCloseCount' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">LogicConnectErrorCount</td><td id="DS-Info-LogicConnectErrorCount' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">PhysicalConnectCount</td><td id="DS-Info-PhysicalConnectCount' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">PhysicalCloseCount</td><td id="DS-Info-PhysicalCloseCount' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">PhysicalConnectErrorCount</td><td id="DS-Info-PhysicalConnectErrorCount' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">PSCacheAccessCount</td><td id="DS-Info-PSCacheAccessCount' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">PSCacheHitCount</td><td id="DS-Info-PSCacheHitCount' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '<tr><td class="td_lable">PSCacheMissCount</td><td id="DS-Info-PSCacheMissCount' + datasourceId + '"> </td></tr>';
|
||||
listHtml += '</table>';
|
||||
listHtml += '</div>';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Druid SqlStat List</title>
|
||||
<title>Druid SqlStat</title>
|
||||
<link href="style.css" type="text/css" rel="stylesheet"/>
|
||||
<script src="js.js" type="text/javascript"></script>
|
||||
<script >
|
||||
@@ -14,11 +14,11 @@
|
||||
<body onload="init()">
|
||||
</br>
|
||||
<div id="menu" >
|
||||
<a href="index.html">Index</a> | <a href="datasource.html">DataSourceStatList</a> | <a href="sql.html">SqlStatList</a>
|
||||
<a href="index.html">Index</a> | <a href="datasource.html">DataSource</a> | <a href="sql.html">Sql</a> | <a href="#" onclick="ajaxRequestForReset()">Reset All</a> | <a href="api.html">JSON API</a>
|
||||
</div>
|
||||
</br>
|
||||
<div id="main">
|
||||
<h2>SqlStat List</h2>
|
||||
<h2>SqlStat List<a href="sql.json" target="_blank">[View JSON API]</a></h2>
|
||||
<table cellspacing="1" cellpadding="5" id="SqlStatTable" width="99%">
|
||||
<thead>
|
||||
<th class="td_lable">SQL</th>
|
||||
|
||||
Reference in New Issue
Block a user