오라클 제어 수정
This commit is contained in:
parent
852075c799
commit
b452f148a9
|
|
@ -1,7 +1,11 @@
|
|||
// @ts-ignore
|
||||
import * as oracledb from 'oracledb';
|
||||
import { DatabaseConnector, ConnectionConfig, QueryResult } from '../interfaces/DatabaseConnector';
|
||||
import { ConnectionTestResult, TableInfo } from '../types/externalDbTypes';
|
||||
import * as oracledb from "oracledb";
|
||||
import {
|
||||
DatabaseConnector,
|
||||
ConnectionConfig,
|
||||
QueryResult,
|
||||
} from "../interfaces/DatabaseConnector";
|
||||
import { ConnectionTestResult, TableInfo } from "../types/externalDbTypes";
|
||||
|
||||
export class OracleConnector implements DatabaseConnector {
|
||||
private connection: oracledb.Connection | null = null;
|
||||
|
|
@ -9,7 +13,7 @@ export class OracleConnector implements DatabaseConnector {
|
|||
|
||||
constructor(config: ConnectionConfig) {
|
||||
this.config = config;
|
||||
|
||||
|
||||
// Oracle XE 21c 특화 설정
|
||||
// oracledb.outFormat = oracledb.OUT_FORMAT_OBJECT;
|
||||
// oracledb.autoCommit = true;
|
||||
|
|
@ -19,31 +23,31 @@ export class OracleConnector implements DatabaseConnector {
|
|||
try {
|
||||
// Oracle XE 21c 연결 문자열 구성
|
||||
const connectionString = this.buildConnectionString();
|
||||
|
||||
|
||||
const connectionConfig: any = {
|
||||
user: this.config.user,
|
||||
password: this.config.password,
|
||||
connectString: connectionString
|
||||
connectString: connectionString,
|
||||
};
|
||||
|
||||
this.connection = await oracledb.getConnection(connectionConfig);
|
||||
console.log('Oracle XE 21c 연결 성공');
|
||||
console.log("Oracle XE 21c 연결 성공");
|
||||
} catch (error: any) {
|
||||
console.error('Oracle XE 21c 연결 실패:', error);
|
||||
console.error("Oracle XE 21c 연결 실패:", error);
|
||||
throw new Error(`Oracle 연결 실패: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
private buildConnectionString(): string {
|
||||
const { host, port, database } = this.config;
|
||||
|
||||
|
||||
// Oracle XE 21c는 기본적으로 XE 서비스명을 사용
|
||||
// 다양한 연결 문자열 형식 지원
|
||||
if (database.includes('/') || database.includes(':')) {
|
||||
if (database.includes("/") || database.includes(":")) {
|
||||
// 이미 완전한 연결 문자열인 경우
|
||||
return database;
|
||||
}
|
||||
|
||||
|
||||
// Oracle XE 21c 표준 형식
|
||||
return `${host}:${port}/${database}`;
|
||||
}
|
||||
|
|
@ -53,9 +57,9 @@ export class OracleConnector implements DatabaseConnector {
|
|||
try {
|
||||
await this.connection.close();
|
||||
this.connection = null;
|
||||
console.log('Oracle 연결 해제됨');
|
||||
console.log("Oracle 연결 해제됨");
|
||||
} catch (error: any) {
|
||||
console.error('Oracle 연결 해제 실패:', error);
|
||||
console.error("Oracle 연결 해제 실패:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -65,28 +69,28 @@ export class OracleConnector implements DatabaseConnector {
|
|||
if (!this.connection) {
|
||||
await this.connect();
|
||||
}
|
||||
|
||||
|
||||
// Oracle XE 21c 버전 확인 쿼리
|
||||
const result = await this.connection!.execute(
|
||||
'SELECT BANNER FROM V$VERSION WHERE BANNER LIKE \'Oracle%\''
|
||||
"SELECT BANNER FROM V$VERSION WHERE BANNER LIKE 'Oracle%'"
|
||||
);
|
||||
|
||||
console.log('Oracle 버전:', result.rows);
|
||||
|
||||
console.log("Oracle 버전:", result.rows);
|
||||
return {
|
||||
success: true,
|
||||
message: '연결 성공',
|
||||
message: "연결 성공",
|
||||
details: {
|
||||
server_version: (result.rows as any)?.[0]?.BANNER || 'Unknown'
|
||||
}
|
||||
server_version: (result.rows as any)?.[0]?.BANNER || "Unknown",
|
||||
},
|
||||
};
|
||||
} catch (error: any) {
|
||||
console.error('Oracle 연결 테스트 실패:', error);
|
||||
console.error("Oracle 연결 테스트 실패:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: '연결 실패',
|
||||
message: "연결 실패",
|
||||
details: {
|
||||
server_version: error.message
|
||||
}
|
||||
server_version: error.message,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -98,28 +102,28 @@ export class OracleConnector implements DatabaseConnector {
|
|||
|
||||
try {
|
||||
const startTime = Date.now();
|
||||
|
||||
|
||||
// 쿼리 타입 확인 (DML인지 SELECT인지)
|
||||
const isDML = /^\s*(INSERT|UPDATE|DELETE|MERGE)/i.test(query);
|
||||
|
||||
|
||||
// Oracle XE 21c 쿼리 실행 옵션
|
||||
const options: any = {
|
||||
outFormat: (oracledb as any).OUT_FORMAT_OBJECT, // OBJECT format
|
||||
maxRows: 10000, // XE 제한 고려
|
||||
fetchArraySize: 100,
|
||||
autoCommit: isDML // ✅ DML 쿼리는 자동 커밋
|
||||
autoCommit: isDML, // ✅ DML 쿼리는 자동 커밋
|
||||
};
|
||||
|
||||
console.log('Oracle 쿼리 실행:', {
|
||||
query: query.substring(0, 100) + '...',
|
||||
console.log("Oracle 쿼리 실행:", {
|
||||
query: query.substring(0, 100) + "...",
|
||||
isDML,
|
||||
autoCommit: options.autoCommit
|
||||
autoCommit: options.autoCommit,
|
||||
});
|
||||
|
||||
const result = await this.connection!.execute(query, params, options);
|
||||
const executionTime = Date.now() - startTime;
|
||||
|
||||
console.log('Oracle 쿼리 실행 결과:', {
|
||||
console.log("Oracle 쿼리 실행 결과:", {
|
||||
query,
|
||||
rowCount: result.rows?.length || 0,
|
||||
rowsAffected: result.rowsAffected,
|
||||
|
|
@ -127,35 +131,35 @@ export class OracleConnector implements DatabaseConnector {
|
|||
executionTime: `${executionTime}ms`,
|
||||
actualRows: result.rows,
|
||||
metaDataInfo: result.metaData,
|
||||
autoCommit: options.autoCommit
|
||||
autoCommit: options.autoCommit,
|
||||
});
|
||||
|
||||
return {
|
||||
rows: result.rows || [],
|
||||
rowCount: result.rowsAffected || (result.rows?.length || 0),
|
||||
fields: this.extractFieldInfo(result.metaData || [])
|
||||
rowCount: result.rowsAffected || result.rows?.length || 0,
|
||||
fields: this.extractFieldInfo(result.metaData || []),
|
||||
};
|
||||
} catch (error: any) {
|
||||
console.error('Oracle 쿼리 실행 실패:', error);
|
||||
console.error("Oracle 쿼리 실행 실패:", error);
|
||||
throw new Error(`쿼리 실행 실패: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
private extractFieldInfo(metaData: any[]): any[] {
|
||||
return metaData.map(field => ({
|
||||
return metaData.map((field) => ({
|
||||
name: field.name,
|
||||
type: this.mapOracleType(field.dbType),
|
||||
length: field.precision || field.byteSize,
|
||||
nullable: field.nullable
|
||||
nullable: field.nullable,
|
||||
}));
|
||||
}
|
||||
|
||||
private mapOracleType(oracleType: any): string {
|
||||
// Oracle XE 21c 타입 매핑 (간단한 방식)
|
||||
if (typeof oracleType === 'string') {
|
||||
if (typeof oracleType === "string") {
|
||||
return oracleType;
|
||||
}
|
||||
return 'UNKNOWN';
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
async getTables(): Promise<TableInfo[]> {
|
||||
|
|
@ -167,22 +171,21 @@ export class OracleConnector implements DatabaseConnector {
|
|||
ORDER BY table_name
|
||||
`;
|
||||
|
||||
console.log('Oracle 테이블 조회 시작 - 사용자:', this.config.user);
|
||||
|
||||
console.log("Oracle 테이블 조회 시작 - 사용자:", this.config.user);
|
||||
|
||||
const result = await this.executeQuery(query);
|
||||
console.log('사용자 스키마 테이블 조회 결과:', result.rows);
|
||||
|
||||
console.log("사용자 스키마 테이블 조회 결과:", result.rows);
|
||||
|
||||
const tables = result.rows.map((row: any) => ({
|
||||
table_name: row.TABLE_NAME,
|
||||
columns: [],
|
||||
description: null
|
||||
description: null,
|
||||
}));
|
||||
|
||||
console.log(`총 ${tables.length}개의 사용자 테이블을 찾았습니다.`);
|
||||
return tables;
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('Oracle 테이블 목록 조회 실패:', error);
|
||||
console.error("Oracle 테이블 목록 조회 실패:", error);
|
||||
throw new Error(`테이블 목록 조회 실패: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -190,7 +193,7 @@ export class OracleConnector implements DatabaseConnector {
|
|||
async getColumns(tableName: string): Promise<any[]> {
|
||||
try {
|
||||
console.log(`[OracleConnector] getColumns 호출: tableName=${tableName}`);
|
||||
|
||||
|
||||
const query = `
|
||||
SELECT
|
||||
column_name,
|
||||
|
|
@ -204,41 +207,44 @@ export class OracleConnector implements DatabaseConnector {
|
|||
WHERE table_name = UPPER(:tableName)
|
||||
ORDER BY column_id
|
||||
`;
|
||||
|
||||
|
||||
console.log(`[OracleConnector] 쿼리 실행 시작: ${query}`);
|
||||
const result = await this.executeQuery(query, [tableName]);
|
||||
|
||||
|
||||
console.log(`[OracleConnector] 쿼리 결과:`, result.rows);
|
||||
console.log(`[OracleConnector] 결과 개수:`, result.rows ? result.rows.length : 'null/undefined');
|
||||
|
||||
console.log(
|
||||
`[OracleConnector] 결과 개수:`,
|
||||
result.rows ? result.rows.length : "null/undefined"
|
||||
);
|
||||
|
||||
const mappedResult = result.rows.map((row: any) => ({
|
||||
column_name: row.COLUMN_NAME,
|
||||
data_type: this.formatOracleDataType(row),
|
||||
is_nullable: row.NULLABLE === 'Y' ? 'YES' : 'NO',
|
||||
column_default: row.DATA_DEFAULT
|
||||
is_nullable: row.NULLABLE === "Y" ? "YES" : "NO",
|
||||
column_default: row.DATA_DEFAULT,
|
||||
}));
|
||||
|
||||
|
||||
console.log(`[OracleConnector] 매핑된 결과:`, mappedResult);
|
||||
return mappedResult;
|
||||
} catch (error: any) {
|
||||
console.error('[OracleConnector] getColumns 오류:', error);
|
||||
console.error("[OracleConnector] getColumns 오류:", error);
|
||||
throw new Error(`테이블 컬럼 조회 실패: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
private formatOracleDataType(row: any): string {
|
||||
const { DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE } = row;
|
||||
|
||||
|
||||
switch (DATA_TYPE) {
|
||||
case 'NUMBER':
|
||||
case "NUMBER":
|
||||
if (DATA_PRECISION && DATA_SCALE !== null) {
|
||||
return `NUMBER(${DATA_PRECISION},${DATA_SCALE})`;
|
||||
} else if (DATA_PRECISION) {
|
||||
return `NUMBER(${DATA_PRECISION})`;
|
||||
}
|
||||
return 'NUMBER';
|
||||
case 'VARCHAR2':
|
||||
case 'CHAR':
|
||||
return "NUMBER";
|
||||
case "VARCHAR2":
|
||||
case "CHAR":
|
||||
return `${DATA_TYPE}(${DATA_LENGTH})`;
|
||||
default:
|
||||
return DATA_TYPE;
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export const EditModal: React.FC<EditModalProps> = ({
|
|||
|
||||
console.log(`🎯 계산된 모달 크기: ${maxWidth}px x ${maxHeight}px`);
|
||||
console.log(
|
||||
`📍 컴포넌트 위치들:`,
|
||||
"📍 컴포넌트 위치들:",
|
||||
components.map((c) => ({ x: c.position?.x, y: c.position?.y, w: c.size?.width, h: c.size?.height })),
|
||||
);
|
||||
return { width: maxWidth, height: maxHeight };
|
||||
|
|
@ -85,7 +85,7 @@ export const EditModal: React.FC<EditModalProps> = ({
|
|||
// 스크롤 완전 제거
|
||||
if (modalContent) {
|
||||
modalContent.style.overflow = "hidden";
|
||||
console.log(`🚫 스크롤 완전 비활성화`);
|
||||
console.log("🚫 스크롤 완전 비활성화");
|
||||
}
|
||||
}, 100); // 100ms 지연으로 렌더링 완료 후 실행
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ export const EditModal: React.FC<EditModalProps> = ({
|
|||
|
||||
// 코드 타입인 경우 특별히 로깅
|
||||
if ((comp as any).widgetType === "code") {
|
||||
console.log(` 🔍 코드 타입 세부정보:`, {
|
||||
console.log(" 🔍 코드 타입 세부정보:", {
|
||||
columnName: comp.columnName,
|
||||
componentId: comp.id,
|
||||
formValue,
|
||||
|
|
@ -281,7 +281,7 @@ export const EditModal: React.FC<EditModalProps> = ({
|
|||
left: component.position?.x || 0,
|
||||
width: component.size?.width || 200,
|
||||
height: component.size?.height || 40,
|
||||
zIndex: component.position?.z || (1000 + index), // 모달 내부에서 충분히 높은 z-index
|
||||
zIndex: component.position?.z || 1000 + index, // 모달 내부에서 충분히 높은 z-index
|
||||
}}
|
||||
>
|
||||
{/* 위젯 컴포넌트는 InteractiveScreenViewer 사용 (라벨 표시) */}
|
||||
|
|
|
|||
Loading…
Reference in New Issue