버튼에 제어 달기

This commit is contained in:
kjs
2025-09-29 15:21:14 +09:00
parent e057c4d960
commit 3c26f24179
17 changed files with 291 additions and 71 deletions

View File

@@ -144,21 +144,133 @@ export class MultiConnectionQueryService {
}
const connection = connectionResult.data;
// INSERT 쿼리 구성
// INSERT 쿼리 구성 (DB 타입별 처리)
const columns = Object.keys(data);
const values = Object.values(data);
const placeholders = values.map((_, index) => `$${index + 1}`).join(", ");
let values = Object.values(data);
// Oracle의 경우 테이블 스키마 확인 및 데이터 타입 변환 처리
if (connection.db_type?.toLowerCase() === 'oracle') {
try {
// Oracle 테이블 스키마 조회
const schemaQuery = `
SELECT COLUMN_NAME, DATA_TYPE, NULLABLE, DATA_DEFAULT
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = UPPER('${tableName}')
ORDER BY COLUMN_ID
`;
logger.info(`🔍 Oracle 테이블 스키마 조회: ${schemaQuery}`);
const schemaResult = await ExternalDbConnectionService.executeQuery(
connectionId,
schemaQuery
);
if (schemaResult.success && schemaResult.data) {
logger.info(`📋 Oracle 테이블 ${tableName} 스키마:`);
schemaResult.data.forEach((col: any) => {
logger.info(` - ${col.COLUMN_NAME}: ${col.DATA_TYPE}, NULL: ${col.NULLABLE}, DEFAULT: ${col.DATA_DEFAULT || 'None'}`);
});
// 필수 컬럼 중 누락된 컬럼이 있는지 확인 (기본값이 없는 NOT NULL 컬럼만)
const providedColumns = columns.map(col => col.toUpperCase());
const missingRequiredColumns = schemaResult.data.filter((schemaCol: any) =>
schemaCol.NULLABLE === 'N' &&
!schemaCol.DATA_DEFAULT &&
!providedColumns.includes(schemaCol.COLUMN_NAME)
);
if (missingRequiredColumns.length > 0) {
const missingNames = missingRequiredColumns.map((col: any) => col.COLUMN_NAME);
logger.error(`❌ 필수 컬럼 누락: ${missingNames.join(', ')}`);
throw new Error(`필수 컬럼이 누락되었습니다: ${missingNames.join(', ')}`);
}
logger.info(`✅ 스키마 검증 통과: 모든 필수 컬럼이 제공되었거나 기본값이 있습니다.`);
}
} catch (schemaError) {
logger.warn(`⚠️ 스키마 조회 실패 (계속 진행): ${schemaError}`);
}
values = values.map(value => {
// null이나 undefined는 그대로 유지
if (value === null || value === undefined) {
return value;
}
// 숫자로 변환 가능한 문자열은 숫자로 변환
if (typeof value === 'string' && value.trim() !== '') {
const numValue = Number(value);
if (!isNaN(numValue)) {
logger.info(`🔄 Oracle 데이터 타입 변환: "${value}" (string) → ${numValue} (number)`);
return numValue;
}
}
return value;
});
}
let query: string;
let queryParams: any[];
const dbType = connection.db_type?.toLowerCase() || 'postgresql';
const query = `
INSERT INTO ${tableName} (${columns.join(", ")})
VALUES (${placeholders})
RETURNING *
`;
switch (dbType) {
case 'oracle':
// Oracle: :1, :2 스타일 바인딩 사용, RETURNING 미지원
const oraclePlaceholders = values.map((_, index) => `:${index + 1}`).join(", ");
query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${oraclePlaceholders})`;
queryParams = values;
logger.info(`🔍 Oracle INSERT 상세 정보:`);
logger.info(` - 테이블: ${tableName}`);
logger.info(` - 컬럼: ${JSON.stringify(columns)}`);
logger.info(` - 값: ${JSON.stringify(values)}`);
logger.info(` - 쿼리: ${query}`);
logger.info(` - 파라미터: ${JSON.stringify(queryParams)}`);
logger.info(` - 데이터 타입: ${JSON.stringify(values.map(v => typeof v))}`);
break;
case 'mysql':
case 'mariadb':
// MySQL/MariaDB: ? 스타일 바인딩 사용, RETURNING 미지원
const mysqlPlaceholders = values.map(() => '?').join(", ");
query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${mysqlPlaceholders})`;
queryParams = values;
logger.info(`MySQL/MariaDB INSERT 쿼리:`, { query, params: queryParams });
break;
case 'sqlserver':
case 'mssql':
// SQL Server: @param1, @param2 스타일 바인딩 사용
const sqlServerPlaceholders = values.map((_, index) => `@param${index + 1}`).join(", ");
query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${sqlServerPlaceholders})`;
queryParams = values;
logger.info(`SQL Server INSERT 쿼리:`, { query, params: queryParams });
break;
case 'sqlite':
// SQLite: ? 스타일 바인딩 사용, RETURNING 지원 (3.35.0+)
const sqlitePlaceholders = values.map(() => '?').join(", ");
query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${sqlitePlaceholders}) RETURNING *`;
queryParams = values;
logger.info(`SQLite INSERT 쿼리:`, { query, params: queryParams });
break;
case 'postgresql':
default:
// PostgreSQL: $1, $2 스타일 바인딩 사용, RETURNING 지원
const pgPlaceholders = values.map((_, index) => `$${index + 1}`).join(", ");
query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${pgPlaceholders}) RETURNING *`;
queryParams = values;
logger.info(`PostgreSQL INSERT 쿼리:`, { query, params: queryParams });
break;
}
// 외부 DB에서 쿼리 실행
const result = await ExternalDbConnectionService.executeQuery(
connectionId,
query
query,
queryParams
);
if (!result.success || !result.data) {