Skip to content

Commit d262bb4

Browse files
committed
feat: Implement mode 'truncate' in 'to_sql' API
1 parent 2abbcf3 commit d262bb4

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

pandas/io/sql.py

+35-1
Original file line numberDiff line numberDiff line change
@@ -970,11 +970,13 @@ def create(self) -> None:
970970
if self.exists():
971971
if self.if_exists == "fail":
972972
raise ValueError(f"Table '{self.name}' already exists.")
973-
if self.if_exists == "replace":
973+
elif self.if_exists == "replace":
974974
self.pd_sql.drop_table(self.name, self.schema)
975975
self._execute_create()
976976
elif self.if_exists == "append":
977977
pass
978+
elif self.if_exists == "truncate":
979+
self.pd_sql.truncate_table(self.name, self.schema)
978980
else:
979981
raise ValueError(f"'{self.if_exists}' is not valid for if_exists")
980982
else:
@@ -2047,6 +2049,25 @@ def drop_table(self, table_name: str, schema: str | None = None) -> None:
20472049
self.get_table(table_name, schema).drop(bind=self.con)
20482050
self.meta.clear()
20492051

2052+
def truncate_table(self, table_name: str, schema: str | None = None) -> None:
2053+
from sqlalchemy.exc import OperationalError
2054+
2055+
schema = schema or self.meta.schema
2056+
2057+
if self.has_table(table_name, schema):
2058+
self.meta.reflect(
2059+
bind=self.con, only=[table_name], schema=schema, views=True
2060+
)
2061+
with self.run_transaction():
2062+
table = self.get_table(table_name, schema)
2063+
try:
2064+
self.execute(f"TRUNCATE TABLE {table.name}")
2065+
except OperationalError:
2066+
raise NotImplementedError("'TRUNCATE' is not supported by this database.")
2067+
2068+
self.meta.clear()
2069+
2070+
20502071
def _create_sql_schema(
20512072
self,
20522073
frame: DataFrame,
@@ -2343,6 +2364,8 @@ def to_sql(
23432364
engine : {'auto', 'sqlalchemy'}, default 'auto'
23442365
Raises NotImplementedError if not set to 'auto'
23452366
"""
2367+
from adbc_driver_manager import ProgrammingError
2368+
23462369
if index_label:
23472370
raise NotImplementedError(
23482371
"'index_label' is not implemented for ADBC drivers"
@@ -2376,6 +2399,14 @@ def to_sql(
23762399
cur.execute(f"DROP TABLE {table_name}")
23772400
elif if_exists == "append":
23782401
mode = "append"
2402+
elif if_exists == "truncate":
2403+
mode = "append"
2404+
with self.con.cursor() as cur:
2405+
try:
2406+
cur.execute(f"TRUNCATE TABLE {table_name}")
2407+
except ProgrammingError:
2408+
raise NotImplementedError("'TRUNCATE' is not supported by this database.")
2409+
23792410

23802411
import pyarrow as pa
23812412

@@ -2857,6 +2888,9 @@ def drop_table(self, name: str, schema: str | None = None) -> None:
28572888
drop_sql = f"DROP TABLE {_get_valid_sqlite_name(name)}"
28582889
self.execute(drop_sql)
28592890

2891+
def truncate_table(self, name:str, schema: str | None) -> None:
2892+
raise NotImplementedError("'TRUNCATE' is not supported by this database.")
2893+
28602894
def _create_sql_schema(
28612895
self,
28622896
frame,

pandas/tests/io/test_sql.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -1067,12 +1067,19 @@ def test_to_sql(conn, method, test_frame1, request):
10671067

10681068

10691069
@pytest.mark.parametrize("conn", all_connectable)
1070-
@pytest.mark.parametrize("mode, num_row_coef", [("replace", 1), ("append", 2)])
1070+
@pytest.mark.parametrize("mode, num_row_coef", [("replace", 1), ("append", 2), ("truncate", 1)])
10711071
def test_to_sql_exist(conn, mode, num_row_coef, test_frame1, request):
1072+
connections_without_truncate = sqlite_connectable + ["sqlite_buildin", "sqlite_adbc_conn"]
1073+
if conn in connections_without_truncate and mode == "truncate":
1074+
context = pytest.raises(NotImplementedError)
1075+
else:
1076+
context = contextlib.nullcontext()
10721077
conn = request.getfixturevalue(conn)
1078+
10731079
with pandasSQL_builder(conn, need_transaction=True) as pandasSQL:
10741080
pandasSQL.to_sql(test_frame1, "test_frame", if_exists="fail")
1075-
pandasSQL.to_sql(test_frame1, "test_frame", if_exists=mode)
1081+
with context:
1082+
pandasSQL.to_sql(test_frame1, "test_frame", if_exists=mode)
10761083
assert pandasSQL.has_table("test_frame")
10771084
assert count_rows(conn, "test_frame") == num_row_coef * len(test_frame1)
10781085

0 commit comments

Comments
 (0)