Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions async_postgres/pg_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -407,9 +407,9 @@ template appendInlineParam(
let oldLen = data.len
data.setLen(oldLen + int(p.len))
if p.len <= PgInlineBufSize:
copyMem(addr data[oldLen], addr p.inlineBuf[0], int(p.len))
data.writeBytesAt(oldLen, p.inlineBuf.toOpenArray(0, int(p.len) - 1))
else:
copyMem(addr data[oldLen], addr p.overflow[0], int(p.len))
data.writeBytesAt(oldLen, p.overflow.toOpenArray(0, int(p.len) - 1))
ranges.add((dataOff, p.len))

proc flattenInline(
Expand Down Expand Up @@ -1612,7 +1612,7 @@ proc copyIn*(
## Converts to bytes internally; avoids manual toOpenArrayByte.
var bytes = newSeq[byte](data.len)
if data.len > 0:
copyMem(addr bytes[0], addr data[0], data.len)
bytes.writeBytesAt(0, data.toOpenArrayByte(0, data.high))
copyIn(conn, sql, bytes, timeout)

proc copyIn*(
Expand All @@ -1630,9 +1630,8 @@ proc copyIn*(
var combined = newSeq[byte](totalLen)
var offset = 0
for chunk in data:
if chunk.len > 0:
copyMem(addr combined[offset], addr chunk[0], chunk.len)
offset += chunk.len
combined.writeBytesAt(offset, chunk)
offset += chunk.len
copyIn(conn, sql, combined, timeout)

proc copyInStreamImpl(
Expand Down
16 changes: 4 additions & 12 deletions async_postgres/pg_replication.nim
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,7 @@ proc `<=`*(a, b: Lsn): bool {.borrow.}

proc toString*(field: TupleField): string =
## Convert a TupleField's data to a string by copying the bytes.
result = newString(field.data.len)
if field.data.len > 0:
copyMem(addr result[0], addr field.data[0], field.data.len)
result = readString(field.data, 0, field.data.len)

template toUInt64*(lsn: Lsn): uint64 =
## Get the raw uint64 value of an LSN.
Expand Down Expand Up @@ -238,9 +236,7 @@ proc decodeCStringAt(buf: openArray[byte], offset: int): (string, int) =
if i >= buf.len:
raise newException(ProtocolError, "decodeCStringAt: missing null terminator")
let slen = i - offset
var s = newString(slen)
if slen > 0:
copyMem(addr s[0], addr buf[offset], slen)
let s = readString(buf, offset, slen)
inc i # skip null
(s, i)

Expand All @@ -261,9 +257,7 @@ proc decodeTuple(buf: openArray[byte], offset: int): (seq[TupleField], int) =
of 't', 'b':
let dataLen = decodeInt32(buf, pos)
pos += 4
var data = newSeq[byte](dataLen)
if dataLen > 0:
copyMem(addr data[0], addr buf[pos], dataLen)
let data = readBytes(buf, pos, int(dataLen))
pos += int(dataLen)
fields[i] = TupleField(kind: if kind == 't': tdkText else: tdkBinary, data: data)
else:
Expand Down Expand Up @@ -387,9 +381,7 @@ proc parsePgOutputMessage*(data: openArray[byte]): PgOutputMessage =
pos = nextPos
let contentLen = decodeInt32(data, pos)
pos += 4
if contentLen > 0:
msg.content = newSeq[byte](contentLen)
copyMem(addr msg.content[0], addr data[pos], contentLen)
msg.content = readBytes(data, pos, int(contentLen))
PgOutputMessage(kind: pomkMessage, message: msg)
else:
raise newException(ProtocolError, "Unknown pgoutput message type: " & msgType)
Expand Down
30 changes: 7 additions & 23 deletions async_postgres/pg_types/accessors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,7 @@ proc getStr*(row: Row, col: int): string =
return $decodeNumericBinary(b.toOpenArray(off, off + clen - 1))
else:
discard # text, varchar, bytea: fall through to raw copy
result = newString(clen)
if clen > 0:
copyMem(addr result[0], addr row.data.buf[off], clen)
result = readString(row.data.buf, off, clen)

proc getInt*(row: Row, col: int): int32 =
## Get a column value as int32. Handles binary int2/int4 directly. Raises `PgTypeError` on NULL.
Expand Down Expand Up @@ -352,9 +350,7 @@ proc getBytes*(row: Row, col: int): seq[byte] =
raise newException(PgTypeError, "Column " & $col & " is NULL")
if row.isBinaryCol(col):
# Binary format: raw bytes, no hex encoding
result = newSeq[byte](clen)
if clen > 0:
copyMem(addr result[0], addr row.data.buf[off], clen)
result = readBytes(row.data.buf, off, clen)
return
# Text format: bytea uses hex encoding \xDEADBEEF
if clen >= 2 and row.data.buf[off] == byte('\\') and row.data.buf[off + 1] == byte(
Expand All @@ -368,9 +364,7 @@ proc getBytes*(row: Row, col: int): seq[byte] =
for i in 0 ..< result.len:
result[i] = byte(parseHexInt(hex[i * 2 .. i * 2 + 1]))
else:
result = newSeq[byte](clen)
if clen > 0:
copyMem(addr result[0], addr row.data.buf[off], clen)
result = readBytes(row.data.buf, off, clen)

proc getTimestamp*(row: Row, col: int): DateTime =
## Get a column value as DateTime. Handles binary timestamp format.
Expand Down Expand Up @@ -946,9 +940,7 @@ proc getStrArray*(row: Row, col: int): seq[string] =
for i, e in decoded.elements:
if e.len == -1:
raise newException(PgTypeError, "NULL element in string array")
result[i] = newString(e.len)
if e.len > 0:
copyMem(addr result[i][0], addr row.data.buf[off + e.off], e.len)
result[i] = readString(row.data.buf, off + e.off, e.len)
return
let s = row.getStr(col)
let elems = parseTextArray(s)
Expand Down Expand Up @@ -1226,9 +1218,7 @@ proc getBytesArray*(row: Row, col: int): seq[seq[byte]] =
for i, e in decoded.elements:
if e.len == -1:
raise newException(PgTypeError, "NULL element in bytea array")
result[i] = newSeq[byte](e.len)
if e.len > 0:
copyMem(addr result[i][0], addr row.data.buf[off + e.off], e.len)
result[i] = readBytes(row.data.buf, off + e.off, e.len)
return
let s = row.getStr(col)
let elems = parseTextArray(s)
Expand Down Expand Up @@ -1509,10 +1499,7 @@ template genStringArrayDecoder(getProc: untyped, T: typedesc, typeName: static s
for i, e in decoded.elements:
if e.len == -1:
raise newException(PgTypeError, "NULL element in " & typeName & " array")
var s = newString(e.len)
if e.len > 0:
copyMem(addr s[0], addr row.data.buf[off + e.off], e.len)
result[i] = T(s)
result[i] = T(readString(row.data.buf, off + e.off, e.len))
return
let s = row.getStr(col)
let elems = parseTextArray(s)
Expand Down Expand Up @@ -1705,10 +1692,7 @@ proc getStrArrayElemOpt*(row: Row, col: int): seq[Option[string]] =
if e.len == -1:
result[i] = none(string)
else:
var s = newString(e.len)
if e.len > 0:
copyMem(addr s[0], addr row.data.buf[off + e.off], e.len)
result[i] = some(s)
result[i] = some(readString(row.data.buf, off + e.off, e.len))
return
let s = row.getStr(col)
result = parseTextArray(s)
Expand Down
20 changes: 14 additions & 6 deletions async_postgres/pg_types/decoding.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ import std/[options, strutils, tables, times, net]

import ./core

proc readString*(src: openArray[byte], off, len: int): string =
## Copy `len` bytes from src starting at off into a new string.
result = newString(len)
if len > 0:
copyMem(addr result[0], addr src[off], len)

proc readBytes*(src: openArray[byte], off, len: int): seq[byte] =
## Copy `len` bytes from src starting at off into a new seq[byte].
result = newSeq[byte](len)
if len > 0:
copyMem(addr result[0], addr src[off], len)

proc decodeHstoreBinary*(data: openArray[byte]): PgHstore =
## Decode PostgreSQL binary hstore format.
result = initTable[string, Option[string]]()
Expand All @@ -16,9 +28,7 @@ proc decodeHstoreBinary*(data: openArray[byte]): PgHstore =
pos += 4
if keyLen < 0 or pos + keyLen > data.len:
raise newException(PgTypeError, "hstore binary: truncated key data")
var key = newString(keyLen)
if keyLen > 0:
copyMem(addr key[0], addr data[pos], keyLen)
let key = readString(data, pos, keyLen)
pos += keyLen
if pos + 4 > data.len:
raise newException(PgTypeError, "hstore binary: truncated value length")
Expand All @@ -29,9 +39,7 @@ proc decodeHstoreBinary*(data: openArray[byte]): PgHstore =
else:
if valLen < 0 or pos + valLen > data.len:
raise newException(PgTypeError, "hstore binary: truncated value data")
var val = newString(valLen)
if valLen > 0:
copyMem(addr val[0], addr data[pos], valLen)
let val = readString(data, pos, valLen)
pos += valLen
result[key] = some(val)

Expand Down
19 changes: 4 additions & 15 deletions async_postgres/pg_types/user_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,7 @@ proc getEnumArray*[T: enum](row: Row, col: int): seq[T] =
for i, e in decoded.elements:
if e.len == -1:
raise newException(PgTypeError, "NULL element in enum array")
var s = newString(e.len)
if e.len > 0:
copyMem(addr s[0], addr row.data.buf[off + e.off], e.len)
result[i] = parseEnum[T](s)
result[i] = parseEnum[T](readString(row.data.buf, off + e.off, e.len))
return
let s = row.getStr(col)
for e in parseTextArray(s):
Expand All @@ -183,10 +180,7 @@ proc getEnumArrayElemOpt*[T: enum](row: Row, col: int): seq[Option[T]] =
if e.len == -1:
result[i] = none(T)
else:
var s = newString(e.len)
if e.len > 0:
copyMem(addr s[0], addr row.data.buf[off + e.off], e.len)
result[i] = some(parseEnum[T](s))
result[i] = some(parseEnum[T](readString(row.data.buf, off + e.off, e.len)))
return
let s = row.getStr(col)
for e in parseTextArray(s):
Expand Down Expand Up @@ -357,9 +351,7 @@ proc compositeFieldFromText[T](s: string): T =

template decodeBinaryField(val, buf: untyped, fOff, fEnd, fLen: int) =
when typeof(val) is string:
val = newString(fLen)
if fLen > 0:
copyMem(addr val[0], addr buf[fOff], fLen)
val = readString(buf, fOff, fLen)
elif typeof(val) is int16:
val = fromBE16(buf.toOpenArray(fOff, fEnd))
elif typeof(val) is int32:
Expand All @@ -373,10 +365,7 @@ template decodeBinaryField(val, buf: untyped, fOff, fEnd, fLen: int) =
elif typeof(val) is bool:
val = buf[fOff] != 0
else:
var s = newString(fLen)
if fLen > 0:
copyMem(addr s[0], addr buf[fOff], fLen)
val = compositeFieldFromText[typeof(val)](s)
val = compositeFieldFromText[typeof(val)](readString(buf, fOff, fLen))

proc getComposite*[T: object](row: Row, col: int): T =
## Read a PostgreSQL composite column as a Nim object. Handles binary format.
Expand Down