execsql2 2.28.0__py3-none-any.whl → 2.29.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.
Files changed (26) hide show
  1. execsql/db/base.py +6 -9
  2. execsql/db/mysql.py +19 -3
  3. execsql/db/postgres.py +1 -1
  4. execsql/exporters/xls.py +3 -2
  5. execsql/script/variables.py +42 -10
  6. execsql/types.py +8 -0
  7. {execsql2-2.28.0.dist-info → execsql2-2.29.0.dist-info}/METADATA +2 -2
  8. {execsql2-2.28.0.dist-info → execsql2-2.29.0.dist-info}/RECORD +26 -26
  9. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/README.md +0 -0
  10. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/config_settings.sqlite +0 -0
  11. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
  12. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/make_config_db.sql +0 -0
  13. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/md_compare.sql +0 -0
  14. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/md_glossary.sql +0 -0
  15. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/md_upsert.sql +0 -0
  16. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/pg_compare.sql +0 -0
  17. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/pg_glossary.sql +0 -0
  18. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/pg_upsert.sql +0 -0
  19. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/script_template.sql +0 -0
  20. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/ss_compare.sql +0 -0
  21. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/ss_glossary.sql +0 -0
  22. {execsql2-2.28.0.data → execsql2-2.29.0.data}/data/execsql2_extras/ss_upsert.sql +0 -0
  23. {execsql2-2.28.0.dist-info → execsql2-2.29.0.dist-info}/WHEEL +0 -0
  24. {execsql2-2.28.0.dist-info → execsql2-2.29.0.dist-info}/entry_points.txt +0 -0
  25. {execsql2-2.28.0.dist-info → execsql2-2.29.0.dist-info}/licenses/LICENSE.txt +0 -0
  26. {execsql2-2.28.0.dist-info → execsql2-2.29.0.dist-info}/licenses/NOTICE +0 -0
execsql/db/base.py CHANGED
@@ -215,21 +215,18 @@ class Database(ABC):
215
215
  def quote_literal(self, value: Any) -> str:
216
216
  """Return *value* as a SQL string literal, safely escaped.
217
217
 
218
- Default ANSI/Postgres behaviour: wrap in single quotes, double
219
- embedded apostrophes, escape backslashes (so a value containing
220
- ``\\'`` cannot terminate the literal on MySQL default mode or
221
- PostgreSQL E-strings), and reject embedded NUL bytes (most
222
- wire protocols truncate or reject them).
223
-
224
- Override per-DBMS only when the wire protocol requires a different
225
- literal form.
218
+ Standard SQL: wrap in single quotes and double embedded apostrophes;
219
+ a backslash is an ordinary character. Embedded NUL bytes are
220
+ rejected (most wire protocols truncate or reject them). A DBMS
221
+ that reads a backslash in a literal as an escape (MySQL) overrides
222
+ this.
226
223
  """
227
224
  if value is None:
228
225
  return "NULL"
229
226
  s = str(value)
230
227
  if "\x00" in s:
231
228
  raise ValueError("SQL literal contains a NUL byte; refusing to quote.")
232
- return "'" + s.replace("\\", "\\\\").replace("'", "''") + "'"
229
+ return "'" + s.replace("'", "''") + "'"
233
230
 
234
231
  def paramsubs(self, paramcount: int) -> str:
235
232
  """Return a comma-separated string of *paramcount* parameter placeholders."""
execsql/db/mysql.py CHANGED
@@ -67,6 +67,20 @@ class MySQLDatabase(Database):
67
67
  re.I,
68
68
  )
69
69
 
70
+ def quote_literal(self, value: Any) -> str:
71
+ """Return *value* as a string literal for MySQL/MariaDB.
72
+
73
+ Unless ``NO_BACKSLASH_ESCAPES`` is set, MySQL reads a backslash in a
74
+ literal as an escape, so ``\\'`` would end it: backslashes are doubled
75
+ as well as apostrophes.
76
+ """
77
+ if value is None:
78
+ return "NULL"
79
+ s = str(value)
80
+ if "\x00" in s:
81
+ raise ValueError("SQL literal contains a NUL byte; refusing to quote.")
82
+ return "'" + s.replace("\\", "\\\\").replace("'", "''") + "'"
83
+
70
84
  def __init__(
71
85
  self,
72
86
  server_name: str,
@@ -307,10 +321,12 @@ class MySQLDatabase(Database):
307
321
  table_cols = self.table_columns(table_name, schema_name)
308
322
  data_table_cols = [d.lower() for d in table_cols]
309
323
  csv_file_cols = csv_file_obj.column_headers()
324
+ # MySQL column names are case-insensitive: compare without case, and
325
+ # send the file's own spelling.
310
326
  if _state.conf.import_common_cols_only:
311
- import_cols = [col for col in csv_file_cols if col in data_table_cols]
327
+ import_cols = [col for col in csv_file_cols if col.lower() in data_table_cols]
312
328
  else:
313
- unmatched_cols = list(set(csv_file_cols) - set(data_table_cols))
329
+ unmatched_cols = [col for col in csv_file_cols if col.lower() not in data_table_cols]
314
330
  if len(unmatched_cols) > 0:
315
331
  raise ErrInfo(
316
332
  type="error",
@@ -326,7 +342,7 @@ class MySQLDatabase(Database):
326
342
  # reads the format that was detected.
327
343
  if (
328
344
  csv_file_obj.escapechar is None
329
- and data_table_cols == csv_file_cols
345
+ and data_table_cols == [col.lower() for col in csv_file_cols]
330
346
  and _state.conf.empty_strings
331
347
  and _state.conf.empty_rows
332
348
  and not _state.conf.del_empty_cols
execsql/db/postgres.py CHANGED
@@ -353,7 +353,7 @@ class PostgresDatabase(Database):
353
353
  from execsql.exporters.delimited import blank_lines_as_empty_rows
354
354
 
355
355
  # Use Postgres' COPY FROM method via psycopg3's cursor.copy() context manager.
356
- rf = csv_file_obj.open("rt")
356
+ rf = csv_file_obj.openclean("rt") # past the SKIP lines, as every other reader starts
357
357
  if skipheader:
358
358
  next(rf)
359
359
  # Copy_from() requires a delimiter, but if there is none, feed it an
execsql/exporters/xls.py CHANGED
@@ -158,7 +158,7 @@ class XlsFile:
158
158
  break
159
159
  ncols += 1
160
160
  sheet_data = []
161
- for r in range(junk_header_rows, sheet.nrows - junk_header_rows):
161
+ for r in range(junk_header_rows, sheet.nrows):
162
162
  datarow = row_data(r, ncols)
163
163
  if datarow.count(None) == len(datarow):
164
164
  break
@@ -270,7 +270,8 @@ class XlsxFile:
270
270
  sheet_data = []
271
271
  rowsrc = sheet.iter_rows(min_row=junk_header_rows + 1, values_only=True)
272
272
  for r in rowsrc:
273
- if not any(r):
273
+ # A row of zeros or FALSE values is data; only a row of empty cells ends it.
274
+ if all(c is None or c == "" for c in r):
274
275
  break
275
276
  sheet_data.append(list(r))
276
277
  for r in range(len(sheet_data)):
@@ -17,6 +17,42 @@ from execsql.exceptions import ErrInfo
17
17
  __all__ = ["CounterVars", "SubVarSet", "LocalSubVarSet", "ScriptArgSubVarSet"]
18
18
 
19
19
 
20
+ def _after_escape_string_prefix(command: str, start: int) -> bool:
21
+ """Whether the ``!'!`` token at *start* follows an ``E`` that makes it a PostgreSQL escape string (``E!'!v!'!``).
22
+
23
+ The ``E`` must stand alone: in ``TYPE!'!v!'!`` it ends a word.
24
+ """
25
+ if start < 1 or command[start - 1] not in "Ee":
26
+ return False
27
+ return start < 2 or not (command[start - 2].isalnum() or command[start - 2] == "_")
28
+
29
+
30
+ def _sql_string_literal(value: str, *, escape_string: bool = False) -> str:
31
+ """*value* as the string literal ``!'!var!'!`` substitutes, in the current connection's form.
32
+
33
+ An apostrophe is doubled everywhere; a backslash only where the DBMS
34
+ reads it as an escape (MySQL/MariaDB), or inside an escape string the
35
+ script wrote as ``E!'!var!'!`` (*escape_string*), so ``C:\\data`` is
36
+ stored as written in every case. Without a connection, the standard SQL
37
+ form. (Upstream doubled backslashes only on Windows, to protect
38
+ ``re.sub``'s replacement template, not the SQL.)
39
+ """
40
+ if escape_string:
41
+ return "'" + value.replace("\\", "\\\\").replace("'", "''") + "'"
42
+ db = None
43
+ try:
44
+ import execsql.state as _state
45
+
46
+ dbs = _state.dbs
47
+ if dbs is not None and dbs.current_db is not None:
48
+ db = dbs.current()
49
+ except Exception:
50
+ db = None
51
+ if db is not None:
52
+ return db.quote_literal(value)
53
+ return "'" + value.replace("'", "''") + "'"
54
+
55
+
20
56
  # ---------------------------------------------------------------------------
21
57
  # CounterVars
22
58
  # ---------------------------------------------------------------------------
@@ -253,13 +289,10 @@ class SubVarSet:
253
289
  )
254
290
  quote = m.group("q")
255
291
  if quote == "'":
256
- # B07a/F002: wrap in single quotes, doubling embedded
257
- # apostrophes AND escaping backslashes so MySQL default
258
- # mode and PostgreSQL E-string literals can't end the
259
- # quoted region via ``\'``. The previous Windows-only
260
- # branch (``os.name != 'posix'``) applied the escape on
261
- # the wrong axis — host OS vs target DBMS.
262
- sub = "'" + sub.replace("\\", "\\\\").replace("'", "''") + "'"
292
+ sub = _sql_string_literal(
293
+ sub,
294
+ escape_string=_after_escape_string_prefix(command_str, m.start()),
295
+ )
263
296
  elif quote == '"':
264
297
  # B07a/F001: wrap in double quotes, doubling embedded
265
298
  # ``"`` so a value containing ``"; DROP TABLE x; --``
@@ -306,13 +339,12 @@ class SubVarSet:
306
339
  if idx != -1:
307
340
  _check_nul(varname, sub)
308
341
  return command_str[:idx] + sub + command_str[idx + len(token) :], True
309
- # Single-quote-wrapped token: !'!varname!'! — escape ``\`` and
310
- # double embedded ``'`` (see substitute_one for rationale).
342
+ # Single-quote-wrapped token: !'!varname!'! — a string literal.
311
343
  tokenq = f"!'!{varname}!'!"
312
344
  idxq = cmd_lower.find(tokenq)
313
345
  if idxq != -1:
314
346
  _check_nul(varname, sub)
315
- wrapped = "'" + sub.replace("\\", "\\\\").replace("'", "''") + "'"
347
+ wrapped = _sql_string_literal(sub, escape_string=_after_escape_string_prefix(command_str, idxq))
316
348
  return (
317
349
  command_str[:idxq] + wrapped + command_str[idxq + len(tokenq) :],
318
350
  True,
execsql/types.py CHANGED
@@ -884,6 +884,14 @@ dbt_oracle.name_datatype(DT_TimestampTZ, "TIMESTAMP WITH TIME ZONE")
884
884
  dbt_oracle.name_datatype(DT_Timestamp, "TIMESTAMP", casting_name="TIMESTAMP")
885
885
  dbt_oracle.name_datatype(DT_Date, "DATE", casting_name="DATE")
886
886
  dbt_oracle.name_datatype(DT_Time_Oracle, "VARCHAR2", True, casting_name="VARCHAR(20)")
887
+ # Oracle has no time-of-day type, and oracledb cannot bind a datetime.time: a
888
+ # time column is stored as its ISO text (at most 15 characters, HH:MM:SS.ffffff).
889
+ dbt_oracle.name_datatype(
890
+ DT_Time,
891
+ "VARCHAR2(15)",
892
+ casting_name="VARCHAR(20)",
893
+ conv_mod_fn=lambda x: x.isoformat() if x is not None else None,
894
+ )
887
895
  dbt_oracle.name_datatype(DT_Integer, "NUMBER")
888
896
  dbt_oracle.name_datatype(DT_Long, "NUMBER")
889
897
  dbt_oracle.name_datatype(DT_Float, "FLOAT")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: execsql2
3
- Version: 2.28.0
3
+ Version: 2.29.0
4
4
  Summary: Runs a SQL script against a PostgreSQL, SQLite, MariaDB/MySQL, DuckDB, Firebird, MS-Access, MS-SQL-Server, or Oracle database, or an ODBC DSN. Provides metacommands to import and export data, copy data between databases, conditionally execute SQL and metacommands, and dynamically alter SQL and metacommands with substitution variables.
5
5
  Project-URL: Homepage, https://execsql2.readthedocs.io
6
6
  Project-URL: Repository, https://github.com/geocoug/execsql
@@ -466,7 +466,7 @@ execsql format --no-sql --in-place scripts/
466
466
  ```yaml
467
467
  repos:
468
468
  - repo: https://github.com/geocoug/execsql
469
- rev: v2.28.0
469
+ rev: v2.29.0
470
470
  hooks:
471
471
  - id: execsql-format
472
472
  - id: execsql-lint
@@ -13,7 +13,7 @@ execsql/plugins.py,sha256=RykMlIjTyWcnQc9ygjLErS3wdcsZSsG9QTIvg4DwfAI,13626
13
13
  execsql/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  execsql/state.py,sha256=NDAtv38b2cmknz-jEgOaOeqZCc6GdxN6mz-KCqb9pqg,23263
15
15
  execsql/state.pyi,sha256=pEuTT4G6VNiwy4Ii7OUXc1RvzcQvjFkeFazSGEOprs0,4300
16
- execsql/types.py,sha256=qUJ5kVKz_Crc9hti5u9_VnVzLBQ2n5Jtbje5hSwxGzE,32809
16
+ execsql/types.py,sha256=zey_bc2AzbUduLoK-nps16qX2zazDYf_iapWkG_cbmA,33130
17
17
  execsql/cli/__init__.py,sha256=8wDwIAFq7AI9iSGuw-Xfky-izN_7oHjUegr_brEBot0,3197
18
18
  execsql/cli/application.py,sha256=qKjkhDMWB7fEjEbqOLZ3pNFw80piBnRSeW_DfZg-9MA,12448
19
19
  execsql/cli/dispatch.py,sha256=deyN2QQYvdzMSqGGa3CSMpaqdLNeMgc5Uke0mUbl764,2704
@@ -35,14 +35,14 @@ execsql/data/execsql.conf.template,sha256=pqh7G21ifYO0BjZoTgUhGyQAx4eKOmbIr6nToc
35
35
  execsql/data/script_header.sql,sha256=a7WKScekNgJoxVEmMRTkWv8NsAzW1jJ4vJfGy9HVy0g,349
36
36
  execsql/db/__init__.py,sha256=jTbuafuKOqYtXFR1wvCOoKK5Lr3l1uErfaIbIr6UywI,1063
37
37
  execsql/db/access.py,sha256=xfBzcgP1qJovxSYwrpu0bdxqyJWqMoMP8i4FsaCTYXA,21306
38
- execsql/db/base.py,sha256=rMkOxfqhlrG1_LnlkIQYwZXnm-wRd2xN4YQ9oY7OOZM,42990
38
+ execsql/db/base.py,sha256=5f-1YxaaopRPnCPVs4OVOkYmWFtG1V71sk2XFoBUE_Y,42849
39
39
  execsql/db/dsn.py,sha256=CaISffisqO5IjSE-elEpwK9vXLaArp3ItpV8lvRTu-I,6920
40
40
  execsql/db/duckdb.py,sha256=2iVlbjQdOSAwhI2LxWEm7FYZxjjVcKiE8rT_3VJdRIo,7761
41
41
  execsql/db/factory.py,sha256=cMptU3BL1Nsilo7LKLAI5RR-LiC9RTH-3UC9rHT2JLQ,5519
42
42
  execsql/db/firebird.py,sha256=CoNnzFtOFAkp8OJByXXXclitCPAAjM23eFJGfy3C7IE,10171
43
- execsql/db/mysql.py,sha256=ovadEv8InaK2VZjfMRwZNQ7dTQaE2qaWNUra-FjP0xA,21492
43
+ execsql/db/mysql.py,sha256=PexKdOzqR7cpkD_nIjPDwSEK_Or8AkWvBh_TEqsIMhU,22231
44
44
  execsql/db/oracle.py,sha256=i5qPahsy_z1AuZT7l54Hzixknkvbzd-SCQgiVcTN94w,13796
45
- execsql/db/postgres.py,sha256=PZ2vXKh9Nbs6aAc899vaPz1w9ZntKNCqQ2pCl_giiVQ,23587
45
+ execsql/db/postgres.py,sha256=0SbdJk9vZ8JXMTHrBfZU3RLssCoX5IL--Awi5zYCOKw,23645
46
46
  execsql/db/sqlite.py,sha256=fEpNPkfJGnqm1Wx_rZK5SEqaWsBqLy85Jxk_5NsnqgM,12109
47
47
  execsql/db/sqlserver.py,sha256=cdbyHoSUKEwUee2GQTKD5SlLyBraYiOvJ2ro5MJuMFA,9525
48
48
  execsql/db/tiers.py,sha256=PH2sUYwlYqcANGVKXprWQKVIlM6fpWU9q74djn8oFwc,2924
@@ -65,7 +65,7 @@ execsql/exporters/raw.py,sha256=9o3BMt7UYmnjbP8OEzmM2kNKfwwERi2yDcuNfUoEfuQ,2530
65
65
  execsql/exporters/sqlite.py,sha256=QjP_W90S-hecNqp2A-Vy58DD8MZitME1sTq4lqIS43w,3401
66
66
  execsql/exporters/templates.py,sha256=N9PRFet0mYuDQFu7PNbq5c6qGu2You2qfHpqnxg17NA,7065
67
67
  execsql/exporters/values.py,sha256=UPxN5IprasBZLqM5jfUXQihjdTeBFTxbJslOEtmGOcY,3384
68
- execsql/exporters/xls.py,sha256=n4J4J4sJq-5iU3Fa1JTAxTq8VAXEhv2znNRGoi1arSw,11265
68
+ execsql/exporters/xls.py,sha256=bdGDTnePkXY3MtPJi4D47sTFSqfZteg9lftbi-7nB24,11361
69
69
  execsql/exporters/xlsx.py,sha256=7sm-3KniYlB2K-n6xQmIoHbAvl2ryJhFWU95SEkR7e4,12702
70
70
  execsql/exporters/xml.py,sha256=t1PSr3i8xvTCWzd9jaxxAy5NcRpl6sqjnZALafKCqpM,2575
71
71
  execsql/exporters/yaml.py,sha256=ex2h91E12wItvh84AarjrDTcZ4SDx9uq0c9wtr-NuQM,3084
@@ -117,7 +117,7 @@ execsql/script/control.py,sha256=WqLy-HLPqHG3vEzYpKMiIJsD7LpORjyQuUWzFzcGz4w,232
117
117
  execsql/script/engine.py,sha256=wjXKwPIis-T2Y8rLnRXQ_ymUFdXff1MlI2IIYmxihKo,18448
118
118
  execsql/script/executor.py,sha256=lvMFjKe2h4fafhKNiuoXAYpDe8pLHHuYMiwPkLYJe9I,41527
119
119
  execsql/script/parser.py,sha256=z73v6t6ZbPUKkRu-UOIL6q1cCRDeoRvG2aXXC8NpMvE,37162
120
- execsql/script/variables.py,sha256=_hklqCeqPbdOT646Yg3ZcpmPke38_8bukMG3eZMTKZw,16384
120
+ execsql/script/variables.py,sha256=Tb01aHqOdWZbkgj-oW0ky3KWNy5N34XLD-Fm2eShYZM,17462
121
121
  execsql/utils/__init__.py,sha256=0uR6JwVJQRX3vceByNBduCAf5dd5assKjeqJUWvpZoA,278
122
122
  execsql/utils/auth.py,sha256=BV7VtLM-ID8jNB42vx7GEz8yb3Z1Qs9xCr4cUMqL864,14539
123
123
  execsql/utils/color.py,sha256=goQqhnLg8yERpFolQikA9zYSVcuAm0unKTJiWTbQm-U,634
@@ -131,23 +131,23 @@ execsql/utils/numeric.py,sha256=_7bi5R6pHjMCkOPne_Sh5nUj-B8e9g6WFmjptFHaunA,1573
131
131
  execsql/utils/regex.py,sha256=B3mSBhRRx_DpUnX_t9IoYd05KvWAebiLMCZqQAmEwcw,3885
132
132
  execsql/utils/strings.py,sha256=UQNjpRCEFa1UO6feU-M-9e24wWAvizs_iu_4fFusLxo,8516
133
133
  execsql/utils/timer.py,sha256=eDYf5VzCNFk7oo90InJucUm3XcBdhYMogjZMqeg9xzc,1899
134
- execsql2-2.28.0.data/data/execsql2_extras/README.md,sha256=7SG9FbBpdqkgQTTt1aBTbCgymBZyV0rLrQMQrendzxs,5032
135
- execsql2-2.28.0.data/data/execsql2_extras/config_settings.sqlite,sha256=aY5cxR7Q7J6zJ4bC9lu5mHUrhy211Cq3MNKPQVCt02E,20480
136
- execsql2-2.28.0.data/data/execsql2_extras/example_config_prompt.sql,sha256=2e8KzzVWhho8KxYVHETSVmZdhW7wodioDsqBLSL6m4s,7487
137
- execsql2-2.28.0.data/data/execsql2_extras/make_config_db.sql,sha256=WwyC6dK-Eh5CAVppiBCDHqiI1_wEI9U95Ytpr4lsZkg,8726
138
- execsql2-2.28.0.data/data/execsql2_extras/md_compare.sql,sha256=qYYVAjSeHZzjszxV3Bv6bg8Ckbq2kMHl87_gh4sywMU,24140
139
- execsql2-2.28.0.data/data/execsql2_extras/md_glossary.sql,sha256=hkZ2Onn57LAKKsuXxzhR8tPtcWXkmWEQkwPE58-Tm2k,10796
140
- execsql2-2.28.0.data/data/execsql2_extras/md_upsert.sql,sha256=_CAK4BzEboRXTNy03SJR-oOjcEdSNMuRBPL6noWUptY,112560
141
- execsql2-2.28.0.data/data/execsql2_extras/pg_compare.sql,sha256=1zJd4hVUKHR0tncc2qTBC9B4qVV4Us2ITkJpsjN3tMw,24352
142
- execsql2-2.28.0.data/data/execsql2_extras/pg_glossary.sql,sha256=IKuwna-_8b20ljSkXZruuiQigrCpo7ueQdUqd1MXiuI,9908
143
- execsql2-2.28.0.data/data/execsql2_extras/pg_upsert.sql,sha256=HpPJtTHvpEjQy03j-3iPxDEOHMRkudOg7O4D4YR38UI,108315
144
- execsql2-2.28.0.data/data/execsql2_extras/script_template.sql,sha256=2J35ddZPguJ-vwTsz83wErv0jiWUyJcdW_JM0mNKDXA,11155
145
- execsql2-2.28.0.data/data/execsql2_extras/ss_compare.sql,sha256=j1qVNUPXQsEU7-DoVgDJCGcE0EuIl7whLBT3fgeiMAo,24833
146
- execsql2-2.28.0.data/data/execsql2_extras/ss_glossary.sql,sha256=2gLxv34xzKt0vy7hSzJH7a9JiMC3ETrv9MofxQwAibU,13065
147
- execsql2-2.28.0.data/data/execsql2_extras/ss_upsert.sql,sha256=G_8rQ0VzuKIZHWs24O_WrfzpC5S27R1JsL-bFBR3SUQ,117730
148
- execsql2-2.28.0.dist-info/METADATA,sha256=8mBy6p3UOLvFCmFwhoNh77QQIR5qYSotGYH0fUF0XgQ,27854
149
- execsql2-2.28.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
150
- execsql2-2.28.0.dist-info/entry_points.txt,sha256=jOf53-4IVGjEZeNYUOF1GGaiPNfVZcNKxP3vDFKEyMA,58
151
- execsql2-2.28.0.dist-info/licenses/LICENSE.txt,sha256=LBdhuxejF8_bLCHZ2kWfmDXpDGUu914Gbd6_3JjCRe0,676
152
- execsql2-2.28.0.dist-info/licenses/NOTICE,sha256=McYzgxYav3U1OaVsY4Su1sfBrfmplpRdA9b6-gCDQCg,342
153
- execsql2-2.28.0.dist-info/RECORD,,
134
+ execsql2-2.29.0.data/data/execsql2_extras/README.md,sha256=7SG9FbBpdqkgQTTt1aBTbCgymBZyV0rLrQMQrendzxs,5032
135
+ execsql2-2.29.0.data/data/execsql2_extras/config_settings.sqlite,sha256=aY5cxR7Q7J6zJ4bC9lu5mHUrhy211Cq3MNKPQVCt02E,20480
136
+ execsql2-2.29.0.data/data/execsql2_extras/example_config_prompt.sql,sha256=2e8KzzVWhho8KxYVHETSVmZdhW7wodioDsqBLSL6m4s,7487
137
+ execsql2-2.29.0.data/data/execsql2_extras/make_config_db.sql,sha256=WwyC6dK-Eh5CAVppiBCDHqiI1_wEI9U95Ytpr4lsZkg,8726
138
+ execsql2-2.29.0.data/data/execsql2_extras/md_compare.sql,sha256=qYYVAjSeHZzjszxV3Bv6bg8Ckbq2kMHl87_gh4sywMU,24140
139
+ execsql2-2.29.0.data/data/execsql2_extras/md_glossary.sql,sha256=hkZ2Onn57LAKKsuXxzhR8tPtcWXkmWEQkwPE58-Tm2k,10796
140
+ execsql2-2.29.0.data/data/execsql2_extras/md_upsert.sql,sha256=_CAK4BzEboRXTNy03SJR-oOjcEdSNMuRBPL6noWUptY,112560
141
+ execsql2-2.29.0.data/data/execsql2_extras/pg_compare.sql,sha256=1zJd4hVUKHR0tncc2qTBC9B4qVV4Us2ITkJpsjN3tMw,24352
142
+ execsql2-2.29.0.data/data/execsql2_extras/pg_glossary.sql,sha256=IKuwna-_8b20ljSkXZruuiQigrCpo7ueQdUqd1MXiuI,9908
143
+ execsql2-2.29.0.data/data/execsql2_extras/pg_upsert.sql,sha256=HpPJtTHvpEjQy03j-3iPxDEOHMRkudOg7O4D4YR38UI,108315
144
+ execsql2-2.29.0.data/data/execsql2_extras/script_template.sql,sha256=2J35ddZPguJ-vwTsz83wErv0jiWUyJcdW_JM0mNKDXA,11155
145
+ execsql2-2.29.0.data/data/execsql2_extras/ss_compare.sql,sha256=j1qVNUPXQsEU7-DoVgDJCGcE0EuIl7whLBT3fgeiMAo,24833
146
+ execsql2-2.29.0.data/data/execsql2_extras/ss_glossary.sql,sha256=2gLxv34xzKt0vy7hSzJH7a9JiMC3ETrv9MofxQwAibU,13065
147
+ execsql2-2.29.0.data/data/execsql2_extras/ss_upsert.sql,sha256=G_8rQ0VzuKIZHWs24O_WrfzpC5S27R1JsL-bFBR3SUQ,117730
148
+ execsql2-2.29.0.dist-info/METADATA,sha256=eqv9-m8EsFEa1OBzwYfK66_d6vGY2Fv5BTmKyy1ashY,27854
149
+ execsql2-2.29.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
150
+ execsql2-2.29.0.dist-info/entry_points.txt,sha256=jOf53-4IVGjEZeNYUOF1GGaiPNfVZcNKxP3vDFKEyMA,58
151
+ execsql2-2.29.0.dist-info/licenses/LICENSE.txt,sha256=LBdhuxejF8_bLCHZ2kWfmDXpDGUu914Gbd6_3JjCRe0,676
152
+ execsql2-2.29.0.dist-info/licenses/NOTICE,sha256=McYzgxYav3U1OaVsY4Su1sfBrfmplpRdA9b6-gCDQCg,342
153
+ execsql2-2.29.0.dist-info/RECORD,,