diff --git a/ui/src/views/developerKit/SqlTableDesignerDialog.tsx b/ui/src/views/developerKit/SqlTableDesignerDialog.tsx
index c1fdc05..cec03df 100644
--- a/ui/src/views/developerKit/SqlTableDesignerDialog.tsx
+++ b/ui/src/views/developerKit/SqlTableDesignerDialog.tsx
@@ -224,6 +224,8 @@ const TENANT_COLUMN: ColumnDefinition = {
description: 'Tenant ID for multi-tenancy',
}
+const CREATE_TABLE_SCRIPT_STORAGE_KEY = 'sqlQueryManager.lastCreateTableScript'
+
// ─── T-SQL Generator ──────────────────────────────────────────────────────────
function colToSqlLine(col: ColumnDefinition, addComma = true): string {
@@ -377,6 +379,136 @@ function dbColToColumnDef(col: {
}
}
+function splitByTopLevelComma(input: string): string[] {
+ const parts: string[] = []
+ let current = ''
+ let depth = 0
+
+ for (let i = 0; i < input.length; i++) {
+ const ch = input[i]
+ if (ch === '(') depth++
+ if (ch === ')') depth = Math.max(0, depth - 1)
+
+ if (ch === ',' && depth === 0) {
+ if (current.trim()) parts.push(current.trim())
+ current = ''
+ continue
+ }
+
+ current += ch
+ }
+
+ if (current.trim()) parts.push(current.trim())
+ return parts
+}
+
+function unwrapDefaultExpression(value: string): string {
+ let result = value.trim()
+ while (result.startsWith('(') && result.endsWith(')')) {
+ result = result.slice(1, -1).trim()
+ }
+ return result
+}
+
+function mapSqlTypeToDesigner(dataTypeRaw: string, lengthRaw: string): {
+ dataType: SqlDataType
+ maxLength: string
+} {
+ const dt = dataTypeRaw.toLowerCase()
+ const len = lengthRaw.toLowerCase()
+
+ if (dt === 'nvarchar' || dt === 'varchar' || dt === 'char' || dt === 'nchar') {
+ if (len === 'max') {
+ return { dataType: 'nvarchar(MAX)', maxLength: '' }
+ }
+ return { dataType: 'nvarchar', maxLength: len || '100' }
+ }
+
+ if (dt === 'int') return { dataType: 'int', maxLength: '' }
+ if (dt === 'bigint') return { dataType: 'bigint', maxLength: '' }
+ if (dt === 'decimal' || dt === 'numeric') return { dataType: 'decimal', maxLength: '' }
+ if (dt === 'float' || dt === 'real') return { dataType: 'float', maxLength: '' }
+ if (dt === 'bit') return { dataType: 'bit', maxLength: '' }
+ if (dt.startsWith('datetime') || dt === 'smalldatetime' || dt === 'time') {
+ return { dataType: 'datetime2', maxLength: '' }
+ }
+ if (dt === 'date') return { dataType: 'date', maxLength: '' }
+ if (dt === 'uniqueidentifier') return { dataType: 'uniqueidentifier', maxLength: '' }
+ if (dt === 'money' || dt === 'smallmoney') return { dataType: 'money', maxLength: '' }
+
+ return { dataType: 'nvarchar', maxLength: '100' }
+}
+
+function parseCreateTableColumns(script: string): ColumnDefinition[] {
+ if (!script?.trim()) return []
+
+ const createIdx = script.search(/\bCREATE\s+TABLE\b/i)
+ if (createIdx < 0) return []
+
+ const openParenIdx = script.indexOf('(', createIdx)
+ if (openParenIdx < 0) return []
+
+ let depth = 0
+ let closeParenIdx = -1
+ for (let i = openParenIdx; i < script.length; i++) {
+ const ch = script[i]
+ if (ch === '(') depth++
+ if (ch === ')') {
+ depth--
+ if (depth === 0) {
+ closeParenIdx = i
+ break
+ }
+ }
+ }
+
+ if (closeParenIdx < 0) return []
+
+ const body = script.slice(openParenIdx + 1, closeParenIdx)
+ const defs = splitByTopLevelComma(body)
+ const columns: ColumnDefinition[] = []
+
+ for (const def of defs) {
+ const trimmed = def.trim()
+ if (!trimmed) continue
+
+ if (
+ /^(CONSTRAINT|PRIMARY\s+KEY|UNIQUE\s+KEY|UNIQUE|FOREIGN\s+KEY|CHECK)\b/i.test(trimmed)
+ ) {
+ continue
+ }
+
+ const colMatch = trimmed.match(/^\[([^\]]+)\]\s+(.+)$/i)
+ if (!colMatch) continue
+
+ const columnName = colMatch[1].trim()
+ const rest = colMatch[2].trim()
+
+ const typeMatch = rest.match(/^\[?([A-Za-z0-9_]+)\]?\s*(?:\(([^)]*)\))?/)
+ if (!typeMatch) continue
+
+ const sqlType = typeMatch[1] ?? 'nvarchar'
+ const sqlLength = (typeMatch[2] ?? '').trim()
+ const mapped = mapSqlTypeToDesigner(sqlType, sqlLength)
+
+ const isNullable = !/\bNOT\s+NULL\b/i.test(rest)
+ const defaultMatch = rest.match(/\bDEFAULT\b\s+(.+)$/i)
+ const defaultValue = defaultMatch ? unwrapDefaultExpression(defaultMatch[1]) : ''
+
+ columns.push({
+ id: crypto.randomUUID(),
+ columnName,
+ dataType: mapped.dataType,
+ maxLength: mapped.maxLength,
+ isNullable,
+ defaultValue,
+ description: '',
+ })
+ }
+
+ return columns
+}
+
/** Generate ALTER TABLE diff SQL (edit mode) */
function generateAlterTableSql(
originalCols: ColumnDefinition[],
@@ -1025,6 +1157,84 @@ const SqlTableDesignerDialog = ({
}
}
+ const importColumnsFromRememberedCreateTable = async () => {
+ let script = ''
+
+ try {
+ const clipboardText = await navigator.clipboard.readText()
+ if (/\bCREATE\s+TABLE\b/i.test(clipboardText)) {
+ script = clipboardText
+ localStorage.setItem(CREATE_TABLE_SCRIPT_STORAGE_KEY, clipboardText)
+ }
+ } catch {
+ // Clipboard read can fail due to browser permissions; fallback to saved script.
+ }
+
+ if (!script) {
+ script = localStorage.getItem(CREATE_TABLE_SCRIPT_STORAGE_KEY) || ''
+ }
+
+ if (!script.trim()) {
+ toast.push(
+