pg-batch 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pg_batch/__init__.py +0 -0
- pg_batch/__main__.py +4 -0
- pg_batch/pg_batch.py +283 -0
- pg_batch-1.2.0.dist-info/METADATA +173 -0
- pg_batch-1.2.0.dist-info/RECORD +9 -0
- pg_batch-1.2.0.dist-info/WHEEL +5 -0
- pg_batch-1.2.0.dist-info/entry_points.txt +2 -0
- pg_batch-1.2.0.dist-info/licenses/LICENSE +21 -0
- pg_batch-1.2.0.dist-info/top_level.txt +1 -0
pg_batch/__init__.py
ADDED
|
File without changes
|
pg_batch/__main__.py
ADDED
pg_batch/pg_batch.py
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# Author: Gabriel Bordeaux (gabfl)
|
|
4
|
+
# Github: https://github.com/gabfl/pg-batch
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
import time
|
|
8
|
+
import psycopg2
|
|
9
|
+
import psycopg2.extras
|
|
10
|
+
import argparse
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def update_batch(ids, table, set_, sleep=0, primary_key='id'):
|
|
14
|
+
"""
|
|
15
|
+
Update a batch of rows
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
global confirmed_write
|
|
19
|
+
|
|
20
|
+
# Leave if ids is empty
|
|
21
|
+
if not ids or len(ids) == 0:
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
# Prepare update
|
|
25
|
+
print('* Updating %i rows...' % len(ids))
|
|
26
|
+
sql = "UPDATE " + table + " SET " + set_ + \
|
|
27
|
+
" WHERE {0} IN (".format(primary_key) + \
|
|
28
|
+
', '.join([str(x) for x in ids]) + ")"
|
|
29
|
+
print(" query: " + sql)
|
|
30
|
+
|
|
31
|
+
if confirmed_write or query_yes_no("* Start updating?"):
|
|
32
|
+
# Switch confirmed_write skip the question for the next update
|
|
33
|
+
confirmed_write = True
|
|
34
|
+
|
|
35
|
+
# Execute query
|
|
36
|
+
run_query(sql, sleep)
|
|
37
|
+
else: # answered "no"
|
|
38
|
+
print("Error: Update declined.")
|
|
39
|
+
sys.exit()
|
|
40
|
+
|
|
41
|
+
return True
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def delete_batch(ids, table, sleep=0, primary_key='id'):
|
|
45
|
+
"""
|
|
46
|
+
Delete a batch of rows
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
global confirmed_write
|
|
50
|
+
|
|
51
|
+
# Leave if ids is empty
|
|
52
|
+
if not ids or len(ids) == 0:
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
# Prepare delete
|
|
56
|
+
print('* Deleting %i rows...' % len(ids))
|
|
57
|
+
sql = "DELETE FROM " + table + \
|
|
58
|
+
" WHERE {0} IN (".format(primary_key) + \
|
|
59
|
+
', '.join([str(x) for x in ids]) + ")"
|
|
60
|
+
print(" query: " + sql)
|
|
61
|
+
|
|
62
|
+
if confirmed_write or query_yes_no("* Start deleting?"):
|
|
63
|
+
# Switch confirmed_write skip the question for the next delete
|
|
64
|
+
confirmed_write = True
|
|
65
|
+
|
|
66
|
+
# Execute query
|
|
67
|
+
run_query(sql, sleep)
|
|
68
|
+
else: # answered "no"
|
|
69
|
+
print("Error: Delete declined.")
|
|
70
|
+
sys.exit()
|
|
71
|
+
|
|
72
|
+
return True
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def run_query(sql, sleep=0):
|
|
76
|
+
"""Execute a write query"""
|
|
77
|
+
|
|
78
|
+
# Execute query
|
|
79
|
+
with connection.cursor() as cursorUpd:
|
|
80
|
+
cursorUpd.execute(sql)
|
|
81
|
+
connection.commit()
|
|
82
|
+
|
|
83
|
+
# Optional Sleep
|
|
84
|
+
if sleep > 0:
|
|
85
|
+
time.sleep(sleep)
|
|
86
|
+
|
|
87
|
+
return True
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def get_input():
|
|
91
|
+
"""
|
|
92
|
+
Get user input
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
return input().lower()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def query_yes_no(question, default="yes"):
|
|
99
|
+
"""Ask a yes/no question via input() and return their answer.
|
|
100
|
+
|
|
101
|
+
"question" is a string that is presented to the user.
|
|
102
|
+
"default" is the presumed answer if the user just hits <Enter>.
|
|
103
|
+
It must be "yes" (the default), "no" or None (meaning
|
|
104
|
+
an answer is required of the user).
|
|
105
|
+
|
|
106
|
+
The "answer" return value is True for "yes" or False for "no".
|
|
107
|
+
|
|
108
|
+
(thanks https://code.activestate.com/recipes/577058/)
|
|
109
|
+
"""
|
|
110
|
+
valid = {"yes": True, "y": True, "ye": True,
|
|
111
|
+
"no": False, "n": False}
|
|
112
|
+
if default is None:
|
|
113
|
+
prompt = " [y/n] "
|
|
114
|
+
elif default == "yes":
|
|
115
|
+
prompt = " [Y/n] "
|
|
116
|
+
elif default == "no":
|
|
117
|
+
prompt = " [y/N] "
|
|
118
|
+
else:
|
|
119
|
+
raise ValueError("invalid default answer: '%s'" % default)
|
|
120
|
+
|
|
121
|
+
while True:
|
|
122
|
+
sys.stdout.write(question + prompt)
|
|
123
|
+
choice = get_input()
|
|
124
|
+
|
|
125
|
+
if default is not None and choice == '':
|
|
126
|
+
return valid[default]
|
|
127
|
+
elif choice in valid:
|
|
128
|
+
return valid[choice]
|
|
129
|
+
else:
|
|
130
|
+
sys.stdout.write("Please respond with 'yes' or 'no' "
|
|
131
|
+
"(or 'y' or 'n').\n")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def connect(host, user, port, password, database):
|
|
135
|
+
"""
|
|
136
|
+
Connect to a PostgreSQL database
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
# Connect to the database
|
|
140
|
+
try:
|
|
141
|
+
return psycopg2.connect(host=host,
|
|
142
|
+
user=user,
|
|
143
|
+
port=port,
|
|
144
|
+
password=password,
|
|
145
|
+
dbname=database)
|
|
146
|
+
except Exception:
|
|
147
|
+
raise RuntimeError('Error: PostgreSQL connection failed.')
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def execute(host, user, port, password, database, action, table, where, set_=None, no_confirm=False, primary_key='id', read_batch_size=10000, write_batch_size=50, sleep=0):
|
|
151
|
+
"""
|
|
152
|
+
Execute batch update or delete
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
global confirmed_write, connection
|
|
156
|
+
|
|
157
|
+
# Make sure we have a SET clause for updates
|
|
158
|
+
if action == 'update' and set_ is None:
|
|
159
|
+
raise RuntimeError('Error: argument -s/--set is required for updates.')
|
|
160
|
+
|
|
161
|
+
# Connect to the database
|
|
162
|
+
connection = connect(host, user, port, password, database)
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
# confirmed_write default value
|
|
166
|
+
confirmed_write = False
|
|
167
|
+
if no_confirm:
|
|
168
|
+
confirmed_write = True
|
|
169
|
+
|
|
170
|
+
with connection.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cursor:
|
|
171
|
+
# Default vars
|
|
172
|
+
min_id = 0
|
|
173
|
+
|
|
174
|
+
while 1: # Infinite loop, will be broken by sys.exit()
|
|
175
|
+
# Get rows to modify
|
|
176
|
+
print("* Selecting data...")
|
|
177
|
+
sql = "SELECT {0} as id FROM ".format(primary_key) + table + " WHERE " + where + \
|
|
178
|
+
" AND {0} > %s ORDER BY {1} LIMIT %s".format(
|
|
179
|
+
primary_key, primary_key)
|
|
180
|
+
print(" query: " + sql % (min_id, read_batch_size))
|
|
181
|
+
cursor.execute(sql, (min_id, read_batch_size))
|
|
182
|
+
|
|
183
|
+
# Row count
|
|
184
|
+
count = cursor.rowcount
|
|
185
|
+
|
|
186
|
+
# No more rows
|
|
187
|
+
if count == 0:
|
|
188
|
+
print("* No more rows to modify!")
|
|
189
|
+
sys.exit()
|
|
190
|
+
|
|
191
|
+
# Loop thru rows
|
|
192
|
+
print("* Preparing to modify %s rows..." % count)
|
|
193
|
+
ids = []
|
|
194
|
+
for result in cursor:
|
|
195
|
+
# Append ID to batch
|
|
196
|
+
ids.append(result.get('id'))
|
|
197
|
+
# print(result)
|
|
198
|
+
|
|
199
|
+
# Minimum ID for future select
|
|
200
|
+
min_id = result.get('id')
|
|
201
|
+
|
|
202
|
+
# Process write when batch size if reached
|
|
203
|
+
if len(ids) >= write_batch_size:
|
|
204
|
+
if action == 'delete':
|
|
205
|
+
# Process delete
|
|
206
|
+
delete_batch(ids, table, sleep, primary_key)
|
|
207
|
+
else:
|
|
208
|
+
# Process update
|
|
209
|
+
update_batch(ids, table, set_, sleep, primary_key)
|
|
210
|
+
|
|
211
|
+
# Reset ids
|
|
212
|
+
ids = []
|
|
213
|
+
|
|
214
|
+
# Process final batch
|
|
215
|
+
if ids:
|
|
216
|
+
if action == 'delete':
|
|
217
|
+
# Process delete
|
|
218
|
+
delete_batch(ids, table, sleep, primary_key)
|
|
219
|
+
else:
|
|
220
|
+
# Process update
|
|
221
|
+
update_batch(ids, table, set_, sleep, primary_key)
|
|
222
|
+
except SystemExit:
|
|
223
|
+
print("* Program exited")
|
|
224
|
+
# except:
|
|
225
|
+
# print("Unexpected error:", sys.exc_info()[0])
|
|
226
|
+
finally:
|
|
227
|
+
connection.close()
|
|
228
|
+
|
|
229
|
+
return True
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def main():
|
|
233
|
+
# Parse arguments
|
|
234
|
+
parser = argparse.ArgumentParser()
|
|
235
|
+
parser.add_argument("-H", "--host", default="127.0.0.1",
|
|
236
|
+
help="PostgreSQL server host")
|
|
237
|
+
parser.add_argument("-P", "--port", type=int, default=5432,
|
|
238
|
+
help="PostgreSQL server port")
|
|
239
|
+
parser.add_argument("-U", "--user", required=True,
|
|
240
|
+
help="PostgreSQL user")
|
|
241
|
+
parser.add_argument("-p", "--password", default='',
|
|
242
|
+
help="PostgreSQL password")
|
|
243
|
+
parser.add_argument("-d", "--database", required=True,
|
|
244
|
+
help="PostgreSQL database name")
|
|
245
|
+
parser.add_argument("-t", "--table", required=True,
|
|
246
|
+
help="PostgreSQL table")
|
|
247
|
+
parser.add_argument("-id", "--primary_key", default='id',
|
|
248
|
+
help="Name of the primary key column")
|
|
249
|
+
parser.add_argument("-w", "--where", required=True,
|
|
250
|
+
help="Select WHERE clause")
|
|
251
|
+
parser.add_argument("-s", "--set",
|
|
252
|
+
help="Update SET clause")
|
|
253
|
+
parser.add_argument("-rbz", "--read_batch_size", type=int, default=10000,
|
|
254
|
+
help="Select batch size")
|
|
255
|
+
parser.add_argument("-wbz", "--write_batch_size", type=int, default=50,
|
|
256
|
+
help="Update/delete batch size")
|
|
257
|
+
parser.add_argument("-S", "--sleep", type=float, default=0.00,
|
|
258
|
+
help="Sleep after each batch")
|
|
259
|
+
parser.add_argument("-a", "--action", default='update', choices=['update', 'delete'],
|
|
260
|
+
help="Action ('update' or 'delete')")
|
|
261
|
+
parser.add_argument("-n", "--no_confirm", action='store_true',
|
|
262
|
+
help="Don't ask for confirmation before to run the write queries")
|
|
263
|
+
args = parser.parse_args()
|
|
264
|
+
|
|
265
|
+
execute(host=args.host,
|
|
266
|
+
user=args.user,
|
|
267
|
+
port=args.port,
|
|
268
|
+
password=args.password,
|
|
269
|
+
database=args.database,
|
|
270
|
+
action=args.action,
|
|
271
|
+
table=args.table,
|
|
272
|
+
where=args.where,
|
|
273
|
+
set_=args.set,
|
|
274
|
+
no_confirm=args.no_confirm,
|
|
275
|
+
primary_key=args.primary_key,
|
|
276
|
+
read_batch_size=args.read_batch_size,
|
|
277
|
+
write_batch_size=args.write_batch_size,
|
|
278
|
+
sleep=args.sleep
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
if __name__ == '__main__':
|
|
283
|
+
main()
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pg_batch
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: Run large PostgreSQL UPDATE and DELETE queries with small batches to prevent locks
|
|
5
|
+
Author-email: Gabriel Bordeaux <pypi@gab.lc>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/gabfl/pg-batch
|
|
8
|
+
Project-URL: Issues, https://github.com/gabfl/pg-batch/issues
|
|
9
|
+
Classifier: Topic :: Software Development
|
|
10
|
+
Classifier: Topic :: Database
|
|
11
|
+
Classifier: Topic :: Database :: Database Engines/Servers
|
|
12
|
+
Classifier: Operating System :: MacOS
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Natural Language :: English
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: psycopg2-binary<3,>=2.9
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# pg-batch
|
|
31
|
+
|
|
32
|
+
[](https://pypi.org/project/pg-batch)
|
|
33
|
+
[](https://github.com/gabfl/pg-batch/actions)
|
|
34
|
+
[](https://codecov.io/gh/gabfl/pg-batch)
|
|
35
|
+
[](https://raw.githubusercontent.com/gabfl/pg-batch/main/LICENSE)
|
|
36
|
+
|
|
37
|
+
PostgreSQL equivalent of https://github.com/gabfl/mysql-batch.
|
|
38
|
+
|
|
39
|
+
Updating or deleting a large amount of rows in PostgreSQL will create locks that will paralyze other queries running in parallel.
|
|
40
|
+
|
|
41
|
+
This tool will run UPDATE and DELETE queries in small batches to limit locking. If a large number of rows has to be updated or deleted, it is also possible to limit the number of rows selected at once.
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
pip3 install pg_batch
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## UPDATE example
|
|
50
|
+
|
|
51
|
+
You can run this example with the schema available in [sample_table/schema.sql](sample_table/schema.sql)
|
|
52
|
+
|
|
53
|
+
The following example will be identical to the following update:
|
|
54
|
+
|
|
55
|
+
```sql
|
|
56
|
+
UPDATE batch_test SET date = NOW() WHERE number > 30 AND date is NULL;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
This is the equivalent to process this update with batches of 20 rows:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pg_batch --host localhost \
|
|
63
|
+
--user postgres \
|
|
64
|
+
--password secret_password \
|
|
65
|
+
--database "test" \
|
|
66
|
+
--table "batch_test" \
|
|
67
|
+
--write_batch_size 20 \
|
|
68
|
+
--where "number > 30 AND date IS NULL" \
|
|
69
|
+
--set "date = NOW()"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Output sample:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
* Selecting data...
|
|
76
|
+
query: SELECT id as id FROM batch_test WHERE number > 30 AND date IS NULL AND id > 0 ORDER BY id LIMIT 10000
|
|
77
|
+
* Preparing to modify 70 rows...
|
|
78
|
+
* Updating 20 rows...
|
|
79
|
+
query: UPDATE batch_test SET date = NOW() WHERE id IN (31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50)
|
|
80
|
+
* Start updating? [Y/n]
|
|
81
|
+
* Updating 20 rows...
|
|
82
|
+
query: UPDATE batch_test SET date = NOW() WHERE id IN (51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70)
|
|
83
|
+
* Updating 20 rows...
|
|
84
|
+
query: UPDATE batch_test SET date = NOW() WHERE id IN (71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90)
|
|
85
|
+
* Updating 10 rows...
|
|
86
|
+
query: UPDATE batch_test SET date = NOW() WHERE id IN (91, 92, 93, 94, 95, 96, 97, 98, 99, 100)
|
|
87
|
+
* Selecting data...
|
|
88
|
+
query: SELECT id as id FROM batch_test WHERE number > 30 AND date IS NULL AND id > 100 ORDER BY id LIMIT 10000
|
|
89
|
+
* No more rows to modify!
|
|
90
|
+
* Program exited
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## DELETE example
|
|
94
|
+
|
|
95
|
+
The following example will be identical to the following delete:
|
|
96
|
+
|
|
97
|
+
```sql
|
|
98
|
+
DELETE FROM batch_test WHERE number > 30 AND date is NULL;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
This is the equivalent to process this delete with batches of 20 rows:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pg_batch --host localhost \
|
|
105
|
+
--user postgres \
|
|
106
|
+
--password secret_password \
|
|
107
|
+
--database "test" \
|
|
108
|
+
--table "batch_test" \
|
|
109
|
+
--write_batch_size 20 \
|
|
110
|
+
--where "number > 30 AND date IS NULL" \
|
|
111
|
+
--action "delete"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Output sample:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
* Selecting data...
|
|
118
|
+
query: SELECT id as id FROM batch_test WHERE number > 30 AND date IS NULL AND id > 0 ORDER BY id LIMIT 10000
|
|
119
|
+
* Preparing to modify 70 rows...
|
|
120
|
+
* Deleting 20 rows...
|
|
121
|
+
query: DELETE FROM batch_test WHERE id IN (31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50)
|
|
122
|
+
* Start deleting? [Y/n]
|
|
123
|
+
* Deleting 20 rows...
|
|
124
|
+
query: DELETE FROM batch_test WHERE id IN (51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70)
|
|
125
|
+
* Deleting 20 rows...
|
|
126
|
+
query: DELETE FROM batch_test WHERE id IN (71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90)
|
|
127
|
+
* Deleting 10 rows...
|
|
128
|
+
query: DELETE FROM batch_test WHERE id IN (91, 92, 93, 94, 95, 96, 97, 98, 99, 100)
|
|
129
|
+
* Selecting data...
|
|
130
|
+
query: SELECT id as id FROM batch_test WHERE number > 30 AND date IS NULL AND id > 100 ORDER BY id LIMIT 10000
|
|
131
|
+
* No more rows to modify!
|
|
132
|
+
* Program exited
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Usage
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
usage: pg_batch [-h] [-H HOST] [-P PORT] -U USER [-p PASSWORD] -d DATABASE -t
|
|
139
|
+
TABLE [-id PRIMARY_KEY] -w WHERE [-s SET]
|
|
140
|
+
[-rbz READ_BATCH_SIZE] [-wbz WRITE_BATCH_SIZE] [-S SLEEP]
|
|
141
|
+
[-a {update,delete}] [-n]
|
|
142
|
+
|
|
143
|
+
options:
|
|
144
|
+
-h, --help show this help message and exit
|
|
145
|
+
-H HOST, --host HOST PostgreSQL server host
|
|
146
|
+
-P PORT, --port PORT PostgreSQL server port
|
|
147
|
+
-U USER, --user USER PostgreSQL user
|
|
148
|
+
-p PASSWORD, --password PASSWORD
|
|
149
|
+
PostgreSQL password
|
|
150
|
+
-d DATABASE, --database DATABASE
|
|
151
|
+
PostgreSQL database name
|
|
152
|
+
-t TABLE, --table TABLE
|
|
153
|
+
PostgreSQL table
|
|
154
|
+
-id PRIMARY_KEY, --primary_key PRIMARY_KEY
|
|
155
|
+
Name of the primary key column
|
|
156
|
+
-w WHERE, --where WHERE
|
|
157
|
+
Select WHERE clause
|
|
158
|
+
-s SET, --set SET Update SET clause
|
|
159
|
+
-rbz READ_BATCH_SIZE, --read_batch_size READ_BATCH_SIZE
|
|
160
|
+
Select batch size
|
|
161
|
+
-wbz WRITE_BATCH_SIZE, --write_batch_size WRITE_BATCH_SIZE
|
|
162
|
+
Update/delete batch size
|
|
163
|
+
-S SLEEP, --sleep SLEEP
|
|
164
|
+
Sleep after each batch
|
|
165
|
+
-a {update,delete}, --action {update,delete}
|
|
166
|
+
Action ('update' or 'delete')
|
|
167
|
+
-n, --no_confirm Don't ask for confirmation before to run the write
|
|
168
|
+
queries
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## License
|
|
172
|
+
|
|
173
|
+
This program is under MIT license ([view license](LICENSE)).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
pg_batch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
pg_batch/__main__.py,sha256=0XMLusKiaJR-vIpHD3JChZGFhyJL7KNyRO1FTB623XY,71
|
|
3
|
+
pg_batch/pg_batch.py,sha256=MQU2Nz5qvhJUXyhpwbFro5-rUkOnTS7mRWmZhwqIf-c,9034
|
|
4
|
+
pg_batch-1.2.0.dist-info/licenses/LICENSE,sha256=WqS7GgVJk_T1GouVCLKKsR1q83EOah9Hpb72mq0pQ64,1073
|
|
5
|
+
pg_batch-1.2.0.dist-info/METADATA,sha256=R6j7tFu4olPfvEXnDfwPh5KWonY5977Og4k81nMh1Aw,6690
|
|
6
|
+
pg_batch-1.2.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
7
|
+
pg_batch-1.2.0.dist-info/entry_points.txt,sha256=cV5U089FFWzVfM7SgVPHqwWjA8gMp7au1SCq_BtNf4M,52
|
|
8
|
+
pg_batch-1.2.0.dist-info/top_level.txt,sha256=MezhyRgDIbdatUfJA5a2GbYU0avk33zBuGqAa2ZKM-w,9
|
|
9
|
+
pg_batch-1.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 Gabriel Bordeaux
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pg_batch
|