Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/pages/programming/sql.md
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,15 @@ system table.

The ```REPLACE TABLE``` statement can be used to replace a table with another table.

The source table is specified using [foreign table](#foreign-tables) syntax. For a database running
on the same machine, use ```LOCAL_database.tablename```:

```sql
REPLACE TABLE mytable WITH LOCAL_sourcedb.sourcetable;
```

For remote databases, use ```database.tablename``` (requires [comdb2db](clients.html#comdb2db) configuration).

Below is a list of requirements that must be satisfied to use this statement:
- The source and destination databases have the same datastripe and blobstripe settings.
- There is no network firewall preventing the destination database from communicating
Expand Down
8 changes: 8 additions & 0 deletions schemachange/sc_import.c
Original file line number Diff line number Diff line change
Expand Up @@ -1812,6 +1812,14 @@ static enum comdb2_import_op get_import_rcode_from_tmpdb_rcode(const int rc) {

int do_import(struct ireq *iq, struct schema_change_type *sc, tran_type *tran)
{
extern int gbl_is_physical_replicant;
if (gbl_is_physical_replicant) {
logmsg(LOGMSG_ERROR, "%s: bulk import into a physical replicant is not allowed\n", __func__);
errstat_set_rcstrf(&iq->errstat, COMDB2_IMPORT_RC_INTERNAL,
"bulk import into a physical replicant is not allowed");
return COMDB2_IMPORT_RC_INTERNAL;
}

const char * const src_tablename = sc->import_src_tablename;
const char * const srcdb = sc->import_src_dbname;
const char * const dst_tablename = sc->tablename;
Expand Down
5 changes: 5 additions & 0 deletions sqlite/src/comdb2build.c
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,11 @@ void comdb2bulkimport(Parse* pParse, Token* nm,Token* lnm, Token* nm2, Token* ln

void comdb2Replace(Parse* pParse, Token *nm, Token *nm2, Token *nm3)
{
if (gbl_is_physical_replicant) {
setError(pParse, SQLITE_MISUSE, "bulk import into a physical replicant is not allowed");
return;
}

if (gbl_disable_sql_table_replacement) {
setError(pParse, SQLITE_MISUSE, "sql table replacement is disabled");
return;
Expand Down
125 changes: 125 additions & 0 deletions tests/phys_rep.test/bulkimport.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/bin/bash

bash -n "$0" || exit 1
source ${TESTSROOTDIR}/tools/runit_common.sh
set -o pipefail
set -x

DBNAME=$1
DBDIR=$2
destdb=${TESTCASE}dest${TESTID} #from runit
tmpdb_name="tmp${DBNAME}"
tmpdb_dir="${DBDIR}/${tmpdb_name}"

function check_rc() {
local cmd="$1"
eval $cmd
if [[ $? -ne 0 ]]; then
echo "failed running $cmd"
cleanup
exit 1
fi
}

# assumes we have comdb2db.cfg on testdir
# cause we sourcing runit_common.sh
function cp_comdb2dbcfg() {
dir=$1
name=$2
echo "comdb2_config:default_type=local" > "$dir/comdb2db.cfg"
echo "comdb2_config:ssl_cert_path=$TESTDIR" >>"$dir/comdb2db.cfg"
echo "comdb2_config:allow_pmux_route:true" >> "$dir/comdb2db.cfg"
}


function cleanup() {
# cleanup tmpdb only - parent and physrep are managed by runit
local name="$tmpdb_name" dir="$tmpdb_dir"
if [[ -f "$dir/${name}.pid" ]]; then
kill -9 $(cat "$dir/${name}.pid") 2>/dev/null || true
fi
}

function create_db() {
local name=$1 dir=$2
mkdir -p "$dir"
check_rc "$COMDB2_EXE --create $name -dir $dir"
$COMDB2_EXE $name --lrl $dir/${name}.lrl --pidfile $dir/${name}.pid >"$DBDIR/${name}.log" 2>&1 &
cp_comdb2dbcfg "$dir" "$name"
# Also add tmpdb to parent's config so destdb can find it
echo "$name $dir $dir/${name}.lrl" >> "$DBDIR/comdb2db.cfg"
sleep 5
check_rc "${CDB2SQL_EXE} --cdb2cfg $dir/comdb2db.cfg $name default 'select 1' "
check_rc "${CDB2SQL_EXE} --cdb2cfg $dir/comdb2db.cfg $name -f ${TESTDIR}/${TESTCASE}.test/1-create-table.src.sql default "
check_rc "${CDB2SQL_EXE} --cdb2cfg $dir/comdb2db.cfg $name default \"insert into t1 (id) values (1)\" "
}

function test_bulkimport_into_physrep() {
# Given: destdb is already a physrep (set up by runit)

# When: bulk import into the physrep (destdb)
local tbl="t1"
local output
output=$(${CDB2SQL_EXE} --cdb2cfg $DBDIR/comdb2db.cfg $destdb --host localhost \
"replace table $tbl with LOCAL_$tmpdb_name.$tbl" 2>&1)
local rc=$?

# Then: bulkimport should fail with the correct error message
if [[ $rc -eq 0 ]] || ! echo "$output" | grep -q "physical replicant" ; then
echo "Fail, rc=$rc, output: $output"
cleanup
exit 1
fi

echo "SUCCESS: bulkimport rejected with error: $output"
}

function test_bulkimport_from_physrep() {
# Given: destdb is a physrep with replicated data from DBNAME
# We reuse tmpdb as the destination and import FROM the physrep
local tbl="t1"

check_rc "${CDB2SQL_EXE} ${CDB2_OPTIONS} $DBNAME default \"drop table if exists $tbl\" "
check_rc "${CDB2SQL_EXE} ${CDB2_OPTIONS} $DBNAME default -f ${TESTDIR}/${TESTCASE}.test/1-create-table.src.sql"
check_rc "${CDB2SQL_EXE} ${CDB2_OPTIONS} $DBNAME default \"insert into $tbl (id) values (100), (200), (300)\" "
sleep 5
check_rc "${CDB2SQL_EXE} --cdb2cfg $tmpdb_dir/comdb2db.cfg $tmpdb_name default \"delete from $tbl where 1\" "

# When: bulk import FROM the physrep to the tmpdb
local output
output=$(${CDB2SQL_EXE} --cdb2cfg $tmpdb_dir/comdb2db.cfg $tmpdb_name default \
"replace table $tbl with LOCAL_$destdb.$tbl" 2>&1)
local rc=$?

# Then: bulkimport should succeed
if [[ $rc -ne 0 ]]; then
echo "FAIL: bulkimport from physrep failed with rc=$rc"
echo "Output: $output"
cleanup
exit 1
fi

# Verify data was imported
local cnt
cnt=$(${CDB2SQL_EXE} --tabs --cdb2cfg $tmpdb_dir/comdb2db.cfg $tmpdb_name default "select count(*) from $tbl")
if [[ $cnt -eq 0 ]]; then
echo "FAIL: no records found in $tmpdb_name.$tbl after import from physrep"
cleanup
exit 1
fi

echo "SUCCESS: bulk import from physrep succeeded, imported $cnt records"
}

function main() {
create_db "$tmpdb_name" "$tmpdb_dir"

test_bulkimport_into_physrep

test_bulkimport_from_physrep

echo "All tests passed"
cleanup
}

main
9 changes: 9 additions & 0 deletions tests/phys_rep.test/runit
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,17 @@ trap - INT EXIT

override_physrep_sp
setup_replicant

${CDB2SQL_EXE} ${CDB2_OPTIONS} $dbname default "exec procedure sys.cmd.send('semver 8.1.0')"
${CDB2SQL_EXE} --host localhost $destdb default "exec procedure sys.cmd.send('semver 8.1.0')"

./generate_tests.sh
run_tests

# (physrep needs to be alive)
./bulkimport.sh $dbname ${DBDIR}
[[ $? -ne 0 ]] && failexit "bulkimport test failed"

cleanup

exit 0
Loading