Skip to content

Commit c122382

Browse files
committed
Merge remote-tracking branch 'origin/main' into saumya/pool-c++
2 parents d373e9b + fc99220 commit c122382

File tree

3 files changed

+126
-1
lines changed

3 files changed

+126
-1
lines changed

mssql_python/bcp_options.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
from dataclasses import dataclass, field
2+
from typing import List, Optional, Literal
3+
4+
5+
@dataclass
6+
class ColumnFormat:
7+
"""
8+
Represents the format of a column in a bulk copy operation.
9+
Attributes:
10+
prefix_len (int): Option: (format_file) or (prefix_len, data_len).
11+
The length of the prefix for fixed-length data types. Must be non-negative.
12+
data_len (int): Option: (format_file) or (prefix_len, data_len).
13+
The length of the data. Must be non-negative.
14+
field_terminator (Optional[bytes]): Option: (-t). The field terminator string.
15+
e.g., b',' for comma-separated values.
16+
row_terminator (Optional[bytes]): Option: (-r). The row terminator string.
17+
e.g., b'\\n' for newline-terminated rows.
18+
server_col (int): Option: (format_file) or (server_col). The 1-based column number
19+
in the SQL Server table. Defaults to 1, representing the first column.
20+
Must be a positive integer.
21+
file_col (int): Option: (format_file) or (file_col). The 1-based column number
22+
in the data file. Defaults to 1, representing the first column.
23+
Must be a positive integer.
24+
"""
25+
26+
prefix_len: int
27+
data_len: int
28+
field_terminator: Optional[bytes] = None
29+
row_terminator: Optional[bytes] = None
30+
server_col: int = 1
31+
file_col: int = 1
32+
33+
def __post_init__(self):
34+
if self.prefix_len < 0:
35+
raise ValueError("prefix_len must be a non-negative integer.")
36+
if self.data_len < 0:
37+
raise ValueError("data_len must be a non-negative integer.")
38+
if self.server_col <= 0:
39+
raise ValueError("server_col must be a positive integer (1-based).")
40+
if self.file_col <= 0:
41+
raise ValueError("file_col must be a positive integer (1-based).")
42+
if self.field_terminator is not None and not isinstance(
43+
self.field_terminator, bytes
44+
):
45+
raise TypeError("field_terminator must be bytes or None.")
46+
if self.row_terminator is not None and not isinstance(
47+
self.row_terminator, bytes
48+
):
49+
raise TypeError("row_terminator must be bytes or None.")
50+
51+
52+
@dataclass
53+
class BCPOptions:
54+
"""
55+
Represents the options for a bulk copy operation.
56+
Attributes:
57+
direction (Literal[str]): 'in' or 'out'. Option: (-i or -o).
58+
data_file (str): The data file. Option: (positional argument).
59+
error_file (Optional[str]): The error file. Option: (-e).
60+
format_file (Optional[str]): The format file to use for 'in'/'out'. Option: (-f).
61+
batch_size (Optional[int]): The batch size. Option: (-b).
62+
max_errors (Optional[int]): The maximum number of errors allowed. Option: (-m).
63+
first_row (Optional[int]): The first row to process. Option: (-F).
64+
last_row (Optional[int]): The last row to process. Option: (-L).
65+
code_page (Optional[str]): The code page. Option: (-C).
66+
keep_identity (bool): Keep identity values. Option: (-E).
67+
keep_nulls (bool): Keep null values. Option: (-k).
68+
hints (Optional[str]): Additional hints. Option: (-h).
69+
bulk_mode (str): Bulk mode ('native', 'char', 'unicode'). Option: (-n, -c, -w).
70+
Defaults to "native".
71+
columns (List[ColumnFormat]): Column formats.
72+
"""
73+
74+
direction: Literal["in", "out"]
75+
data_file: str # data_file is mandatory for 'in' and 'out'
76+
error_file: Optional[str] = None
77+
format_file: Optional[str] = None
78+
# write_format_file is removed as 'format' direction is not actively supported
79+
batch_size: Optional[int] = None
80+
max_errors: Optional[int] = None
81+
first_row: Optional[int] = None
82+
last_row: Optional[int] = None
83+
code_page: Optional[str] = None
84+
keep_identity: bool = False
85+
keep_nulls: bool = False
86+
hints: Optional[str] = None
87+
bulk_mode: Literal["native", "char", "unicode"] = "native"
88+
columns: List[ColumnFormat] = field(default_factory=list)
89+
90+
def __post_init__(self):
91+
if self.direction not in ["in", "out"]:
92+
raise ValueError("direction must be 'in' or 'out'.")
93+
if not self.data_file:
94+
raise ValueError("data_file must be provided and non-empty for 'in' or 'out' directions.")
95+
if self.error_file is None or not self.error_file: # Making error_file mandatory for in/out
96+
raise ValueError("error_file must be provided and non-empty for 'in' or 'out' directions.")
97+
98+
if self.format_file is not None and not self.format_file:
99+
raise ValueError("format_file, if provided, must not be an empty string.")
100+
if self.batch_size is not None and self.batch_size <= 0:
101+
raise ValueError("batch_size must be a positive integer.")
102+
if self.max_errors is not None and self.max_errors < 0:
103+
raise ValueError("max_errors must be a non-negative integer.")
104+
if self.first_row is not None and self.first_row <= 0:
105+
raise ValueError("first_row must be a positive integer.")
106+
if self.last_row is not None and self.last_row <= 0:
107+
raise ValueError("last_row must be a positive integer.")
108+
if self.last_row is not None and self.first_row is None:
109+
raise ValueError("first_row must be specified if last_row is specified.")
110+
if (
111+
self.first_row is not None
112+
and self.last_row is not None
113+
and self.last_row < self.first_row
114+
):
115+
raise ValueError("last_row must be greater than or equal to first_row.")
116+
if self.code_page is not None and not self.code_page:
117+
raise ValueError("code_page, if provided, must not be an empty string.")
118+
if self.hints is not None and not self.hints:
119+
raise ValueError("hints, if provided, must not be an empty string.")
120+
if self.bulk_mode not in ["native", "char", "unicode"]:
121+
raise ValueError("bulk_mode must be 'native', 'char', or 'unicode'.")

mssql_python/pybind/connection/connection.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "connection.h"
88
#include "connection_pool.h"
9+
910
#include <vector>
1011
#include <pybind11/pybind11.h>
1112

@@ -285,4 +286,4 @@ SqlHandlePtr ConnectionHandle::allocStatementHandle() {
285286
ThrowStdException("Connection object is not initialized");
286287
}
287288
return _conn->allocStatementHandle();
288-
}
289+
}

mssql_python/pybind/ddbc_bindings.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
// taken up in beta release
66
#include "ddbc_bindings.h"
77
#include "connection/connection.h"
8+
<<<<<<< HEAD
89
#include "connection/connection_pool.h"
10+
=======
11+
>>>>>>> origin/main
912

1013
#include <cstdint>
1114
#include <iomanip> // std::setw, std::setfill

0 commit comments

Comments
 (0)