make implicit cstring conversions explicit (#19488)

The Nim manual says that an implicit conversion to cstring will
eventually not be allowed [1]:

    A Nim `string` is implicitly convertible to `cstring` for convenience.

    [...]

    Even though the conversion is implicit, it is not *safe*: The garbage collector
    does not consider a `cstring` to be a root and may collect the underlying
    memory. For this reason, the implicit conversion will be removed in future
    releases of the Nim compiler. Certain idioms like conversion of a `const` string
    to `cstring` are safe and will remain to be allowed.

And from Nim 1.6.0, such a conversion triggers a warning [2]:

    A dangerous implicit conversion to `cstring` now triggers a `[CStringConv]` warning.
    This warning will become an error in future versions! Use an explicit conversion
    like `cstring(x)` in order to silence the warning.

However, some files in this repo produced such a warning. For example,
before this commit, compiling `parsejson.nim` would produce:

    /foo/Nim/lib/pure/parsejson.nim(221, 37) Warning: implicit conversion to 'cstring' from a non-const location: my.buf; this will become a compile time error in the future [CStringConv]
    /foo/Nim/lib/pure/parsejson.nim(231, 39) Warning: implicit conversion to 'cstring' from a non-const location: my.buf; this will become a compile time error in the future [CStringConv]

This commit resolves the most visible `CStringConv` warnings, making the
cstring conversions explicit.

[1] d2318d9ccf/doc/manual.md (cstring-type)
[2] d2318d9ccf/changelogs/changelog_1_6_0.md (type-system)
This commit is contained in:
ee7 2022-08-19 21:40:53 +02:00 • committed by GitHub
commit e8657c7107
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 63 additions and 63 deletions

View file

@ -149,17 +149,17 @@ proc tryExec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]): bool {.
tags: [ReadDbEffect, WriteDbEffect].} =
## tries to execute the query and returns true if successful, false otherwise.
var q = dbFormat(query, args)
return mysql.real_query(PMySQL db, q, q.len) == 0'i32
return mysql.real_query(PMySQL db, q.cstring, q.len) == 0'i32
proc rawExec(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) =
var q = dbFormat(query, args)
if mysql.real_query(PMySQL db, q, q.len) != 0'i32: dbError(db)
if mysql.real_query(PMySQL db, q.cstring, q.len) != 0'i32: dbError(db)
proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {.
tags: [ReadDbEffect, WriteDbEffect].} =
## executes the query and raises EDB if not successful.
var q = dbFormat(query, args)
if mysql.real_query(PMySQL db, q, q.len) != 0'i32: dbError(db)
if mysql.real_query(PMySQL db, q.cstring, q.len) != 0'i32: dbError(db)
proc newRow(L: int): Row =
newSeq(result, L)
@ -360,7 +360,7 @@ proc tryInsertId*(db: DbConn, query: SqlQuery,
## executes the query (typically "INSERT") and returns the
## generated ID for the row or -1 in case of an error.
var q = dbFormat(query, args)
if mysql.real_query(PMySQL db, q, q.len) != 0'i32:
if mysql.real_query(PMySQL db, q.cstring, q.len) != 0'i32:
result = -1'i64
else:
result = mysql.insertId(PMySQL db)
@ -409,7 +409,7 @@ proc open*(connection, user, password, database: string): DbConn {.
else: substr(connection, 0, colonPos-1)
port: int32 = if colonPos < 0: 0'i32
else: substr(connection, colonPos+1).parseInt.int32
if mysql.realConnect(res, host, user, password, database,
if mysql.realConnect(res, host.cstring, user, password, database,
port, nil, 0) == nil:
var errmsg = $mysql.error(res)
mysql.close(res)

View file

@ -334,7 +334,7 @@ proc `[]`*(row: InstantRow, col: int): string {.inline.} =
proc unsafeColumnAt*(row: InstantRow, index: int): cstring {.inline.} =
## Return cstring of given column of the row
row.row[index]
row.row[index].cstring
proc len*(row: InstantRow): int {.inline.} =
## Returns number of columns in the row

View file

@ -133,7 +133,7 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
proc tryExec*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): bool {.tags: [ReadDbEffect, WriteDbEffect].} =
## tries to execute the query and returns true if successful, false otherwise.
var res = pqexecParams(db, dbFormat(query, args), 0, nil, nil,
var res = pqexecParams(db, dbFormat(query, args).cstring, 0, nil, nil,
nil, nil, 0)
result = pqresultStatus(res) == PGRES_COMMAND_OK
pqclear(res)
@ -143,7 +143,7 @@ proc tryExec*(db: DbConn, stmtName: SqlPrepared,
ReadDbEffect, WriteDbEffect].} =
## tries to execute the query and returns true if successful, false otherwise.
var arr = allocCStringArray(args)
var res = pqexecPrepared(db, stmtName.string, int32(args.len), arr,
var res = pqexecPrepared(db, stmtName.cstring, int32(args.len), arr,
nil, nil, 0)
deallocCStringArray(arr)
result = pqresultStatus(res) == PGRES_COMMAND_OK
@ -152,7 +152,7 @@ proc tryExec*(db: DbConn, stmtName: SqlPrepared,
proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {.
tags: [ReadDbEffect, WriteDbEffect].} =
## executes the query and raises EDB if not successful.
var res = pqexecParams(db, dbFormat(query, args), 0, nil, nil,
var res = pqexecParams(db, dbFormat(query, args).cstring, 0, nil, nil,
nil, nil, 0)
if pqresultStatus(res) != PGRES_COMMAND_OK: dbError(db)
pqclear(res)
@ -160,7 +160,7 @@ proc exec*(db: DbConn, query: SqlQuery, args: varargs[string, `$`]) {.
proc exec*(db: DbConn, stmtName: SqlPrepared,
args: varargs[string]) {.tags: [ReadDbEffect, WriteDbEffect].} =
var arr = allocCStringArray(args)
var res = pqexecPrepared(db, stmtName.string, int32(args.len), arr,
var res = pqexecPrepared(db, stmtName.cstring, int32(args.len), arr,
nil, nil, 0)
deallocCStringArray(arr)
if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
@ -172,20 +172,20 @@ proc newRow(L: int): Row =
proc setupQuery(db: DbConn, query: SqlQuery,
args: varargs[string]): PPGresult =
result = pqexec(db, dbFormat(query, args))
result = pqexec(db, dbFormat(query, args).cstring)
if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db)
proc setupQuery(db: DbConn, stmtName: SqlPrepared,
args: varargs[string]): PPGresult =
var arr = allocCStringArray(args)
result = pqexecPrepared(db, stmtName.string, int32(args.len), arr,
result = pqexecPrepared(db, stmtName.cstring, int32(args.len), arr,
nil, nil, 0)
deallocCStringArray(arr)
if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db)
proc setupSingeRowQuery(db: DbConn, query: SqlQuery,
args: varargs[string]) =
if pqsendquery(db, dbFormat(query, args)) != 1:
if pqsendquery(db, dbFormat(query, args).cstring) != 1:
dbError(db)
if pqSetSingleRowMode(db) != 1:
dbError(db)
@ -193,7 +193,7 @@ proc setupSingeRowQuery(db: DbConn, query: SqlQuery,
proc setupSingeRowQuery(db: DbConn, stmtName: SqlPrepared,
args: varargs[string]) =
var arr = allocCStringArray(args)
if pqsendqueryprepared(db, stmtName.string, int32(args.len), arr, nil, nil, 0) != 1:
if pqsendqueryprepared(db, stmtName.cstring, int32(args.len), arr, nil, nil, 0) != 1:
dbError(db)
if pqSetSingleRowMode(db) != 1:
dbError(db)
@ -205,7 +205,7 @@ proc prepare*(db: DbConn; stmtName: string, query: SqlQuery;
## via `$1`, `$2`, `$3`, etc.
if nParams > 0 and not string(query).contains("$1"):
dbError("parameter substitution expects \"$1\"")
var res = pqprepare(db, stmtName, query.string, int32(nParams), nil)
var res = pqprepare(db, stmtName, query.cstring, int32(nParams), nil)
if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
return SqlPrepared(stmtName)
@ -590,7 +590,7 @@ proc execAffectedRows*(db: DbConn, query: SqlQuery,
## executes the query (typically "UPDATE") and returns the
## number of affected rows.
var q = dbFormat(query, args)
var res = pqExec(db, q)
var res = pqExec(db, q.cstring)
if pqresultStatus(res) != PGRES_COMMAND_OK: dbError(db)
result = parseBiggestInt($pqcmdTuples(res))
pqclear(res)
@ -601,7 +601,7 @@ proc execAffectedRows*(db: DbConn, stmtName: SqlPrepared,
## executes the query (typically "UPDATE") and returns the
## number of affected rows.
var arr = allocCStringArray(args)
var res = pqexecPrepared(db, stmtName.string, int32(args.len), arr,
var res = pqexecPrepared(db, stmtName.cstring, int32(args.len), arr,
nil, nil, 0)
deallocCStringArray(arr)
if pqresultStatus(res) != PGRES_COMMAND_OK: dbError(db)
@ -634,7 +634,7 @@ proc open*(connection, user, password, database: string): DbConn {.
else: substr(connection, 0, colonPos-1)
port = if colonPos < 0: ""
else: substr(connection, colonPos+1)
result = pqsetdbLogin(host, port, nil, nil, database, user, password)
result = pqsetdbLogin(host.cstring, port.cstring, nil, nil, database, user, password)
if pqStatus(result) != CONNECTION_OK: dbError(result) # result = nil
proc setEncoding*(connection: DbConn, encoding: string): bool {.

View file

@ -235,7 +235,7 @@ proc tryExec*(db: DbConn, query: SqlQuery,
assert(not db.isNil, "Database not connected.")
var q = dbFormat(query, args)
var stmt: sqlite3.PStmt
if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK:
if prepare_v2(db, q.cstring, q.len.cint, stmt, nil) == SQLITE_OK:
let x = step(stmt)
if x in {SQLITE_DONE, SQLITE_ROW}:
result = finalize(stmt) == SQLITE_OK
@ -278,7 +278,7 @@ proc setupQuery(db: DbConn, query: SqlQuery,
args: varargs[string]): PStmt =
assert(not db.isNil, "Database not connected.")
var q = dbFormat(query, args)
if prepare_v2(db, q, q.len.cint, result, nil) != SQLITE_OK: dbError(db)
if prepare_v2(db, q.cstring, q.len.cint, result, nil) != SQLITE_OK: dbError(db)
proc setupQuery(db: DbConn, stmtName: SqlPrepared): SqlPrepared {.since: (1, 3).} =
assert(not db.isNil, "Database not connected.")
@ -653,7 +653,7 @@ proc tryInsertID*(db: DbConn, query: SqlQuery,
var q = dbFormat(query, args)
var stmt: sqlite3.PStmt
result = -1
if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK:
if prepare_v2(db, q.cstring, q.len.cint, stmt, nil) == SQLITE_OK:
if step(stmt) == SQLITE_DONE:
result = last_insert_rowid(db)
if finalize(stmt) != SQLITE_OK: