Skip to content

Commit 154c7e3

Browse files
committed
Minor optimization
1 parent d6b491d commit 154c7e3

4 files changed

Lines changed: 76 additions & 55 deletions

File tree

data/txt/sha256sums.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,13 +170,13 @@ d69e84f1648cdb907f5d2dd454f03874a4613752b07867510145d51d84b3c56f lib/controller
170170
c51c33501cc905586a9aaac93b06f2ac6f71628d032a7dc39fd0ef05d7ee3856 lib/core/bigarray.py
171171
d143df718fbaacb617b6046c73cf4e47932e1a25928a4e1ecb87ea77a3b154ed lib/core/common.py
172172
8f1272487e1adfcc8c755a2f56f0c6d21eac5e685a73a9a159482f9dc9142bc5 lib/core/compat.py
173-
a683d0ad9ba543587382c4903d28db610ae20394fcf9045a68b2ab54a39381ae lib/core/convert.py
173+
5301ba2204404d086e9a67271cde00fc10214c63b018a95fc5aa90ff9e0b2ad9 lib/core/convert.py
174174
c03dc585f89642cfd81b087ac2723e3e1bb3bfa8c60e6f5fe58ef3b0113ebfe6 lib/core/data.py
175175
d9ec034a6d51ab4ddde0b6aa7ed306f9e0b1336557f77d7939ba547600f9b3ae lib/core/datatype.py
176176
f8de57606325456928e46ae2896f5f8bbec9ad18b1c644b492a566fa992216f6 lib/core/decorators.py
177177
147823c37596bd6a56d677697781f34b8d1d1671d5a2518fbc9468d623c6d07d lib/core/defaults.py
178178
8e4f4b5ea37a49d445bb0df83bf04b34f61035ec33fd8acf598ebcf371cb19a7 lib/core/dicts.py
179-
854073f899b876ab13b36e93e174b9cfe51408f7343040197a80afd9fc9c65ee lib/core/dump.py
179+
10d8bb671a64cc787fc2fbf2c641560b7797fccd62c4792e55dffe5efab9f544 lib/core/dump.py
180180
6dd47f52082e98dc0cda6969b277b7d81c6f7c68dac4688821f873a1c65c6edf lib/core/enums.py
181181
5387168e5dfedd94ae22af7bb255f27d6baaca50b24179c6b98f4f325f5cc7b4 lib/core/exception.py
182182
1966ca704961fb987ab757f0a4afddbf841d1a880631b701487c75cef63d60c3 lib/core/__init__.py
@@ -189,7 +189,7 @@ f8de57606325456928e46ae2896f5f8bbec9ad18b1c644b492a566fa992216f6 lib/core/decor
189189
9bf174058f15d14e24e94f9aaf42df045119d3617c6c54bd2f3af79b462f331d lib/core/replication.py
190190
0b8c38a01bb01f843d94a6c5f2075ee47520d0c4aa799cecea9c3e2c5a4a23a6 lib/core/revision.py
191191
888daba83fd4a34e9503fe21f01fef4cc730e5cde871b1d40e15d4cbc847d56c lib/core/session.py
192-
4d9cc21e2b2a10fd6c06ce6c9b248fd16a4c266511cd01156bbe7643e5327a89 lib/core/settings.py
192+
516d6b40efa04a5a25b0aa317ea49771f6964a57581777761f82d36d1b1b78b0 lib/core/settings.py
193193
c7804223319e18eb0b8e2cbf0a8b6896d1cefb7b0b1a2e9f1cf826a8a3b56750 lib/core/shell.py
194194
a2e98a94b231432736d6b304fc75525c8b5fdb4768c418387c5b4c1a610dad64 lib/core/subprocessng.py
195195
19f1e3c5e3ba703d28d510cd7a9ab8284d5fbe9df5ce7e77c86e5931571364b7 lib/core/target.py

lib/core/convert.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,9 @@ def stdoutEncode(value):
464464

465465
return retVal
466466

467+
# str.isascii() is available on Python 3.7+ only (sqlmap still supports 2.7)
468+
_HAS_ISASCII = hasattr(str, "isascii")
469+
467470
def getConsoleLength(value):
468471
"""
469472
Returns console width of unicode values
@@ -475,7 +478,15 @@ def getConsoleLength(value):
475478
"""
476479

477480
if isinstance(value, six.text_type):
478-
retVal = len(value) + sum(ord(_) >= 0x3000 for _ in value)
481+
# Fast path: ASCII values have no wide (>= U+3000) characters, so their
482+
# console width is simply their length. str.isascii() (Python 3.7+) is a
483+
# C-level scan, far cheaper than the per-character generator below (which
484+
# stays for the rare wide-character case and for Python 2). This runs
485+
# once per dumped cell, so it dominates large table dumps.
486+
if _HAS_ISASCII and value.isascii():
487+
retVal = len(value)
488+
else:
489+
retVal = len(value) + sum(ord(_) >= 0x3000 for _ in value)
479490
else:
480491
retVal = len(value)
481492

lib/core/dump.py

Lines changed: 60 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -627,74 +627,84 @@ def dbTableValues(self, tableValues):
627627
elif conf.dumpFormat == DUMP_FORMAT.SQLITE:
628628
rtable.beginTransaction()
629629

630+
# Precompute the per-column layout once. These values are invariant across
631+
# every row, so resolving them per cell (dict lookup, int() conversion and
632+
# identifier normalization) wasted count x ncols work on large dumps.
633+
dumpColumns = []
634+
for column in columns:
635+
if column != "__infos__":
636+
info = tableValues[column]
637+
dumpColumns.append((unsafeSQLIdentificatorNaming(column), info["values"], int(info["length"])))
638+
630639
for i in xrange(count):
631640
console = (i >= count - TRIM_STDOUT_DUMP_SIZE)
632641
field = 1
633-
values = []
634-
record = OrderedDict()
642+
643+
# Only the SQLITE and JSONL paths accumulate a per-row container; the
644+
# others left these unused, wasting an allocation on every single row
645+
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
646+
values = []
647+
elif conf.dumpFormat == DUMP_FORMAT.JSONL:
648+
record = OrderedDict()
635649

636650
if i == 0 and count > TRIM_STDOUT_DUMP_SIZE:
637651
self._write(" ...")
638652

639653
if conf.dumpFormat == DUMP_FORMAT.HTML:
640654
dataToDumpFile(dumpFP, "<tr>")
641655

642-
for column in columns:
643-
if column != "__infos__":
644-
info = tableValues[column]
645-
646-
if len(info["values"]) <= i or info["values"][i] is None:
647-
value = u''
656+
for safeColumn, colValues, maxlength in dumpColumns:
657+
if len(colValues) <= i or colValues[i] is None:
658+
value = u''
659+
else:
660+
value = getUnicode(colValues[i])
661+
value = DUMP_REPLACEMENTS.get(value, value)
662+
663+
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
664+
# Note: store a real NULL for the NULL sentinel (and the raw value otherwise),
665+
# mirroring the JSONL path below; appending the display-replaced 'NULL'/'<blank>'
666+
# text would corrupt the INTEGER/REAL-typed columns inferred above
667+
if len(colValues) <= i or colValues[i] is None or colValues[i] == " ": # NULL
668+
values.append(None)
648669
else:
649-
value = getUnicode(info["values"][i])
650-
value = DUMP_REPLACEMENTS.get(value, value)
651-
652-
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
653-
# Note: store a real NULL for the NULL sentinel (and the raw value otherwise),
654-
# mirroring the JSONL path below; appending the display-replaced 'NULL'/'<blank>'
655-
# text would corrupt the INTEGER/REAL-typed columns inferred above
656-
if len(info["values"]) <= i or info["values"][i] is None or info["values"][i] == " ": # NULL
657-
values.append(None)
658-
else:
659-
values.append(getUnicode(info["values"][i]))
670+
values.append(getUnicode(colValues[i]))
660671

661-
maxlength = int(info["length"])
662-
blank = " " * (maxlength - getConsoleLength(value))
663-
self._write("| %s%s" % (value, blank), newline=False, console=console)
672+
blank = " " * (maxlength - getConsoleLength(value))
673+
self._write("| %s%s" % (value, blank), newline=False, console=console)
664674

665-
if len(value) > MIN_BINARY_DISK_DUMP_SIZE and r'\x' in value:
666-
try:
667-
mimetype = getText(magic.from_buffer(getBytes(value), mime=True))
668-
if any(mimetype.startswith(_) for _ in ("application", "image")):
669-
if not os.path.isdir(dumpDbPath):
670-
os.makedirs(dumpDbPath)
675+
if len(value) > MIN_BINARY_DISK_DUMP_SIZE and r'\x' in value:
676+
try:
677+
mimetype = getText(magic.from_buffer(getBytes(value), mime=True))
678+
if any(mimetype.startswith(_) for _ in ("application", "image")):
679+
if not os.path.isdir(dumpDbPath):
680+
os.makedirs(dumpDbPath)
671681

672-
_ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(unsafeSQLIdentificatorNaming(column)))
673-
filepath = os.path.join(dumpDbPath, "%s-%d.bin" % (_, randomInt(8)))
674-
warnMsg = "writing binary ('%s') content to file '%s' " % (mimetype, filepath)
675-
logger.warning(warnMsg)
682+
_ = re.sub(r"[^\w]", UNSAFE_DUMP_FILEPATH_REPLACEMENT, normalizeUnicode(safeColumn))
683+
filepath = os.path.join(dumpDbPath, "%s-%d.bin" % (_, randomInt(8)))
684+
warnMsg = "writing binary ('%s') content to file '%s' " % (mimetype, filepath)
685+
logger.warning(warnMsg)
676686

677-
with openFile(filepath, "w+b", None) as f:
678-
_ = safechardecode(value, True)
679-
f.write(_)
687+
with openFile(filepath, "w+b", None) as f:
688+
_ = safechardecode(value, True)
689+
f.write(_)
680690

681-
except Exception as ex:
682-
logger.debug(getSafeExString(ex))
691+
except Exception as ex:
692+
logger.debug(getSafeExString(ex))
683693

684-
if conf.dumpFormat == DUMP_FORMAT.CSV:
685-
if field == fields:
686-
dataToDumpFile(dumpFP, "%s" % safeCSValue(value))
687-
else:
688-
dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(value), conf.csvDel))
689-
elif conf.dumpFormat == DUMP_FORMAT.HTML:
690-
dataToDumpFile(dumpFP, "<td>%s</td>" % getUnicode(htmlEscape(value).encode("ascii", "xmlcharrefreplace")))
691-
elif conf.dumpFormat == DUMP_FORMAT.JSONL:
692-
if len(info["values"]) <= i or info["values"][i] is None or info["values"][i] == " ": # NULL
693-
record[unsafeSQLIdentificatorNaming(column)] = None
694-
else:
695-
record[unsafeSQLIdentificatorNaming(column)] = getUnicode(info["values"][i])
694+
if conf.dumpFormat == DUMP_FORMAT.CSV:
695+
if field == fields:
696+
dataToDumpFile(dumpFP, "%s" % safeCSValue(value))
697+
else:
698+
dataToDumpFile(dumpFP, "%s%s" % (safeCSValue(value), conf.csvDel))
699+
elif conf.dumpFormat == DUMP_FORMAT.HTML:
700+
dataToDumpFile(dumpFP, "<td>%s</td>" % getUnicode(htmlEscape(value).encode("ascii", "xmlcharrefreplace")))
701+
elif conf.dumpFormat == DUMP_FORMAT.JSONL:
702+
if len(colValues) <= i or colValues[i] is None or colValues[i] == " ": # NULL
703+
record[safeColumn] = None
704+
else:
705+
record[safeColumn] = getUnicode(colValues[i])
696706

697-
field += 1
707+
field += 1
698708

699709
if conf.dumpFormat == DUMP_FORMAT.SQLITE:
700710
try:

lib/core/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from thirdparty import six
2121

2222
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
23-
VERSION = "1.10.6.201"
23+
VERSION = "1.10.7.0"
2424
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
2525
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
2626
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

0 commit comments

Comments
 (0)