[CBRD-27336] Support a remote REPLACE ... SELECT whose source is a local table - #7985
Open
kwangsoochae wants to merge 7 commits into
Open
kwangsoochae wants to merge 7 commits into
kwangsoochae wants to merge 7 commits into
Conversation
❌ TC Merge Gate — Merge BlockedTC changes for this PR are not on TC develop yet.
|
Contributor
Author
|
@greptileai review |
🧪 TC Test Environment ReadyCircleCI Testing:
TC Repositories & Branches:
Next Steps:
|
Contributor
Author
|
/run all |
Contributor
|
이전 리뷰 이후 변경에서 병합을 막을 새 결함이 확인되지 않아 현재 상태는 병합해도 안전해 보입니다. Reviews (2) · Last reviewed commit: "Merge remote-tracking branch 'upstream/d..." |
Contributor
Author
|
/run all |
kwangsoochae
force-pushed
the
CBRD-27336_dblink_replace_local_source
branch
from
September 22, 2026 00:20
a4eb40f to
6a0cd50
Compare
Contributor
Author
|
/run shell |
kwangsoochae
force-pushed
the
CBRD-27336_dblink_replace_local_source
branch
from
September 22, 2026 11:00
6a0cd50 to
fd49b61
Compare
The sink builds one statement kind, a plain INSERT. A REPLACE that reached it would insert instead of replacing, so the parser gate refuses the shape and the statement falls through to the mixed local/remote rejection. Give DBLINK_DML_KIND a REPLACE member and let the builder switch the prefix. Nothing else about the statement changes -- REPLACE takes an INSERT's shape, so the column list, the placeholders and the values the sink binds are the same, and the two kinds share a case wherever the executor reads INSERT_PROC. The builder's own diagnostics name the statement it was asked for rather than always saying INSERT. The leading /* DBLINK ... */ comment is not a label. A CUBRID gateway reads the word after DBLINK and maps it to a statement type, refusing the statement when the word is not one it knows, and that vocabulary has no REPLACE. Both kinds carry INSERT there and the statement itself says which one it is. The gate stays shut: do_replace never reaches the plan yet, so the executor still picks INSERT. The commit that opens it comes last, so no revision in between sends the wrong statement to a remote.
The INSERT sink counted one row per statement it sent, because a positional INSERT of one row was expected to affect exactly one. A REPLACE breaks that: the remote counts the row it removed as well as the one it inserted, so a row that replaces answers 2. Read affected_rows and add it, the way the DELETE sink already does. The text-push path reports the remote's number as it stands, so the two paths now answer alike for the same statement. This also changes what a plain INSERT sink reports if a remote ever answers with something other than 1. The old comment named that case and left it out of scope; it was not reproduced on the remotes the INSERT sink was measured against, so nothing observed changes here. The callee's header no longer offers the INSERT sink as the example of a caller that ignores the count, and the comment naming which statements reach cci_execute is dropped rather than extended -- what runs there is whatever the prepare built.
The gate admitted only a plain INSERT ... SELECT, so a REPLACE whose source was local fell through to the mixed local/remote rejection. The sink can send the statement now, and the plan carries which one it is, so the shape has somewhere to go. Drop do_replace from the gate's exclusions and set it on the remote sink's plan. ODKU stays out: the sink has nowhere to carry the update assignments yet. This also admits a source that mixes a local table with a remote one on the target's own server. case PT_INSERT counts sub_sel_server_cnt whatever the sink kind, so the same-server conversion those sources need is already wired -- holding the shape back would mean adding a guard to refuse what otherwise works. The comment that deferred both clauses quoted a rejection message CBRD-26921 has since replaced, and is rewritten to say what the gate now admits.
kwangsoochae
force-pushed
the
CBRD-27336_dblink_replace_local_source
branch
from
September 22, 2026 11:00
fd49b61 to
996e1a0
Compare
Contributor
Author
|
/run all |
do_prepare_insert () marks a source query with a compile-time false WHERE by leaving xasl_id NULL: there is nothing to execute. do_execute_insert () skipped that check for a remote target, so a remote INSERT or REPLACE with a local source that reduces to false -- WHERE 1 = 0, or a view defined with such a condition -- asked the server to run a NULL XASL and the client died. Return with no rows when a remote target has no XASL, as do_execute_delete () already does for false where or a statement that did not prepare correctly. The do_insert () fallback stays with local targets, as CBRD-24867 left it.
…k_replace_local_source
Contributor
Author
|
/run all |
The comment over the remote INSERT gate ended by calling the mixed local/remote rejection "the same behavior develop gives for it". Once this lands, develop is this code, so the phrase stops saying anything. The comment in do_execute_insert () named CBRD-24867 as the origin of the local-only do_insert () fallback. That ticket gives no reason for it, so the number tells a reader no more than git blame does.
…k_replace_local_source
Contributor
Author
|
/run all |
Contributor
Author
|
/run rerun 35818139527 |
kwangsoochae
requested review from
airnet73,
beyondykk9,
childyouth,
ctshim,
hyunikn,
jongmin-won and
kangmin5505
September 23, 2026 05:40
kwangsoochae
marked this pull request as ready for review
September 23, 2026 05:40
beyondykk9
removed request for
airnet73,
childyouth,
ctshim,
hyunikn,
jongmin-won and
kangmin5505
September 27, 2026 22:49
beyondykk9
approved these changes
Sep 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
http://jira.cubrid.org/browse/CBRD-27336
Purpose
원격 테이블 대상
REPLACE는 리터럴 형태만 동작하고(문장이 그대로 원격에 전달된다), 소스가 로컬 테이블이면파서가 거절했다.
INSERT ... SELECT는 로컬에서 행을 만들어 원격에 보내는 값 sink 로 로컬 소스를 받는다. 이 sink 는 소스의행마다 원격에 한 문장씩 보내고,
REPLACE도 행 단위로 처리된다 — 같은 키가 소스에 여러 행 있으면 소스 질의순서상 마지막 행이 남는다. 따라서 새 실행 모드 없이 sink 가 준비하는 문장을
REPLACE INTO로 바꾸면 같은 결과에 도달한다.Implementation
커밋 단위로 리뷰할 수 있도록 세 단계로 나눴다. 네 번째 커밋은 Remarks 첫 항목의 선행 결함
수정이고, 그 뒤는 주석 정리와 develop merge 다.
1. 원격에 보낼 문장을 조립한다
DBLINK_DML_KIND에REPLACE를 더하고 문장 조립 함수가 접두만 가르게 한다. 컬럼 목록·자리표·바인드 값은INSERT와 같으므로, 실행기에서INSERT_PROC를 읽는 자리들은 두 종류가case를 공유한다.문장 머리의
/* DBLINK ... */주석은 게이트웨이가 문장 종류로 읽는 값이고, 그 어휘에REPLACE가 없다.그래서 두 종류 모두
INSERT를 싣는다.2. 원격이 보고한 행 수를 그대로 누적한다
INSERTsink 는 문장마다 1 을 셌지만,REPLACE는 교체가 일어난 행에 원격이 2 를 돌려준다. 원격이 돌려주는수를 누적하도록 바꿨다(원격
DELETEsink 와 같은 방식).3. 게이트를 연다
sink 자격 조건에서
REPLACE제외를 걷어내고 문장 종류를 실행 계획에 싣는다. 직렬화 포맷은 바뀌지 않는다 —그 필드는 이미 전송되고 있었다.
소스가 로컬과 타깃 서버의 원격 테이블을 함께 읽는 형태도 함께 열린다. sink 자격을 넓히면 그대로 닿는 경로라
따로 막지 않았다.
Remarks
INSERT/REPLACE의 로컬 소스가 컴파일 시점에거짓이면(
WHERE 1 = 0, 그런 조건을 정의에 가진 뷰) 클라이언트가 죽었다. develop 에서는 로컬 소스REPLACE가거절돼
INSERT에만 드러나던 결함인데, 이 PR 이REPLACE를 열면 그대로 상속한다. XASL 이 없는 원격 대상은원격
DELETE와 같이 0 행으로 끝낸다(do_execute_insert).ON DUPLICATE KEY UPDATE는 범위 밖이며 지금과 같이 거절한다(sink 에 갱신 대입을 실을 자리가 없다). 별도 PR 로 뗀다.REPLACE구문이 없어 원격이 거절한다 — 리터럴 형태와 같은 자리, 같은 이유다.