execsql2 2.22.7__py3-none-any.whl → 2.22.9__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.
- execsql/data/execsql.conf.template +1 -0
- execsql/format.py +164 -33
- execsql/utils/mail.py +9 -5
- {execsql2-2.22.7.dist-info → execsql2-2.22.9.dist-info}/METADATA +2 -2
- {execsql2-2.22.7.dist-info → execsql2-2.22.9.dist-info}/RECORD +23 -23
- {execsql2-2.22.7.dist-info → execsql2-2.22.9.dist-info}/WHEEL +1 -1
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/README.md +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/config_settings.sqlite +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/example_config_prompt.sql +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/make_config_db.sql +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/md_compare.sql +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/md_glossary.sql +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/md_upsert.sql +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/pg_compare.sql +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/pg_glossary.sql +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/pg_upsert.sql +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/script_template.sql +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/ss_compare.sql +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/ss_glossary.sql +0 -0
- {execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/ss_upsert.sql +0 -0
- {execsql2-2.22.7.dist-info → execsql2-2.22.9.dist-info}/entry_points.txt +0 -0
- {execsql2-2.22.7.dist-info → execsql2-2.22.9.dist-info}/licenses/LICENSE.txt +0 -0
- {execsql2-2.22.7.dist-info → execsql2-2.22.9.dist-info}/licenses/NOTICE +0 -0
execsql/format.py
CHANGED
|
@@ -176,13 +176,18 @@ _EXECSQL_VAR_RE = re.compile(r"""!(['"]?)!([^!\s][^!]*)!\1!|!\{[^}]+\}!""")
|
|
|
176
176
|
_IDENT_CHAR_RE = re.compile(r"[A-Za-z0-9_$]")
|
|
177
177
|
|
|
178
178
|
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
_LITERAL_KINDS = frozenset({"estring", "plain", "dollar"})
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _iter_sql_spans(sql: str) -> Iterator[tuple[int, int, str]]:
|
|
183
|
+
"""Yield ``(start, end, kind)`` spans for every non-code region of *sql*.
|
|
181
184
|
|
|
182
185
|
This is a lexical walk rather than a regex sweep, because an apostrophe
|
|
183
|
-
only starts a literal in some contexts
|
|
184
|
-
(which
|
|
185
|
-
|
|
186
|
+
only starts a literal in some contexts: inside a line comment, a block
|
|
187
|
+
comment (which nests in PostgreSQL), or a quoted identifier it is just a
|
|
188
|
+
character. Those three regions are reported as spans of their own so
|
|
189
|
+
callers that care about code positions — :func:`_paren_depths` — can mask
|
|
190
|
+
them out, and :func:`_iter_sql_literals` filters them back off.
|
|
186
191
|
|
|
187
192
|
*kind* is one of:
|
|
188
193
|
|
|
@@ -195,6 +200,8 @@ def _iter_sql_literals(sql: str) -> Iterator[tuple[int, int, str]]:
|
|
|
195
200
|
``"dollar"``
|
|
196
201
|
A dollar-quoted body, ``$$...$$`` or ``$tag$...$tag$``, in which no
|
|
197
202
|
character is special.
|
|
203
|
+
``"line_comment"``, ``"block_comment"``, ``"quoted_ident"``
|
|
204
|
+
Regions that are not code and hold no literal.
|
|
198
205
|
"""
|
|
199
206
|
i, n = 0, len(sql)
|
|
200
207
|
while i < n:
|
|
@@ -202,10 +209,13 @@ def _iter_sql_literals(sql: str) -> Iterator[tuple[int, int, str]]:
|
|
|
202
209
|
|
|
203
210
|
if c == "-" and sql.startswith("--", i):
|
|
204
211
|
nl = sql.find("\n", i)
|
|
205
|
-
|
|
212
|
+
stop = n if nl < 0 else nl
|
|
213
|
+
yield i, stop, "line_comment"
|
|
214
|
+
i = stop
|
|
206
215
|
continue
|
|
207
216
|
|
|
208
217
|
if c == "/" and sql.startswith("/*", i):
|
|
218
|
+
start = i
|
|
209
219
|
depth, i = 1, i + 2
|
|
210
220
|
while i < n and depth:
|
|
211
221
|
if sql.startswith("/*", i):
|
|
@@ -214,9 +224,11 @@ def _iter_sql_literals(sql: str) -> Iterator[tuple[int, int, str]]:
|
|
|
214
224
|
depth, i = depth - 1, i + 2
|
|
215
225
|
else:
|
|
216
226
|
i += 1
|
|
227
|
+
yield start, i, "block_comment"
|
|
217
228
|
continue
|
|
218
229
|
|
|
219
230
|
if c == '"':
|
|
231
|
+
start = i
|
|
220
232
|
i += 1
|
|
221
233
|
while i < n:
|
|
222
234
|
if sql[i] == '"':
|
|
@@ -226,6 +238,7 @@ def _iter_sql_literals(sql: str) -> Iterator[tuple[int, int, str]]:
|
|
|
226
238
|
i += 1
|
|
227
239
|
break
|
|
228
240
|
i += 1
|
|
241
|
+
yield start, i, "quoted_ident"
|
|
229
242
|
continue
|
|
230
243
|
|
|
231
244
|
if c == "$":
|
|
@@ -273,6 +286,46 @@ def _iter_sql_literals(sql: str) -> Iterator[tuple[int, int, str]]:
|
|
|
273
286
|
i += 1
|
|
274
287
|
|
|
275
288
|
|
|
289
|
+
def _iter_sql_literals(sql: str) -> Iterator[tuple[int, int, str]]:
|
|
290
|
+
"""Yield ``(start, end, kind)`` spans for every string literal in *sql*.
|
|
291
|
+
|
|
292
|
+
The literal subset of :func:`_iter_sql_spans`; comments and quoted
|
|
293
|
+
identifiers are dropped, so quotes inside them never open a literal.
|
|
294
|
+
"""
|
|
295
|
+
for start, end, kind in _iter_sql_spans(sql):
|
|
296
|
+
if kind in _LITERAL_KINDS:
|
|
297
|
+
yield start, end, kind
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def _paren_depths(lines: list[str]) -> list[int]:
|
|
301
|
+
"""Return the parenthesis nesting depth at the start of each of *lines*.
|
|
302
|
+
|
|
303
|
+
Parentheses inside string literals, comments, and quoted identifiers do
|
|
304
|
+
not count. Depth resets at every ``;`` so one statement with unbalanced
|
|
305
|
+
parens — which only happens when the input is a fragment — cannot skew
|
|
306
|
+
the statements that follow.
|
|
307
|
+
"""
|
|
308
|
+
text = "\n".join(lines)
|
|
309
|
+
chars = list(text)
|
|
310
|
+
for start, end, _kind in _iter_sql_spans(text):
|
|
311
|
+
for i in range(start, min(end, len(chars))):
|
|
312
|
+
if chars[i] != "\n":
|
|
313
|
+
chars[i] = " "
|
|
314
|
+
|
|
315
|
+
depths: list[int] = []
|
|
316
|
+
depth = 0
|
|
317
|
+
for line in "".join(chars).split("\n"):
|
|
318
|
+
depths.append(depth)
|
|
319
|
+
for ch in line:
|
|
320
|
+
if ch == "(":
|
|
321
|
+
depth += 1
|
|
322
|
+
elif ch == ")":
|
|
323
|
+
depth = max(0, depth - 1)
|
|
324
|
+
elif ch == ";":
|
|
325
|
+
depth = 0
|
|
326
|
+
return depths
|
|
327
|
+
|
|
328
|
+
|
|
276
329
|
def _sql_literal_texts(sql: str) -> list[str]:
|
|
277
330
|
"""Return the source text of every string literal in *sql*, in order."""
|
|
278
331
|
return [sql[start:end] for start, end, _ in _iter_sql_literals(sql)]
|
|
@@ -588,6 +641,34 @@ _CMT_MARKER_RE = re.compile(rf"/\*\s*({re.escape(_CMT_MARKER)}\d+)\s*\*/")
|
|
|
588
641
|
# converge. Matching the run as a unit removes it cleanly. See issue #35.
|
|
589
642
|
_CMT_MARKER_RUN_RE = re.compile(rf"\s*(?:/\*\s*{re.escape(_CMT_MARKER)}\d+\s*\*/\s*)+")
|
|
590
643
|
|
|
644
|
+
# Characters that must not be preceded by a space once a marker run between
|
|
645
|
+
# them and the previous token is removed.
|
|
646
|
+
_NO_SPACE_BEFORE = frozenset(",;).")
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
def _strip_marker_runs(line: str) -> str:
|
|
650
|
+
"""Remove every comment-marker run from *line*, leaving no stray spacing.
|
|
651
|
+
|
|
652
|
+
A run stands where the author wrote nothing, so it is replaced by the one
|
|
653
|
+
space that keeps its neighbours apart — ``AND /* m */ RTRIM(`` must not
|
|
654
|
+
become ``ANDRTRIM(``. At the ends of the line, or against punctuation
|
|
655
|
+
that binds to the token before it, that space is not a separator but
|
|
656
|
+
residue: sqlglot emitting ``1 = 1 /* m */;`` left ``1 = 1 ;``, which the
|
|
657
|
+
next run then normalised — costing a pass and making ``--check`` fail on a
|
|
658
|
+
file that was already formatted. See issue #35.
|
|
659
|
+
"""
|
|
660
|
+
|
|
661
|
+
def repl(match: re.Match[str]) -> str:
|
|
662
|
+
before = line[: match.start()]
|
|
663
|
+
after = line[match.end() :]
|
|
664
|
+
if not before.strip() or not after.strip():
|
|
665
|
+
return ""
|
|
666
|
+
if after[:1] in _NO_SPACE_BEFORE or before.endswith("("):
|
|
667
|
+
return ""
|
|
668
|
+
return " "
|
|
669
|
+
|
|
670
|
+
return _CMT_MARKER_RUN_RE.sub(repl, line)
|
|
671
|
+
|
|
591
672
|
|
|
592
673
|
def _format_preserving_comments(
|
|
593
674
|
lines: list[str],
|
|
@@ -613,6 +694,7 @@ def _format_preserving_comments(
|
|
|
613
694
|
comment_store: dict[str, str] = {} # marker → original comment line
|
|
614
695
|
# Track the SQL line that originally followed each comment, for fallback
|
|
615
696
|
anchor_sql: dict[str, str] = {} # marker → next SQL line (stripped)
|
|
697
|
+
anchor_line: dict[str, int] = {} # marker → index of that line in `processed`
|
|
616
698
|
pending_markers: list[str] = []
|
|
617
699
|
processed: list[str] = []
|
|
618
700
|
in_block = False
|
|
@@ -639,50 +721,87 @@ def _format_preserving_comments(
|
|
|
639
721
|
processed.append(f"{prefix} {line}" if prefix else line)
|
|
640
722
|
for m in pending_markers:
|
|
641
723
|
anchor_sql[m] = stripped
|
|
724
|
+
anchor_line[m] = len(processed) - 1
|
|
642
725
|
pending_markers.clear()
|
|
643
726
|
|
|
644
727
|
# Trailing comments with no following SQL — preserve as-is
|
|
645
728
|
trailing: list[str] = [comment_store[m] for m in pending_markers]
|
|
646
729
|
|
|
730
|
+
# Parenthesis depth each comment sat at in the input. A comment on its own
|
|
731
|
+
# line belongs to the SQL line below it, so it shares that line's depth.
|
|
732
|
+
in_depths = _paren_depths(processed)
|
|
733
|
+
anchor_depth: dict[str, int] = {m: in_depths[i] for m, i in anchor_line.items()}
|
|
734
|
+
|
|
647
735
|
# ---- Step 2: format through sqlglot ---------------------------------
|
|
648
736
|
formatted = _sqlglot_format(processed, sql_indent=sql_indent, leading_comma=leading_comma)
|
|
649
737
|
|
|
650
738
|
# ---- Step 3: restore surviving markers to comment lines -------------
|
|
651
739
|
found_markers: set[str] = set()
|
|
652
|
-
|
|
740
|
+
sql_out: list[str] = []
|
|
741
|
+
marker_sites: list[tuple[int, str]] = [] # (index in sql_out, marker)
|
|
653
742
|
for fline in formatted:
|
|
654
743
|
markers_here = _CMT_MARKER_RE.findall(fline)
|
|
655
|
-
if markers_here:
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
744
|
+
if not markers_here:
|
|
745
|
+
sql_out.append(fline)
|
|
746
|
+
continue
|
|
747
|
+
# Strip markers to get the underlying SQL line and its indent
|
|
748
|
+
cleaned = _strip_marker_runs(fline).strip()
|
|
749
|
+
# Indent comes from the line's own leading whitespace, never from
|
|
750
|
+
# what is left after removing the marker. Markers are injected as
|
|
751
|
+
# ``/* marker */ line`` — with a separating space — so measuring
|
|
752
|
+
# after removal counts that space as indentation. Whenever
|
|
753
|
+
# sqlglot leaves the line untouched (an unparsable statement falls
|
|
754
|
+
# back verbatim) the extra space is re-measured and re-added on the
|
|
755
|
+
# next run, growing the indent by one on every pass and never
|
|
756
|
+
# converging. See issue #35.
|
|
757
|
+
line_indent = fline[: len(fline) - len(fline.lstrip())]
|
|
758
|
+
for m in markers_here:
|
|
759
|
+
if m in comment_store:
|
|
760
|
+
marker_sites.append((len(sql_out), m))
|
|
761
|
+
found_markers.add(m)
|
|
762
|
+
if cleaned:
|
|
763
|
+
sql_out.append(line_indent + cleaned)
|
|
764
|
+
|
|
765
|
+
# Place each comment above the line where its expression *starts*, not
|
|
766
|
+
# above whatever line the marker landed on. sqlglot attaches an inline
|
|
767
|
+
# comment to a node, and when it then reflows that node across lines the
|
|
768
|
+
# marker can surface deep inside the expression — ``COALESCE((a.b).c,
|
|
769
|
+
# FALSE)`` puts it on the ``).c, FALSE)`` continuation line. Restoring
|
|
770
|
+
# there splits the expression around a comment that now documents a
|
|
771
|
+
# fragment of it. The comment's own line in the input sat at the
|
|
772
|
+
# parenthesis depth of the SQL line below it, so walk back from the marker
|
|
773
|
+
# to the nearest line at that depth: the line the reflowed expression
|
|
774
|
+
# opens on. A marker that did not move is already at its anchor depth and
|
|
775
|
+
# stays where it is.
|
|
776
|
+
out_depths = _paren_depths(sql_out)
|
|
777
|
+
comments_before: dict[int, list[str]] = {}
|
|
778
|
+
for idx, marker in marker_sites:
|
|
779
|
+
target = idx
|
|
780
|
+
want = anchor_depth.get(marker, 0)
|
|
781
|
+
while target > 0 and target < len(out_depths) and out_depths[target] > want:
|
|
782
|
+
target -= 1
|
|
783
|
+
orig_stripped = comment_store[marker].strip()
|
|
784
|
+
if not orig_stripped:
|
|
785
|
+
comments_before.setdefault(target, []).append("")
|
|
786
|
+
continue
|
|
787
|
+
# Re-indent the comment to match the SQL line it precedes
|
|
788
|
+
if target < len(sql_out):
|
|
789
|
+
anchor = sql_out[target]
|
|
790
|
+
indent_str = anchor[: len(anchor) - len(anchor.lstrip())]
|
|
679
791
|
else:
|
|
680
|
-
|
|
792
|
+
indent_str = ""
|
|
793
|
+
comments_before.setdefault(target, []).append(indent_str + orig_stripped)
|
|
794
|
+
|
|
795
|
+
result: list[str] = []
|
|
796
|
+
for i, line in enumerate(sql_out):
|
|
797
|
+
result.extend(comments_before.get(i, ()))
|
|
798
|
+
result.append(line)
|
|
799
|
+
result.extend(comments_before.get(len(sql_out), ()))
|
|
681
800
|
|
|
682
801
|
# ---- Step 4: reinsert lost markers ----------------------------------
|
|
683
802
|
lost = [m for m in comment_store if m not in found_markers and m not in set(pending_markers)]
|
|
684
803
|
if lost:
|
|
685
|
-
_reinsert_lost_comments(result, lost, comment_store, anchor_sql)
|
|
804
|
+
_reinsert_lost_comments(result, lost, comment_store, anchor_sql, anchor_depth)
|
|
686
805
|
|
|
687
806
|
result.extend(trailing)
|
|
688
807
|
return result
|
|
@@ -693,14 +812,22 @@ def _reinsert_lost_comments(
|
|
|
693
812
|
lost_markers: list[str],
|
|
694
813
|
comment_store: dict[str, str],
|
|
695
814
|
anchor_sql: dict[str, str],
|
|
815
|
+
anchor_depth: dict[str, int],
|
|
696
816
|
) -> None:
|
|
697
817
|
"""Best-effort reinsertion of comments that sqlglot dropped.
|
|
698
818
|
|
|
699
819
|
For each lost comment, extract key tokens from its anchor SQL line and
|
|
700
820
|
find the output line that best matches, then insert the comment before
|
|
701
821
|
that line (indented to match). Operates on *result* in place.
|
|
822
|
+
|
|
823
|
+
Token matching scores whole lines, so on a reflowed expression the best
|
|
824
|
+
match is often a continuation line — ``a.meas_value`` out of ``CASE WHEN
|
|
825
|
+
(a.meas_value).undetected``. Inserting there splits the expression, so
|
|
826
|
+
the match is pulled back to the line where the expression opens, the same
|
|
827
|
+
way surviving markers are placed in :func:`_format_preserving_comments`.
|
|
702
828
|
"""
|
|
703
829
|
_word_re = re.compile(r"[a-zA-Z_]\w*")
|
|
830
|
+
out_depths = _paren_depths(result)
|
|
704
831
|
|
|
705
832
|
# Process in reverse order so earlier inserts don't shift later indices.
|
|
706
833
|
insertions: list[tuple[int, str]] = []
|
|
@@ -727,6 +854,10 @@ def _reinsert_lost_comments(
|
|
|
727
854
|
best_score = score
|
|
728
855
|
best_idx = i
|
|
729
856
|
|
|
857
|
+
want = anchor_depth.get(marker, 0)
|
|
858
|
+
while best_idx > 0 and best_idx < len(out_depths) and out_depths[best_idx] > want:
|
|
859
|
+
best_idx -= 1
|
|
860
|
+
|
|
730
861
|
# Re-indent comment to match the target line
|
|
731
862
|
if best_idx < len(result):
|
|
732
863
|
target = result[best_idx]
|
execsql/utils/mail.py
CHANGED
|
@@ -66,15 +66,19 @@ class Mailer:
|
|
|
66
66
|
self.smtpconn = smtplib.SMTP_SSL(conf.smtp_host, conf.smtp_port, timeout=smtp_timeout)
|
|
67
67
|
else:
|
|
68
68
|
self.smtpconn = smtplib.SMTP(conf.smtp_host, conf.smtp_port, timeout=smtp_timeout)
|
|
69
|
-
self.smtpconn.
|
|
69
|
+
self.smtpconn.ehlo_or_helo_if_needed()
|
|
70
70
|
if conf.smtp_tls:
|
|
71
71
|
self.smtpconn.starttls()
|
|
72
72
|
self.smtpconn.ehlo(conf.smtp_host)
|
|
73
73
|
if conf.smtp_username:
|
|
74
|
-
if conf.smtp_password:
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
if not conf.smtp_password:
|
|
75
|
+
# smtplib.login() requires a password; calling it with only a
|
|
76
|
+
# username raises TypeError deep in the stdlib.
|
|
77
|
+
raise ErrInfo(
|
|
78
|
+
type="error",
|
|
79
|
+
other_msg="Can't send email; an SMTP username is configured but no password.",
|
|
80
|
+
)
|
|
81
|
+
self.smtpconn.login(conf.smtp_username, conf.smtp_password)
|
|
78
82
|
|
|
79
83
|
def sendmail(
|
|
80
84
|
self,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.22.
|
|
3
|
+
Version: 2.22.9
|
|
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
|
|
@@ -384,7 +384,7 @@ execsql-format --no-sql --in-place scripts/
|
|
|
384
384
|
```yaml
|
|
385
385
|
repos:
|
|
386
386
|
- repo: https://github.com/geocoug/execsql
|
|
387
|
-
rev: v2.22.
|
|
387
|
+
rev: v2.22.9
|
|
388
388
|
hooks:
|
|
389
389
|
- id: execsql-format
|
|
390
390
|
```
|
|
@@ -3,7 +3,7 @@ execsql/__main__.py,sha256=HdbK-SAhyUmfB6xINY5AzxdMSxGzWSGEG_2dv42Jn64,315
|
|
|
3
3
|
execsql/api.py,sha256=EOtBwMnm-8fmB_KmvxyjglR6C7CjdYhCPBisJ9CFfJg,22227
|
|
4
4
|
execsql/config.py,sha256=txKziUJLV7UPonj2sGFgkmlinDdSV50aHmR_cuCbEIo,34369
|
|
5
5
|
execsql/exceptions.py,sha256=GlphAiR8iZu4UR4U50WgSqEUMd9_8AeQJ_hhPcJOeQU,9381
|
|
6
|
-
execsql/format.py,sha256=
|
|
6
|
+
execsql/format.py,sha256=OOxsOX6g7otVgL3gI6uGxa5WIh8GTvjJ8WO-_P91zXg,52886
|
|
7
7
|
execsql/models.py,sha256=-DWTVrPNwM-n1h3e3rXMoBv9-wpWVdZahyy4RB7fRRE,15502
|
|
8
8
|
execsql/parser.py,sha256=aOxZ7Mzgvk7G4-nvy9Bgz7xlaZm6oo81cffDeBk_LCk,15597
|
|
9
9
|
execsql/plugins.py,sha256=l82VWa5NpvOQWD6vcO-WKP-vtn0wp9__wWDFAbwxZg0,12838
|
|
@@ -17,7 +17,7 @@ execsql/cli/help.py,sha256=ThwdZuMIfLPxLAPpGWwXFY_UfyWvYOCjdlBNK20Vzd8,5718
|
|
|
17
17
|
execsql/cli/lint.py,sha256=YqKzFNUhyb_Th69hYgKk1ZZVjCsZfJMIiUGqp06JwNs,17236
|
|
18
18
|
execsql/cli/run.py,sha256=Yb-Ri3cds0st1hUn4_w-PHMphTsArHhC4fx919SW9gU,39390
|
|
19
19
|
execsql/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
execsql/data/execsql.conf.template,sha256=
|
|
20
|
+
execsql/data/execsql.conf.template,sha256=zbjEluk6j9vnW74nlWpvopM6HDYe0rwJhsPVzU-e0Ss,11032
|
|
21
21
|
execsql/db/__init__.py,sha256=jTbuafuKOqYtXFR1wvCOoKK5Lr3l1uErfaIbIr6UywI,1063
|
|
22
22
|
execsql/db/access.py,sha256=h2zAMr3mQrm6vFlOYaN7iaG19K7gitXDuonllelqbcE,19539
|
|
23
23
|
execsql/db/base.py,sha256=0K6mSCqFcheg_T91VOwEnagqqP_eLL2dP5VN4yDz36Q,35414
|
|
@@ -96,28 +96,28 @@ execsql/utils/datetime.py,sha256=8BrD24KWeMoouJZiFaXK4HF7plc-O_xrzIw12qOEyp8,362
|
|
|
96
96
|
execsql/utils/errors.py,sha256=bDWooUmGdN8xqUt6csq466wPqKPLHHSi7U4hsmrFZxA,8577
|
|
97
97
|
execsql/utils/fileio.py,sha256=_15UIdcRZxZn2R6YP4xQn-6C9CVK2yxj1oEfxULo2_c,33329
|
|
98
98
|
execsql/utils/gui.py,sha256=X5aw6LVoeaAdHaQkymm4ba176jga0cS2GrqxSFWTWTg,23853
|
|
99
|
-
execsql/utils/mail.py,sha256=
|
|
99
|
+
execsql/utils/mail.py,sha256=SXZac24p62qxDbIviO8VdDZTbKljIoJWgWZfxIGu5zI,6260
|
|
100
100
|
execsql/utils/numeric.py,sha256=_7bi5R6pHjMCkOPne_Sh5nUj-B8e9g6WFmjptFHaunA,1573
|
|
101
101
|
execsql/utils/regex.py,sha256=B3mSBhRRx_DpUnX_t9IoYd05KvWAebiLMCZqQAmEwcw,3885
|
|
102
102
|
execsql/utils/strings.py,sha256=UQNjpRCEFa1UO6feU-M-9e24wWAvizs_iu_4fFusLxo,8516
|
|
103
103
|
execsql/utils/timer.py,sha256=eDYf5VzCNFk7oo90InJucUm3XcBdhYMogjZMqeg9xzc,1899
|
|
104
|
-
execsql2-2.22.
|
|
105
|
-
execsql2-2.22.
|
|
106
|
-
execsql2-2.22.
|
|
107
|
-
execsql2-2.22.
|
|
108
|
-
execsql2-2.22.
|
|
109
|
-
execsql2-2.22.
|
|
110
|
-
execsql2-2.22.
|
|
111
|
-
execsql2-2.22.
|
|
112
|
-
execsql2-2.22.
|
|
113
|
-
execsql2-2.22.
|
|
114
|
-
execsql2-2.22.
|
|
115
|
-
execsql2-2.22.
|
|
116
|
-
execsql2-2.22.
|
|
117
|
-
execsql2-2.22.
|
|
118
|
-
execsql2-2.22.
|
|
119
|
-
execsql2-2.22.
|
|
120
|
-
execsql2-2.22.
|
|
121
|
-
execsql2-2.22.
|
|
122
|
-
execsql2-2.22.
|
|
123
|
-
execsql2-2.22.
|
|
104
|
+
execsql2-2.22.9.data/data/execsql2_extras/README.md,sha256=vX4NTL095dUoA_hesyRMGYBorEZ_Y_tJ9qrd-MVV09I,5032
|
|
105
|
+
execsql2-2.22.9.data/data/execsql2_extras/config_settings.sqlite,sha256=aY5cxR7Q7J6zJ4bC9lu5mHUrhy211Cq3MNKPQVCt02E,20480
|
|
106
|
+
execsql2-2.22.9.data/data/execsql2_extras/example_config_prompt.sql,sha256=2e8KzzVWhho8KxYVHETSVmZdhW7wodioDsqBLSL6m4s,7487
|
|
107
|
+
execsql2-2.22.9.data/data/execsql2_extras/make_config_db.sql,sha256=WwyC6dK-Eh5CAVppiBCDHqiI1_wEI9U95Ytpr4lsZkg,8726
|
|
108
|
+
execsql2-2.22.9.data/data/execsql2_extras/md_compare.sql,sha256=qYYVAjSeHZzjszxV3Bv6bg8Ckbq2kMHl87_gh4sywMU,24140
|
|
109
|
+
execsql2-2.22.9.data/data/execsql2_extras/md_glossary.sql,sha256=hkZ2Onn57LAKKsuXxzhR8tPtcWXkmWEQkwPE58-Tm2k,10796
|
|
110
|
+
execsql2-2.22.9.data/data/execsql2_extras/md_upsert.sql,sha256=_CAK4BzEboRXTNy03SJR-oOjcEdSNMuRBPL6noWUptY,112560
|
|
111
|
+
execsql2-2.22.9.data/data/execsql2_extras/pg_compare.sql,sha256=1zJd4hVUKHR0tncc2qTBC9B4qVV4Us2ITkJpsjN3tMw,24352
|
|
112
|
+
execsql2-2.22.9.data/data/execsql2_extras/pg_glossary.sql,sha256=IKuwna-_8b20ljSkXZruuiQigrCpo7ueQdUqd1MXiuI,9908
|
|
113
|
+
execsql2-2.22.9.data/data/execsql2_extras/pg_upsert.sql,sha256=HpPJtTHvpEjQy03j-3iPxDEOHMRkudOg7O4D4YR38UI,108315
|
|
114
|
+
execsql2-2.22.9.data/data/execsql2_extras/script_template.sql,sha256=2J35ddZPguJ-vwTsz83wErv0jiWUyJcdW_JM0mNKDXA,11155
|
|
115
|
+
execsql2-2.22.9.data/data/execsql2_extras/ss_compare.sql,sha256=j1qVNUPXQsEU7-DoVgDJCGcE0EuIl7whLBT3fgeiMAo,24833
|
|
116
|
+
execsql2-2.22.9.data/data/execsql2_extras/ss_glossary.sql,sha256=2gLxv34xzKt0vy7hSzJH7a9JiMC3ETrv9MofxQwAibU,13065
|
|
117
|
+
execsql2-2.22.9.data/data/execsql2_extras/ss_upsert.sql,sha256=G_8rQ0VzuKIZHWs24O_WrfzpC5S27R1JsL-bFBR3SUQ,117730
|
|
118
|
+
execsql2-2.22.9.dist-info/METADATA,sha256=Ku6XhxrqV05mj1lvzrZEO6p4uKCa_PA2tbs43yBT9ew,20382
|
|
119
|
+
execsql2-2.22.9.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
120
|
+
execsql2-2.22.9.dist-info/entry_points.txt,sha256=sUOxkM-dN1eBGGpSpDLsAaE0yNXYQKWZAfxPOlMkQyk,90
|
|
121
|
+
execsql2-2.22.9.dist-info/licenses/LICENSE.txt,sha256=LBdhuxejF8_bLCHZ2kWfmDXpDGUu914Gbd6_3JjCRe0,676
|
|
122
|
+
execsql2-2.22.9.dist-info/licenses/NOTICE,sha256=McYzgxYav3U1OaVsY4Su1sfBrfmplpRdA9b6-gCDQCg,342
|
|
123
|
+
execsql2-2.22.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{execsql2-2.22.7.data → execsql2-2.22.9.data}/data/execsql2_extras/example_config_prompt.sql
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|