Merge remote-tracking branch 'origin/developing' into developing

This commit is contained in:
jipengfei-jpf
2023-07-18 21:35:00 +08:00
17 changed files with 423 additions and 186 deletions

View File

@ -1,3 +1,11 @@
# 2.0.4
## 🐞 Bug Fixes
- Default return alias for returned results [Issue #270](https://github.com/chat2db/Chat2DB/issues/270)
## 🐞 问题修复
- 返回结果默认返回别名 [Issue #270](https://github.com/chat2db/Chat2DB/issues/270)
# 2.0.4 # 2.0.4
## ⭐ New Features ## ⭐ New Features
- Support DB2 database - Support DB2 database

View File

@ -1,9 +1,9 @@
/* 在线链接服务仅供平台体验和调试使用,平台不承诺服务的稳定性,企业客户需下载字体包自行发布使用并做好备份。 */
@font-face { @font-face {
font-family: 'iconfont'; font-family: 'iconfont'; /* Project id 3633546 */
/* Project id 3633546 */ src: url('//at.alicdn.com/t/c/font_3633546_fu54vhe509d.woff2?t=1689606758277') format('woff2'),
src: url('../../assets/font/iconfont.woff2') format('woff2'), url('//at.alicdn.com/t/c/font_3633546_fu54vhe509d.woff?t=1689606758277') format('woff'),
url('../../assets/font/iconfont.woff') format('woff'), url('//at.alicdn.com/t/c/font_3633546_fu54vhe509d.ttf?t=1689606758277') format('truetype');
url('../../assets/font/iconfont.ttf') format('truetype');
} }
.iconfont { .iconfont {

View File

@ -77,19 +77,19 @@ export const databaseMap: {
icon: '\ue655', icon: '\ue655',
}, },
[DatabaseTypeCode.PRESTO]: { [DatabaseTypeCode.PRESTO]: {
name: 'Presto', name: 'Presto',
img: moreDBLogo, img: moreDBLogo,
code: DatabaseTypeCode.PRESTO, code: DatabaseTypeCode.PRESTO,
port: 8080, // port: 8080,
icon: '\ue60b', icon: '\ue60b',
}, },
[DatabaseTypeCode.DB2]: { [DatabaseTypeCode.DB2]: {
name: 'DB2', name: 'DB2',
img: moreDBLogo, img: moreDBLogo,
code: DatabaseTypeCode.DB2, code: DatabaseTypeCode.DB2,
port: 50000, // port: 50000,
icon: '\ue60a', icon: '\ue60a',
}, },
[DatabaseTypeCode.OCEANBASE]: { [DatabaseTypeCode.OCEANBASE]: {
name: 'OceanBase', name: 'OceanBase',
img: moreDBLogo, img: moreDBLogo,

View File

@ -2,7 +2,7 @@ export default {
'setting.title.setting': 'Setting', 'setting.title.setting': 'Setting',
'setting.nav.basic': 'Basic', 'setting.nav.basic': 'Basic',
'setting.nav.customAi': 'Custom Ai', 'setting.nav.customAi': 'Custom Ai',
'setting.nav.proxy': 'Proxy', 'setting.nav.proxy': 'Service Path',
'setting.nav.aboutUs': 'About Us', 'setting.nav.aboutUs': 'About Us',
'setting.title.backgroundColor': 'Background Color', 'setting.title.backgroundColor': 'Background Color',
'setting.title.themeColor': 'Theme Color', 'setting.title.themeColor': 'Theme Color',

View File

@ -2,7 +2,7 @@ export default {
'setting.title.setting': '设置', 'setting.title.setting': '设置',
'setting.nav.basic': '基础设置', 'setting.nav.basic': '基础设置',
'setting.nav.customAi': '自定义AI', 'setting.nav.customAi': '自定义AI',
'setting.nav.proxy': '代理设置', 'setting.nav.proxy': '服务端地址',
'setting.nav.aboutUs': '关于我们', 'setting.nav.aboutUs': '关于我们',
'setting.title.backgroundColor': '背景色', 'setting.title.backgroundColor': '背景色',
'setting.title.themeColor': '主题色', 'setting.title.themeColor': '主题色',

View File

@ -48,13 +48,16 @@ const ConnectionModel: IConnectionModelType = {
}, },
effects: { effects: {
*fetchConnectionList(_, { call, put }) { *fetchConnectionList({ callback }, { call, put }) {
try { try {
const res = (yield connectionService.getList({ pageNo: 1, pageSize: 999 })) as IPageResponse<IConnectionDetails>; const res = (yield connectionService.getList({ pageNo: 1, pageSize: 999 })) as IPageResponse<IConnectionDetails>;
yield put({ yield put({
type: 'setConnectionList', type: 'setConnectionList',
payload: res.data, payload: res.data,
}); });
if (callback && typeof callback === 'function') {
callback(res);
}
} }
catch { catch {

View File

@ -14,7 +14,7 @@
width: 220px; width: 220px;
overflow: hidden; overflow: hidden;
background-color: var(--color-bg-elevated); background-color: var(--color-bg-elevated);
border: 1px solid var(--color-border-secondary); border-right: 1px solid var(--color-border-secondary);
border-top: 0px; border-top: 0px;
border-bottom: 0px; border-bottom: 0px;
} }

View File

@ -37,7 +37,7 @@ function Connections(props: IProps) {
getConnectionList(); getConnectionList();
}, []); }, []);
const getConnectionList = async () => { const getConnectionList = () => {
dispatch({ dispatch({
type: 'connection/fetchConnectionList', type: 'connection/fetchConnectionList',
}); });
@ -133,15 +133,18 @@ function Connections(props: IProps) {
<div ref={volatileRef} className={styles.layoutLeft}> <div ref={volatileRef} className={styles.layoutLeft}>
<div className={styles.pageTitle}>{i18n('connection.title.connections')}</div> <div className={styles.pageTitle}>{i18n('connection.title.connections')}</div>
{renderMenu()} {renderMenu()}
<Button {
type="primary" curConnection && Object.keys(curConnection).length &&
className={styles.addConnection} <Button
onClick={() => { type="primary"
setCurConnection({}); className={styles.addConnection}
}} onClick={() => {
> setCurConnection({});
{i18n('connection.button.addConnection')} }}
</Button> >
{i18n('connection.button.addConnection')}
</Button>
}
</div> </div>
<div className={styles.layoutRight}> <div className={styles.layoutRight}>
{curConnection && Object.keys(curConnection).length ? ( {curConnection && Object.keys(curConnection).length ? (
@ -159,29 +162,29 @@ function Connections(props: IProps) {
/> />
</div> </div>
) : ( ) : (
<div className={styles.dataBaseList}> <div className={styles.dataBaseList}>
{databaseTypeList.map((t) => { {databaseTypeList.map((t) => {
return ( return (
<div key={t.code} className={styles.databaseItem} onClick={handleCreateConnections.bind(null, t)}> <div key={t.code} className={styles.databaseItem} onClick={handleCreateConnections.bind(null, t)}>
<div className={styles.databaseItemMain}> <div className={styles.databaseItemMain}>
<div className={styles.databaseItemLeft}> <div className={styles.databaseItemLeft}>
<div className={styles.logoBox}> <div className={styles.logoBox}>
<Iconfont code={t.icon} /> <Iconfont code={t.icon} />
</div>
{t.name}
</div>
<div className={styles.databaseItemRight}>
<Iconfont code="&#xe631;" />
</div> </div>
{t.name}
</div>
<div className={styles.databaseItemRight}>
<Iconfont code="&#xe631;" />
</div> </div>
</div> </div>
); </div>
})} );
{Array.from({ length: 20 }).map((t, index) => { })}
return <div key={index} className={styles.databaseItemSpacer}></div>; {Array.from({ length: 20 }).map((t, index) => {
})} return <div key={index} className={styles.databaseItemSpacer}></div>;
</div> })}
)} </div>
)}
</div> </div>
</div> </div>
); );

View File

@ -10,7 +10,7 @@
width: 220px; width: 220px;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
border: 1px solid var(--color-border-secondary); border-right: 1px solid var(--color-border-secondary);
border-top: 0px; border-top: 0px;
border-bottom: 0px; border-bottom: 0px;
} }

View File

@ -16,6 +16,7 @@
align-items: center; align-items: center;
width: 68px; width: 68px;
background-color: var(--color-bg-elevated); background-color: var(--color-bg-elevated);
border-right: 1px solid var(--color-border-secondary);
user-select: none; user-select: none;
overflow: hidden; overflow: hidden;
} }

View File

@ -0,0 +1,47 @@
@import '../../../../../styles/var.less';
.workspaceHeader{
flex-shrink: 0;
display: flex;
align-items: center;
padding-left: 10px;
background-color: var(--color-bg-elevated);
border-bottom: 1px solid var(--color-border-secondary);
}
.databaseLogo{
margin-right: 10px;
overflow: hidden;
height: 18px;
width: 18px;
display: flex;
justify-content: center;
align-items: center;
.refreshBox{
cursor: pointer;
}
.spin{
transform: scale(0.6);
}
}
.crumbsItem{
display: flex;
align-items: center;
height: 28px;
cursor: pointer;
&:hover{
color: var(--color-primary);
}
.typeIcon{
margin-right: 6px;
}
.arrow{
font-size: 10px;
margin: 0px 10px;
transform: translateY(1px);
}
}

View File

@ -0,0 +1,148 @@
import React, { memo, useEffect, useMemo, useState } from 'react';
import { connect } from 'umi';
import { IConnectionModelType } from '@/models/connection';
import { IWorkspaceModelType } from '@/models/workspace';
import styles from './index.less';
import classnames from 'classnames';
import { Cascader, Spin } from 'antd';
import Iconfont from '@/components/Iconfont';
import { databaseMap } from '@/constants';
import { useSafeState } from 'ahooks';
interface IProps {
className?: string;
cascaderOptions: any;
connectionModel: IConnectionModelType['state'];
workspaceModel: IWorkspaceModelType['state'];
dispatch: any;
}
const WorkspaceHeader = memo<IProps>((props) => {
const { className, cascaderOptions, connectionModel, workspaceModel, dispatch } = props;
const { connectionList, curConnection } = connectionModel;
const { curWorkspaceParams } = workspaceModel;
const [curSchemaOptions, setCurSchemaOptions] = useState<any>([]);
const [cascaderLoading, setCascaderLoading] = useState(false);
const connectionListOptions = useMemo(() => {
return connectionList?.map(t => {
return {
value: t.id,
label: t.alias
}
})
}, [connectionList])
useEffect(() => {
getConnectionList();
}, []);
const getConnectionList = () => {
setCascaderLoading(true)
dispatch({
type: 'connection/fetchConnectionList',
callback: () => {
setTimeout(() => {
setCascaderLoading(false)
}, 200);
}
});
};
function connectionChange(id: any, data: any) {
connectionList.map(t => {
if (t.id === id[0]) {
dispatch({
type: 'connection/setCurConnection',
payload: t
});
}
})
}
const databaseChange: any = (valueArr: any, selectedOptions: any) => {
const curWorkspaceParams = {
dataSourceId: curConnection?.id,
databaseSourceName: curConnection?.alias,
databaseName: selectedOptions[0].value,
schemaName: selectedOptions?.[0]?.next?.[0]?.value,
databaseType: curConnection?.type,
};
dispatch({
type: 'workspace/setCurWorkspaceParams',
payload: curWorkspaceParams,
});
setCurSchemaOptions(selectedOptions[0].next)
};
const schemaChange: any = (valueArr: any, selectedOptions: any) => {
dispatch({
type: 'workspace/setCurWorkspaceParams',
payload: { ...curWorkspaceParams, schemaName: selectedOptions[0].value },
});
}
function handelRefresh() {
getConnectionList()
}
return <div className={styles.workspaceHeader}>
<div className={styles.databaseLogo}>
{curConnection?.type ?
<div className={styles.refreshBox} onClick={handelRefresh}>
{cascaderLoading ? <Spin className={styles.spin} /> : <Iconfont className={styles.typeIcon} code={databaseMap[curConnection.type]?.icon} />}
</div>
:
<Iconfont className={styles.typeIcon} code="&#xe640;" />}
</div>
<Cascader
popupClassName={styles.cascaderPopup}
options={connectionListOptions}
onChange={connectionChange}
bordered={false}
>
<div className={styles.crumbsItem}>
<div>{curConnection?.alias}</div>
<Iconfont className={styles.arrow} code="&#xe641;" />
</div>
</Cascader>
<Cascader
popupClassName={styles.cascaderPopup}
options={cascaderOptions}
onChange={databaseChange}
bordered={false}
>
<div className={styles.crumbsItem}>
<div>{curWorkspaceParams.databaseName}</div>
{
!!curSchemaOptions.length && <Iconfont className={styles.arrow} code="&#xe608;" />
}
</div>
</Cascader>
{
!!curSchemaOptions.length &&
<Cascader
popupClassName={styles.cascaderPopup}
options={curSchemaOptions}
onChange={schemaChange}
bordered={false}
>
<div className={styles.crumbsItem}>
<div>{curWorkspaceParams.schemaName}</div>
</div>
</Cascader>
}
</div >
})
export default connect(
({ connection, workspace }: { connection: IConnectionModelType; workspace: IWorkspaceModelType }) => ({
connectionModel: connection,
workspaceModel: workspace,
}),
)(WorkspaceHeader);

View File

@ -81,9 +81,9 @@ const WorkspaceLeft = memo<IProps>(function (props) {
return ( return (
<div className={classnames(styles.box, className)}> <div className={classnames(styles.box, className)}>
<div className={styles.header}> {/* <div className={styles.header}>
<RenderSelectDatabase cascaderOptions={cascaderOptions} /> <RenderSelectDatabase cascaderOptions={cascaderOptions} />
</div> </div> */}
<RenderSaveBox></RenderSaveBox> <RenderSaveBox></RenderSaveBox>
<Divider className={styles.divider} /> <Divider className={styles.divider} />
<RenderTableBox /> <RenderTableBox />
@ -109,82 +109,81 @@ interface IProps {
dispatch: any; dispatch: any;
} }
const RenderSelectDatabase = dvaModel(function (props: IProps) { // const RenderSelectDatabase = dvaModel(function (props: IProps) {
const { connectionModel, workspaceModel, dispatch, cascaderOptions } = props; // const { connectionModel, workspaceModel, dispatch, cascaderOptions } = props;
const { curWorkspaceParams } = workspaceModel; // const { curWorkspaceParams } = workspaceModel;
const { curConnection } = connectionModel; // const { curConnection } = connectionModel;
const [currentSelectedName, setCurrentSelectedName] = useState(''); // const [currentSelectedName, setCurrentSelectedName] = useState('');
const [cascaderLoading, setCascaderLoading] = useState(false) // const [cascaderLoading, setCascaderLoading] = useState(false);
// useEffect(() => {
// if (curWorkspaceParams) {
// const { databaseName, schemaName, databaseSourceName } = curWorkspaceParams;
// const currentSelectedArr = [databaseSourceName, databaseName, schemaName].filter((t) => t);
// setCurrentSelectedName(currentSelectedArr.join('/'));
// }
// }, [curWorkspaceParams]);
useEffect(() => { // const onChange: any = (valueArr: any, selectedOptions: any) => {
if (curWorkspaceParams) { // let labelArr: string[] = [];
const { databaseName, schemaName, databaseSourceName } = curWorkspaceParams; // labelArr = selectedOptions.map((t: any) => {
const currentSelectedArr = [databaseSourceName, databaseName, schemaName].filter((t) => t); // return t.label;
setCurrentSelectedName(currentSelectedArr.join('/')); // });
}
}, [curWorkspaceParams]);
const onChange: any = (valueArr: any, selectedOptions: any) => { // const curWorkspaceParams = {
let labelArr: string[] = []; // dataSourceId: curConnection?.id,
labelArr = selectedOptions.map((t: any) => { // databaseSourceName: curConnection?.alias,
return t.label; // databaseName: labelArr[0],
}); // schemaName: labelArr[1],
// databaseType: curConnection?.type,
// };
const curWorkspaceParams = { // dispatch({
dataSourceId: curConnection?.id, // type: 'workspace/setCurWorkspaceParams',
databaseSourceName: curConnection?.alias, // payload: curWorkspaceParams,
databaseName: labelArr[0], // });
schemaName: labelArr[1], // };
databaseType: curConnection?.type,
};
dispatch({ // const dropdownRender = (menus: React.ReactNode) => <div>{menus}</div>;
type: 'workspace/setCurWorkspaceParams',
payload: curWorkspaceParams,
});
};
const dropdownRender = (menus: React.ReactNode) => <div>{menus}</div>; // function handleRefresh() {
// setCascaderLoading(true)
// dispatch({
// type: 'workspace/fetchDatabaseAndSchema',
// payload: {
// dataSourceId: curConnection?.id,
// refresh: true
// },
// callback: () => {
// setCascaderLoading(false)
// }
// });
// }
function handleRefresh() { // return (
setCascaderLoading(true) // <div className={styles.selectDatabaseBox}>
dispatch({ // <Cascader
type: 'workspace/fetchDatabaseAndSchema', // popupClassName={styles.cascaderPopup}
payload: { // options={cascaderOptions}
dataSourceId: curConnection?.id, // onChange={onChange}
refresh: true // bordered={false}
}, // dropdownRender={dropdownRender}
callback: () => { // >
setCascaderLoading(false) // <div className={styles.currentDatabase}>
} // <div className={styles.name}>
}); // {currentSelectedName || <span style={{ opacity: 0.8 }}>{i18n('workspace.cascader.placeholder')}</span>}{' '}
} // </div>
// <Iconfont code="&#xe608;" />
return ( // </div>
<div className={styles.selectDatabaseBox}> // </Cascader>
<Cascader // <div className={styles.otherOperations}>
popupClassName={styles.cascaderPopup} // <div className={classnames(styles.refreshIconBox, styles.iconBox)} onClick={handleRefresh}>
options={cascaderOptions} // {cascaderLoading ? <Spin /> : <Iconfont code="&#xec08;" />}
onChange={onChange} // </div>
bordered={false} // </div>
dropdownRender={dropdownRender} // </div>
> // );
<div className={styles.currentDatabase}> // });
<div className={styles.name}>
{currentSelectedName || <span style={{ opacity: 0.8 }}>{i18n('workspace.cascader.placeholder')}</span>}{' '}
</div>
<Iconfont code="&#xe608;" />
</div>
</Cascader>
<div className={styles.otherOperations}>
<div className={classnames(styles.refreshIconBox, styles.iconBox)} onClick={handleRefresh}>
{cascaderLoading ? <Spin /> : <Iconfont code="&#xec08;" />}
</div>
</div>
</div>
);
});
const RenderTableBox = dvaModel(function (props: any) { const RenderTableBox = dvaModel(function (props: any) {
const { workspaceModel, dispatch, tableLoading } = props; const { workspaceModel, dispatch, tableLoading } = props;
@ -375,7 +374,7 @@ const RenderSaveBox = dvaModel(function (props: any) {
type: 'workspace/fetchGetSavedConsole', type: 'workspace/fetchGetSavedConsole',
payload: { payload: {
status: ConsoleStatus.RELEASE, status: ConsoleStatus.RELEASE,
orderByDesc: false, orderByDesc: Boolean,
...curWorkspaceParams ...curWorkspaceParams
}, },
callback: (res: any) => { callback: (res: any) => {

View File

@ -1,15 +1,21 @@
@import '../../../styles/var.less'; @import '../../../styles/var.less';
.box { .workspace {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex;
flex-direction: column;
}
.workspaceMain{
height: 100%;
} }
.boxLeft { .boxLeft {
width: 220px; width: 220px;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
border: 1px solid var(--color-border-secondary); border-right: 1px solid var(--color-border-secondary);
border-top: 0px; border-top: 0px;
border-bottom: 0px; border-bottom: 0px;
} }

View File

@ -4,10 +4,12 @@ import styles from './index.less';
import DraggableContainer from '@/components/DraggableContainer'; import DraggableContainer from '@/components/DraggableContainer';
import WorkspaceLeft from './components/WorkspaceLeft'; import WorkspaceLeft from './components/WorkspaceLeft';
import WorkspaceRight from './components/WorkspaceRight'; import WorkspaceRight from './components/WorkspaceRight';
import WorkspaceHeader from './components/WorkspaceHeader';
import { IConnectionModelType } from '@/models/connection'; import { IConnectionModelType } from '@/models/connection';
import { IWorkspaceModelType } from '@/models/workspace'; import { IWorkspaceModelType } from '@/models/workspace';
import LoadingContent from '@/components/Loading/LoadingContent'; import LoadingContent from '@/components/Loading/LoadingContent';
import { ConsoleOpenedStatus } from '@/constants'; import { ConsoleOpenedStatus } from '@/constants';
import Iconfont from '@/components/Iconfont';
interface IProps { interface IProps {
className?: string; className?: string;
@ -47,7 +49,7 @@ function handleDatabaseAndSchema(databaseAndSchema: IWorkspaceModelType['state']
return { return {
value: t.name, value: t.name,
label: t.name, label: t.name,
children: schemasList, next: schemasList,
}; };
}); });
} else if (databaseAndSchema?.schemas) { } else if (databaseAndSchema?.schemas) {
@ -70,15 +72,12 @@ const workspace = memo<IProps>((props) => {
useEffect(() => { useEffect(() => {
if (pageLoading === true) { if (pageLoading === true) {
setLoading(true) setLoading(true);
} else { } else {
setLoading(false) setLoading(false);
} }
}, [pageLoading]) }, [pageLoading])
console.log('pageLoading', pageLoading)
const cascaderOptions = useMemo(() => { const cascaderOptions = useMemo(() => {
if (!databaseAndSchema) { if (!databaseAndSchema) {
return return
@ -113,7 +112,6 @@ const workspace = memo<IProps>((props) => {
clearData(); clearData();
}, [curConnection]); }, [curConnection]);
useEffect(() => { useEffect(() => {
if (curWorkspaceParams.dataSourceId) { if (curWorkspaceParams.dataSourceId) {
getConsoleList(); getConsoleList();
@ -162,17 +160,21 @@ const workspace = memo<IProps>((props) => {
}, },
}); });
} }
return ( return (
<LoadingContent isLoading={loading}> <div className={styles.workspace}>
<DraggableContainer className={styles.box}> <WorkspaceHeader cascaderOptions={cascaderOptions}></WorkspaceHeader>
<div ref={draggableRef} className={styles.boxLeft}> <LoadingContent isLoading={loading}>
<WorkspaceLeft cascaderOptions={cascaderOptions} /> <DraggableContainer className={styles.workspaceMain}>
</div> <div ref={draggableRef} className={styles.boxLeft}>
<div className={styles.boxRight}> <WorkspaceLeft cascaderOptions={cascaderOptions} />
<WorkspaceRight /> </div>
</div> <div className={styles.boxRight}>
</DraggableContainer> <WorkspaceRight />
</LoadingContent> </div>
</DraggableContainer>
</LoadingContent >
</div>
); );
}); });

View File

@ -14,6 +14,7 @@ import java.util.stream.Collectors;
import ai.chat2db.server.tools.base.constant.EasyToolsConstant; import ai.chat2db.server.tools.base.constant.EasyToolsConstant;
import ai.chat2db.spi.model.*; import ai.chat2db.spi.model.*;
import ai.chat2db.spi.util.ResultSetUtils;
import cn.hutool.core.date.TimeInterval; import cn.hutool.core.date.TimeInterval;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -57,13 +58,14 @@ public class SQLExecutor {
/** /**
* 执行sql * 执行sql
*
* @param connection * @param connection
* @param sql * @param sql
* @param function * @param function
* @return * @return
*/ */
public <R> R executeSql(Connection connection,String sql, Function<ResultSet, R> function) { public <R> R executeSql(Connection connection, String sql, Function<ResultSet, R> function) {
if (StringUtils.isEmpty(sql)) { if (StringUtils.isEmpty(sql)) {
return null; return null;
} }
@ -115,7 +117,7 @@ public class SQLExecutor {
headerList.add(Header.builder() headerList.add(Header.builder()
.dataType(ai.chat2db.spi.util.JdbcUtils.resolveDataType( .dataType(ai.chat2db.spi.util.JdbcUtils.resolveDataType(
resultSetMetaData.getColumnTypeName(i), resultSetMetaData.getColumnType(i)).getCode()) resultSetMetaData.getColumnTypeName(i), resultSetMetaData.getColumnType(i)).getCode())
.name(resultSetMetaData.getColumnName(i)) .name(ResultSetUtils.getColumnName(resultSetMetaData, i))
.build()); .build());
} }
@ -153,12 +155,13 @@ public class SQLExecutor {
* @return * @return
* @throws SQLException * @throws SQLException
*/ */
public ExecuteResult execute(Connection connection,String sql) throws SQLException { public ExecuteResult execute(Connection connection, String sql) throws SQLException {
return execute(sql, connection); return execute(sql, connection);
} }
/** /**
* 获取所有的数据库 * 获取所有的数据库
*
* @param connection * @param connection
* @return * @return
*/ */
@ -178,12 +181,13 @@ public class SQLExecutor {
/** /**
* 获取所有的schema * 获取所有的schema
*
* @param connection * @param connection
* @param databaseName * @param databaseName
* @param schemaName * @param schemaName
* @return * @return
*/ */
public List<Map<String, String>> schemas(Connection connection,String databaseName, String schemaName) { public List<Map<String, String>> schemas(Connection connection, String databaseName, String schemaName) {
List<Map<String, String>> schemaList = Lists.newArrayList(); List<Map<String, String>> schemaList = Lists.newArrayList();
if (StringUtils.isEmpty(databaseName) && StringUtils.isEmpty(schemaName)) { if (StringUtils.isEmpty(databaseName) && StringUtils.isEmpty(schemaName)) {
try (ResultSet resultSet = connection.getMetaData().getSchemas()) { try (ResultSet resultSet = connection.getMetaData().getSchemas()) {
@ -217,6 +221,7 @@ public class SQLExecutor {
/** /**
* 获取所有的数据库表 * 获取所有的数据库表
*
* @param connection * @param connection
* @param databaseName * @param databaseName
* @param schemaName * @param schemaName
@ -224,7 +229,8 @@ public class SQLExecutor {
* @param types * @param types
* @return * @return
*/ */
public List<Table> tables(Connection connection,String databaseName, String schemaName, String tableName, String types[]) { public List<Table> tables(Connection connection, String databaseName, String schemaName, String tableName,
String types[]) {
List<Table> tables = Lists.newArrayList(); List<Table> tables = Lists.newArrayList();
int n = 0; int n = 0;
try (ResultSet resultSet = connection.getMetaData().getTables(databaseName, schemaName, tableName, try (ResultSet resultSet = connection.getMetaData().getTables(databaseName, schemaName, tableName,
@ -246,6 +252,7 @@ public class SQLExecutor {
/** /**
* 获取所有的数据库表列 * 获取所有的数据库表列
*
* @param connection * @param connection
* @param databaseName * @param databaseName
* @param schemaName * @param schemaName
@ -253,7 +260,8 @@ public class SQLExecutor {
* @param columnName * @param columnName
* @return * @return
*/ */
public List<TableColumn> columns(Connection connection,String databaseName, String schemaName, String tableName, String columnName) { public List<TableColumn> columns(Connection connection, String databaseName, String schemaName, String tableName,
String columnName) {
List<TableColumn> tableColumns = Lists.newArrayList(); List<TableColumn> tableColumns = Lists.newArrayList();
try (ResultSet resultSet = connection.getMetaData().getColumns(databaseName, schemaName, tableName, try (ResultSet resultSet = connection.getMetaData().getColumns(databaseName, schemaName, tableName,
columnName)) { columnName)) {
@ -270,13 +278,14 @@ public class SQLExecutor {
/** /**
* 获取所有的数据库表索引 * 获取所有的数据库表索引
*
* @param connection * @param connection
* @param databaseName * @param databaseName
* @param schemaName * @param schemaName
* @param tableName * @param tableName
* @return * @return
*/ */
public List<TableIndex> indexes(Connection connection,String databaseName, String schemaName, String tableName) { public List<TableIndex> indexes(Connection connection, String databaseName, String schemaName, String tableName) {
List<TableIndex> tableIndices = Lists.newArrayList(); List<TableIndex> tableIndices = Lists.newArrayList();
try (ResultSet resultSet = connection.getMetaData().getIndexInfo(databaseName, schemaName, tableName, try (ResultSet resultSet = connection.getMetaData().getIndexInfo(databaseName, schemaName, tableName,
false, false,
@ -308,12 +317,13 @@ public class SQLExecutor {
/** /**
* 获取所有的函数 * 获取所有的函数
*
* @param connection * @param connection
* @param databaseName * @param databaseName
* @param schemaName * @param schemaName
* @return * @return
*/ */
public List<ai.chat2db.spi.model.Function> functions(Connection connection,String databaseName, public List<ai.chat2db.spi.model.Function> functions(Connection connection, String databaseName,
String schemaName) { String schemaName) {
List<ai.chat2db.spi.model.Function> functions = Lists.newArrayList(); List<ai.chat2db.spi.model.Function> functions = Lists.newArrayList();
try (ResultSet resultSet = connection.getMetaData().getFunctions(databaseName, schemaName, null);) { try (ResultSet resultSet = connection.getMetaData().getFunctions(databaseName, schemaName, null);) {
@ -328,12 +338,13 @@ public class SQLExecutor {
/** /**
* 获取所有的存储过程 * 获取所有的存储过程
*
* @param connection * @param connection
* @param databaseName * @param databaseName
* @param schemaName * @param schemaName
* @return * @return
*/ */
public List<Procedure> procedures(Connection connection,String databaseName, String schemaName) { public List<Procedure> procedures(Connection connection, String databaseName, String schemaName) {
List<Procedure> procedures = Lists.newArrayList(); List<Procedure> procedures = Lists.newArrayList();
try (ResultSet resultSet = connection.getMetaData().getProcedures(databaseName, schemaName, null)) { try (ResultSet resultSet = connection.getMetaData().getProcedures(databaseName, schemaName, null)) {
while (resultSet != null && resultSet.next()) { while (resultSet != null && resultSet.next()) {

View File

@ -2,6 +2,7 @@
package ai.chat2db.spi.util; package ai.chat2db.spi.util;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import ai.chat2db.spi.model.*; import ai.chat2db.spi.model.*;
@ -16,12 +17,12 @@ public class ResultSetUtils {
ai.chat2db.spi.model.Function function ai.chat2db.spi.model.Function function
= new ai.chat2db.spi.model.Function(); = new ai.chat2db.spi.model.Function();
try { try {
function.setDatabaseName(getString(resultSet,"FUNCTION_CAT")); function.setDatabaseName(getString(resultSet, "FUNCTION_CAT"));
function.setSchemaName(getString(resultSet,"FUNCTION_SCHEM")); function.setSchemaName(getString(resultSet, "FUNCTION_SCHEM"));
function.setFunctionName(getString(resultSet,"FUNCTION_NAME")); function.setFunctionName(getString(resultSet, "FUNCTION_NAME"));
function.setRemarks(getString(resultSet,"REMARKS")); function.setRemarks(getString(resultSet, "REMARKS"));
function.setFunctionType(resultSet.getShort("FUNCTION_TYPE")); function.setFunctionType(resultSet.getShort("FUNCTION_TYPE"));
function.setSpecificName(getString(resultSet,"SPECIFIC_NAME")); function.setSpecificName(getString(resultSet, "SPECIFIC_NAME"));
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -31,12 +32,12 @@ public class ResultSetUtils {
public static Procedure buildProcedure(ResultSet resultSet) { public static Procedure buildProcedure(ResultSet resultSet) {
Procedure procedure = new Procedure(); Procedure procedure = new Procedure();
try { try {
procedure.setDatabaseName(getString(resultSet,"PROCEDURE_CAT")); procedure.setDatabaseName(getString(resultSet, "PROCEDURE_CAT"));
procedure.setSchemaName(getString(resultSet,"PROCEDURE_SCHEM")); procedure.setSchemaName(getString(resultSet, "PROCEDURE_SCHEM"));
procedure.setProcedureName(getString(resultSet,"PROCEDURE_NAME")); procedure.setProcedureName(getString(resultSet, "PROCEDURE_NAME"));
procedure.setRemarks(getString(resultSet,"REMARKS")); procedure.setRemarks(getString(resultSet, "REMARKS"));
procedure.setProcedureType(resultSet.getShort("PROCEDURE_TYPE")); procedure.setProcedureType(resultSet.getShort("PROCEDURE_TYPE"));
procedure.setSpecificName(getString(resultSet,"SPECIFIC_NAME")); procedure.setSpecificName(getString(resultSet, "SPECIFIC_NAME"));
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -45,31 +46,31 @@ public class ResultSetUtils {
public static TableIndexColumn buildTableIndexColumn(ResultSet resultSet) throws SQLException { public static TableIndexColumn buildTableIndexColumn(ResultSet resultSet) throws SQLException {
TableIndexColumn tableIndexColumn = new TableIndexColumn(); TableIndexColumn tableIndexColumn = new TableIndexColumn();
tableIndexColumn.setColumnName(getString(resultSet,"COLUMN_NAME")); tableIndexColumn.setColumnName(getString(resultSet, "COLUMN_NAME"));
tableIndexColumn.setIndexName(getString(resultSet,"INDEX_NAME")); tableIndexColumn.setIndexName(getString(resultSet, "INDEX_NAME"));
tableIndexColumn.setAscOrDesc(getString(resultSet,"ASC_OR_DESC")); tableIndexColumn.setAscOrDesc(getString(resultSet, "ASC_OR_DESC"));
tableIndexColumn.setCardinality(resultSet.getLong("CARDINALITY")); tableIndexColumn.setCardinality(resultSet.getLong("CARDINALITY"));
tableIndexColumn.setPages(resultSet.getLong("PAGES")); tableIndexColumn.setPages(resultSet.getLong("PAGES"));
tableIndexColumn.setFilterCondition(getString(resultSet,"FILTER_CONDITION")); tableIndexColumn.setFilterCondition(getString(resultSet, "FILTER_CONDITION"));
tableIndexColumn.setIndexQualifier(getString(resultSet,"INDEX_QUALIFIER")); tableIndexColumn.setIndexQualifier(getString(resultSet, "INDEX_QUALIFIER"));
// tableIndexColumn.setIndexType(resultSet.getShort("TYPE")); // tableIndexColumn.setIndexType(resultSet.getShort("TYPE"));
tableIndexColumn.setNonUnique(resultSet.getBoolean("NON_UNIQUE")); tableIndexColumn.setNonUnique(resultSet.getBoolean("NON_UNIQUE"));
tableIndexColumn.setOrdinalPosition(resultSet.getShort("ORDINAL_POSITION")); tableIndexColumn.setOrdinalPosition(resultSet.getShort("ORDINAL_POSITION"));
tableIndexColumn.setDatabaseName(getString(resultSet,"TABLE_CAT")); tableIndexColumn.setDatabaseName(getString(resultSet, "TABLE_CAT"));
tableIndexColumn.setSchemaName(getString(resultSet,"TABLE_SCHEM")); tableIndexColumn.setSchemaName(getString(resultSet, "TABLE_SCHEM"));
tableIndexColumn.setTableName(getString(resultSet,"TABLE_NAME")); tableIndexColumn.setTableName(getString(resultSet, "TABLE_NAME"));
return tableIndexColumn; return tableIndexColumn;
} }
public static TableColumn buildColumn(ResultSet resultSet) throws SQLException { public static TableColumn buildColumn(ResultSet resultSet) throws SQLException {
TableColumn tableColumn = new TableColumn(); TableColumn tableColumn = new TableColumn();
tableColumn.setDatabaseName(getString(resultSet,"TABLE_CAT")); tableColumn.setDatabaseName(getString(resultSet, "TABLE_CAT"));
tableColumn.setSchemaName(getString(resultSet,"TABLE_SCHEM")); tableColumn.setSchemaName(getString(resultSet, "TABLE_SCHEM"));
tableColumn.setTableName(getString(resultSet,"TABLE_NAME")); tableColumn.setTableName(getString(resultSet, "TABLE_NAME"));
tableColumn.setName(getString(resultSet,"COLUMN_NAME")); tableColumn.setName(getString(resultSet, "COLUMN_NAME"));
tableColumn.setComment(getString(resultSet,"REMARKS")); tableColumn.setComment(getString(resultSet, "REMARKS"));
tableColumn.setDefaultValue(getString(resultSet,"COLUMN_DEF")); tableColumn.setDefaultValue(getString(resultSet, "COLUMN_DEF"));
tableColumn.setTypeName(getString(resultSet,"TYPE_NAME")); tableColumn.setTypeName(getString(resultSet, "TYPE_NAME"));
tableColumn.setColumnSize(resultSet.getInt("COLUMN_SIZE")); tableColumn.setColumnSize(resultSet.getInt("COLUMN_SIZE"));
tableColumn.setDataType(resultSet.getInt("DATA_TYPE")); tableColumn.setDataType(resultSet.getInt("DATA_TYPE"));
tableColumn.setNullable(resultSet.getInt("NULLABLE") == 1); tableColumn.setNullable(resultSet.getInt("NULLABLE") == 1);
@ -85,22 +86,30 @@ public class ResultSetUtils {
public static Table buildTable(ResultSet resultSet) throws SQLException { public static Table buildTable(ResultSet resultSet) throws SQLException {
Table table = new Table(); Table table = new Table();
table.setName(getString(resultSet,"TABLE_NAME")); table.setName(getString(resultSet, "TABLE_NAME"));
table.setComment(getString(resultSet,"REMARKS")); table.setComment(getString(resultSet, "REMARKS"));
table.setDatabaseName(getString(resultSet,"TABLE_CAT")); table.setDatabaseName(getString(resultSet, "TABLE_CAT"));
table.setSchemaName(getString(resultSet,"TABLE_SCHEM")); table.setSchemaName(getString(resultSet, "TABLE_SCHEM"));
table.setType(getString(resultSet,"TABLE_TYPE")); table.setType(getString(resultSet, "TABLE_TYPE"));
return table; return table;
} }
private static String getString(ResultSet resultSet,String name){ private static String getString(ResultSet resultSet, String name) {
if(resultSet == null){ if (resultSet == null) {
return null; return null;
} }
try { try {
return resultSet.getString(name); return resultSet.getString(name);
}catch (Exception e){ } catch (Exception e) {
return null; return null;
} }
} }
public static String getColumnName(ResultSetMetaData resultSetMetaData, int column) throws SQLException {
String columnLabel = resultSetMetaData.getColumnLabel(column);
if (columnLabel != null) {
return columnLabel;
}
return resultSetMetaData.getColumnName(column);
}
} }