VARCHAR2(4000 CHAR) Might Not Store 4000 Characters

VARCHAR2(4000) means 4000 bytes, not characters. Most people know this. What's less obvious: VARCHAR2(4000 CHAR) doesn't guarantee 4000 characters either.

Under the default MAX_STRING_SIZE=STANDARD, the hard column cap is 4000 bytes regardless of whether you declared BYTE or CHAR. In AL32UTF8, a Chinese character takes ~3 bytes, so VARCHAR2(4000 CHAR) on a column storing CJK text will fail once the actual byte count exceeds 4000 — around ~1333 characters in.

To actually store 4000 CJK characters in a single VARCHAR2, the instance needs MAX_STRING_SIZE=EXTENDED (12c+), which raises the limit to 32767 bytes. This is not the default — not even in 19c — and it's a one-way migration that requires running utl32k.sql in upgrade mode. Oracle keeps it off by default precisely because it changes data dictionary behavior and breaks compatibility.

Quick check for your instance:

SELECT value FROM v$parameter WHERE name = 'max_string_size';

STANDARD = 4000-byte ceiling. EXTENDED = 32767-byte ceiling.

Suppress SQLcl Banner and Version Noise with -S

When scripting with Oracle SQLcl, the startup banner (version, copyright, connection info) clamps your output. The -S (silent) flag suppresses all of it:

sql -S user/password@connect_string @script.sql

This gives you clean output suitable for piping or log capture.

For even more control inside the session, pair it with:

set heading off
set feedback off
set pagesize 0
set echo off

-S is the entry-level switch. The set commands handle the rest.

Cloning an EC2 Instance: Three Ways

AWS console offers three ways to duplicate an EC2 instance, differing in whether disk data is carried over.

Create AMI (recommended, full clone) — preserves the system disk, installed software, and all configuration.

In the EC2 console, select the target instance → Actions → Image and templates → Create image. Wait for the AMI status to become available (a few minutes to tens of minutes), then go to AMIs → select it → Launch instance from AMI. Adjust instance type, subnet, Security Group as needed.

Launch More Like This (fastest, no data) — copies only instance configuration (type, SG, subnet, tags). The system disk is brand new.

Actions → Image and templates → Launch more like this. The Launch page opens with config pre-filled; confirm and launch. Good for stateless instances, e.g. web servers initialized via userdata.

Launch Template — if the original instance had a Launch Template saved, launch directly from it. EC2 → Launch Templates → select template → Actions → Launch instance from template.

Use AMI for most cases. Use Launch More Like This when you only need the same specs with a clean disk.

照着现有 EC2 开一台一样的:三种方式

AWS 控制台里有三种复制 EC2 的方式,区别在于是否携带磁盘数据。

创建 AMI(推荐,完整克隆) — 保留系统盘数据、已安装软件和所有配置。

EC2 控制台选中目标实例 → Actions → Image and templates → Create image。等 AMI 状态变为 available(几分钟到几十分钟),再到 AMIs 页面选中它 → Launch instance from AMI,按需调整 instance type、subnet、Security Group 即可。

Launch More Like This(最快,但不含数据) — 只复制实例规格配置(type、SG、subnet、tags),系统盘是全新的。

Actions → Image and templates → Launch more like this,进入 Launch 页面时配置已预填好,确认启动就行。适合无状态实例,比如用 userdata 初始化的 web server。

Launch Template — 如果原实例之前保存过 Launch Template,可以直接从模板启动。EC2 → Launch Templates → 选模板 → Actions → Launch instance from template。

大多数场景用 AMI,只需要同规格全新系统时用 Launch More Like This。

Why Vite dev server needs a proxy (and production doesn't)

In development, your frontend runs on localhost:5173 and your API server on localhost:3000. The browser blocks cross-origin requests — that's CORS. Vite's dev proxy solves this by forwarding /api/* requests to the backend, making them look same-origin to the browser:

// vite.config.ts
server: {
  proxy: {
    '/api': 'http://localhost:3000'
  }
}

In production this proxy disappears. The built frontend is just static files (HTML/JS/CSS) — no port, no process. Nginx or a CDN serves them, and reverse-proxies /api/* to the backend the same way Vite did in dev:

user → Nginx :80
         ├── /api/*  → backend :3000
         └── /*      → dist/ static files

One port from the user's perspective, no CORS issue. The backend port is always real and needed; the frontend "port" only exists during development because Vite's dev server is a live process.