Skip to content

Commit 03a91ed

Browse files
authored
chore: remove sql.unsafe usages (#2001)
* chore: remove sql.unsafe usages * chore: remove sql.unsafe usages
1 parent b1d6be9 commit 03a91ed

File tree

2 files changed

+45
-58
lines changed

2 files changed

+45
-58
lines changed

src/datastore/helpers.ts

+4-15
Original file line numberDiff line numberDiff line change
@@ -273,29 +273,18 @@ export function prefixedCols(columns: string[], prefix: string): string[] {
273273
return columns.map(c => `${prefix}.${c}`);
274274
}
275275

276-
/**
277-
* Concatenates column names to use on a query. Necessary when one or more of those columns is complex enough
278-
* so that postgres.js can't figure out how to list it (e.g. abi column, aggregates, partitions, etc.).
279-
* @param sql - SQL client
280-
* @param columns - list of columns
281-
* @returns raw SQL column list string
282-
*/
283-
export function unsafeCols(sql: PgSqlClient, columns: string[]): postgres.PendingQuery<any> {
284-
return sql.unsafe(columns.join(', '));
285-
}
286-
287276
/**
288277
* Shorthand function that returns a column query to retrieve the smart contract abi when querying transactions
289278
* that may be of type `contract_call`. Usually used alongside `TX_COLUMNS` or `MEMPOOL_TX_COLUMNS`.
290279
* @param tableName - Name of the table that will determine the transaction type. Defaults to `txs`.
291280
* @returns `string` - abi column select statement portion
292281
*/
293-
export function abiColumn(tableName: string = 'txs'): string {
294-
return `
295-
CASE WHEN ${tableName}.type_id = ${DbTxTypeId.ContractCall} THEN (
282+
export function abiColumn(sql: PgSqlClient, tableName: string = 'txs'): postgres.Fragment {
283+
return sql`
284+
CASE WHEN ${sql(tableName)}.type_id = ${DbTxTypeId.ContractCall} THEN (
296285
SELECT abi
297286
FROM smart_contracts
298-
WHERE smart_contracts.contract_id = ${tableName}.contract_call_contract_id
287+
WHERE smart_contracts.contract_id = ${sql(tableName)}.contract_call_contract_id
299288
ORDER BY abi != 'null' DESC, canonical DESC, microblock_canonical DESC, block_height DESC
300289
LIMIT 1
301290
) END as abi

src/datastore/pg-store.ts

+41-43
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ import {
8888
POX_SYNTHETIC_EVENT_COLUMNS,
8989
prefixedCols,
9090
TX_COLUMNS,
91-
unsafeCols,
9291
validateZonefileHash,
9392
} from './helpers';
9493
import { PgNotifier } from './pg-notifier';
@@ -240,7 +239,7 @@ export class PgStore extends BasePgStore {
240239
const microblock_tx_count: Record<string, number> = {};
241240
if (metadata?.txs) {
242241
const txQuery = await sql<ContractTxQueryResult[]>`
243-
SELECT ${unsafeCols(sql, [...TX_COLUMNS, abiColumn()])}
242+
SELECT ${sql(TX_COLUMNS)}, ${abiColumn(sql)}
244243
FROM txs
245244
WHERE index_block_hash = ${block.result.index_block_hash}
246245
AND canonical = true AND microblock_canonical = true
@@ -528,7 +527,7 @@ export class PgStore extends BasePgStore {
528527
throw new Error(`Could not find block by hash ${blockHash}`);
529528
}
530529
const result = await sql<ContractTxQueryResult[]>`
531-
SELECT ${unsafeCols(sql, [...TX_COLUMNS, abiColumn()])}
530+
SELECT ${sql(TX_COLUMNS)}, ${abiColumn(sql)}
532531
FROM txs
533532
WHERE index_block_hash = ${blockQuery.result.index_block_hash}
534533
AND canonical = true AND microblock_canonical = true
@@ -613,7 +612,7 @@ export class PgStore extends BasePgStore {
613612
const { block_height } = await this.getChainTip(sql);
614613
const unanchoredBlockHeight = block_height + 1;
615614
const query = await sql<ContractTxQueryResult[]>`
616-
SELECT ${unsafeCols(sql, [...TX_COLUMNS, abiColumn()])}
615+
SELECT ${sql(TX_COLUMNS)}, ${abiColumn(sql)}
617616
FROM txs
618617
WHERE canonical = true AND microblock_canonical = true AND block_height = ${unanchoredBlockHeight}
619618
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
@@ -823,7 +822,7 @@ export class PgStore extends BasePgStore {
823822
AND index_block_hash = ${blockQuery.result.index_block_hash}
824823
`;
825824
const result = await sql<ContractTxQueryResult[]>`
826-
SELECT ${unsafeCols(sql, [...TX_COLUMNS, abiColumn()])}
825+
SELECT ${sql(TX_COLUMNS)}, ${abiColumn(sql)}
827826
FROM txs
828827
WHERE canonical = true AND microblock_canonical = true
829828
AND index_block_hash = ${blockQuery.result.index_block_hash}
@@ -977,7 +976,7 @@ export class PgStore extends BasePgStore {
977976
}
978977
return await this.sqlTransaction(async sql => {
979978
const result = await sql<MempoolTxQueryResult[]>`
980-
SELECT ${unsafeCols(sql, [...MEMPOOL_TX_COLUMNS, abiColumn('mempool_txs')])}
979+
SELECT ${sql(MEMPOOL_TX_COLUMNS)}, ${abiColumn(sql, 'mempool_txs')}
981980
FROM mempool_txs
982981
WHERE tx_id IN ${sql(args.txIds)}
983982
`;
@@ -996,7 +995,7 @@ export class PgStore extends BasePgStore {
996995
}): Promise<FoundOrNot<DbMempoolTx>> {
997996
return await this.sqlTransaction(async sql => {
998997
const result = await sql<MempoolTxQueryResult[]>`
999-
SELECT ${unsafeCols(sql, [...MEMPOOL_TX_COLUMNS, abiColumn('mempool_txs')])}
998+
SELECT ${sql(MEMPOOL_TX_COLUMNS)}, ${abiColumn(sql, 'mempool_txs')}
1000999
FROM mempool_txs
10011000
WHERE tx_id = ${txId}
10021001
`;
@@ -1048,11 +1047,9 @@ export class PgStore extends BasePgStore {
10481047
DbTxStatus.DroppedProblematic,
10491048
];
10501049
const resultQuery = await sql<(MempoolTxQueryResult & { count: number })[]>`
1051-
SELECT ${unsafeCols(sql, [
1052-
...prefixedCols(MEMPOOL_TX_COLUMNS, 'mempool'),
1053-
abiColumn('mempool'),
1054-
'(COUNT(*) OVER())::INTEGER AS count',
1055-
])}
1050+
SELECT ${sql(prefixedCols(MEMPOOL_TX_COLUMNS, 'mempool'))},
1051+
${abiColumn(sql, 'mempool')},
1052+
(COUNT(*) OVER())::INTEGER AS count
10561053
FROM (
10571054
SELECT *
10581055
FROM mempool_txs
@@ -1323,7 +1320,7 @@ export class PgStore extends BasePgStore {
13231320
orderBy == 'fee' ? sql`fee_rate` : orderBy == 'size' ? sql`tx_size` : sql`receipt_time`;
13241321
const orderSql = order == 'asc' ? sql`ASC` : sql`DESC`;
13251322
const resultQuery = await sql<(MempoolTxQueryResult & { count: number })[]>`
1326-
SELECT ${unsafeCols(sql, [...MEMPOOL_TX_COLUMNS, abiColumn('mempool_txs')])}, ${count}
1323+
SELECT ${sql(MEMPOOL_TX_COLUMNS)}, ${abiColumn(sql, 'mempool_txs')}, ${count}
13271324
FROM mempool_txs
13281325
WHERE ${
13291326
address
@@ -1386,7 +1383,7 @@ export class PgStore extends BasePgStore {
13861383
return await this.sqlTransaction(async sql => {
13871384
const maxBlockHeight = await this.getMaxBlockHeight(sql, { includeUnanchored });
13881385
const result = await sql<ContractTxQueryResult[]>`
1389-
SELECT ${unsafeCols(sql, [...TX_COLUMNS, abiColumn()])}
1386+
SELECT ${sql(TX_COLUMNS)}, ${abiColumn(sql)}
13901387
FROM txs
13911388
WHERE tx_id = ${txId} AND block_height <= ${maxBlockHeight}
13921389
ORDER BY canonical DESC, microblock_canonical DESC, block_height DESC
@@ -1434,7 +1431,7 @@ export class PgStore extends BasePgStore {
14341431
FROM chain_tip
14351432
`;
14361433
resultQuery = await sql<ContractTxQueryResult[]>`
1437-
SELECT ${unsafeCols(sql, [...TX_COLUMNS, abiColumn()])}
1434+
SELECT ${sql(TX_COLUMNS)}, ${abiColumn(sql)}
14381435
FROM txs
14391436
WHERE canonical = true AND microblock_canonical = true AND block_height <= ${maxHeight}
14401437
ORDER BY block_height DESC, microblock_sequence DESC, tx_index DESC
@@ -1450,7 +1447,7 @@ export class PgStore extends BasePgStore {
14501447
AND type_id IN ${sql(txTypeIds)} AND block_height <= ${maxHeight}
14511448
`;
14521449
resultQuery = await sql<ContractTxQueryResult[]>`
1453-
SELECT ${unsafeCols(sql, [...TX_COLUMNS, abiColumn()])}
1450+
SELECT ${sql(TX_COLUMNS)}, ${abiColumn(sql)}
14541451
FROM txs
14551452
WHERE canonical = true AND microblock_canonical = true
14561453
AND type_id IN ${sql(txTypeIds)} AND block_height <= ${maxHeight}
@@ -1474,11 +1471,13 @@ export class PgStore extends BasePgStore {
14741471
}): Promise<{ results: DbEvent[] }> {
14751472
return await this.sqlTransaction(async sql => {
14761473
if (args.txs.length === 0) return { results: [] };
1477-
// TODO: This hack has to be done because postgres.js can't figure out how to interpolate
1478-
// these `bytea` VALUES comparisons yet.
1479-
const transactionValues = args.txs
1480-
.map(tx => `('\\x${tx.txId.slice(2)}'::bytea, '\\x${tx.indexBlockHash.slice(2)}'::bytea)`)
1481-
.join(', ');
1474+
1475+
const transactionValues = args.txs.map(tx => [
1476+
`\\x${tx.txId.slice(2)}`,
1477+
`\\x${tx.indexBlockHash.slice(2)}`,
1478+
]);
1479+
const txValuesSql = sql(transactionValues.map(tx => sql`(${tx[0]}::bytea, ${tx[1]}::bytea)`));
1480+
14821481
const eventIndexStart = args.offset;
14831482
const eventIndexEnd = args.offset + args.limit - 1;
14841483
const stxLockResults = await sql<
@@ -1497,7 +1496,7 @@ export class PgStore extends BasePgStore {
14971496
SELECT
14981497
event_index, tx_id, tx_index, block_height, canonical, locked_amount, unlock_height, locked_address, contract_name
14991498
FROM stx_lock_events
1500-
WHERE (tx_id, index_block_hash) IN (VALUES ${sql.unsafe(transactionValues)})
1499+
WHERE (tx_id, index_block_hash) IN ${txValuesSql}
15011500
AND microblock_canonical = true AND event_index BETWEEN ${eventIndexStart} AND ${eventIndexEnd}
15021501
`;
15031502
const stxResults = await sql<
@@ -1517,7 +1516,7 @@ export class PgStore extends BasePgStore {
15171516
SELECT
15181517
event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, amount, memo
15191518
FROM stx_events
1520-
WHERE (tx_id, index_block_hash) IN (VALUES ${sql.unsafe(transactionValues)})
1519+
WHERE (tx_id, index_block_hash) IN ${txValuesSql}
15211520
AND microblock_canonical = true AND event_index BETWEEN ${eventIndexStart} AND ${eventIndexEnd}
15221521
`;
15231522
const ftResults = await sql<
@@ -1537,7 +1536,7 @@ export class PgStore extends BasePgStore {
15371536
SELECT
15381537
event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, asset_identifier, amount
15391538
FROM ft_events
1540-
WHERE (tx_id, index_block_hash) IN (VALUES ${sql.unsafe(transactionValues)})
1539+
WHERE (tx_id, index_block_hash) IN ${txValuesSql}
15411540
AND microblock_canonical = true AND event_index BETWEEN ${eventIndexStart} AND ${eventIndexEnd}
15421541
`;
15431542
const nftResults = await sql<
@@ -1557,7 +1556,7 @@ export class PgStore extends BasePgStore {
15571556
SELECT
15581557
event_index, tx_id, tx_index, block_height, canonical, asset_event_type_id, sender, recipient, asset_identifier, value
15591558
FROM nft_events
1560-
WHERE (tx_id, index_block_hash) = ANY(VALUES ${sql.unsafe(transactionValues)})
1559+
WHERE (tx_id, index_block_hash) IN ${txValuesSql}
15611560
AND microblock_canonical = true AND event_index BETWEEN ${eventIndexStart} AND ${eventIndexEnd}
15621561
`;
15631562
const logResults = await sql<
@@ -1575,7 +1574,7 @@ export class PgStore extends BasePgStore {
15751574
SELECT
15761575
event_index, tx_id, tx_index, block_height, canonical, contract_identifier, topic, value
15771576
FROM contract_logs
1578-
WHERE (tx_id, index_block_hash) IN (VALUES ${sql.unsafe(transactionValues)})
1577+
WHERE (tx_id, index_block_hash) IN ${txValuesSql}
15791578
AND microblock_canonical = true AND event_index BETWEEN ${eventIndexStart} AND ${eventIndexEnd}
15801579
`;
15811580
return {
@@ -2745,7 +2744,9 @@ export class PgStore extends BasePgStore {
27452744
LIMIT ${args.limit}
27462745
OFFSET ${args.offset}
27472746
)
2748-
SELECT ${unsafeCols(this.sql, [...TX_COLUMNS, abiColumn(), 'count'])}
2747+
SELECT ${this.sql(TX_COLUMNS)},
2748+
${abiColumn(this.sql)},
2749+
count
27492750
FROM stx_txs
27502751
INNER JOIN txs USING (tx_id, index_block_hash, microblock_hash)
27512752
`;
@@ -2814,7 +2815,7 @@ export class PgStore extends BasePgStore {
28142815
events.sender as event_sender,
28152816
events.recipient as event_recipient,
28162817
events.memo as event_memo,
2817-
${this.sql.unsafe(abiColumn('transactions'))}
2818+
${abiColumn(this.sql, 'transactions')}
28182819
FROM transactions
28192820
LEFT JOIN events ON transactions.tx_id = events.tx_id
28202821
AND transactions.tx_id = ${tx_id}
@@ -2914,7 +2915,7 @@ export class PgStore extends BasePgStore {
29142915
)
29152916
SELECT
29162917
transactions.*,
2917-
${this.sql.unsafe(abiColumn('transactions'))},
2918+
${abiColumn(this.sql, 'transactions')},
29182919
events.event_index as event_index,
29192920
events.event_type_id as event_type,
29202921
events.amount as event_amount,
@@ -3039,7 +3040,7 @@ export class PgStore extends BasePgStore {
30393040
// TODO(mb): add support for searching for microblock by hash
30403041
return await this.sqlTransaction(async sql => {
30413042
const txQuery = await sql<ContractTxQueryResult[]>`
3042-
SELECT ${unsafeCols(sql, [...TX_COLUMNS, abiColumn()])}
3043+
SELECT ${sql(TX_COLUMNS)}, ${abiColumn(sql)}
30433044
FROM txs WHERE tx_id = ${hash} LIMIT 1
30443045
`;
30453046
if (txQuery.length > 0) {
@@ -3054,7 +3055,7 @@ export class PgStore extends BasePgStore {
30543055
};
30553056
}
30563057
const txMempoolQuery = await sql<MempoolTxQueryResult[]>`
3057-
SELECT ${unsafeCols(sql, [...MEMPOOL_TX_COLUMNS, abiColumn('mempool_txs')])}
3058+
SELECT ${sql(MEMPOOL_TX_COLUMNS)}, ${abiColumn(sql, 'mempool_txs')}
30583059
FROM mempool_txs WHERE pruned = false AND tx_id = ${hash} LIMIT 1
30593060
`;
30603061
if (txMempoolQuery.length > 0) {
@@ -3099,7 +3100,7 @@ export class PgStore extends BasePgStore {
30993100
return await this.sqlTransaction(async sql => {
31003101
if (isContract) {
31013102
const contractMempoolTxResult = await sql<MempoolTxQueryResult[]>`
3102-
SELECT ${unsafeCols(sql, [...MEMPOOL_TX_COLUMNS, abiColumn('mempool_txs')])}
3103+
SELECT ${sql(MEMPOOL_TX_COLUMNS)}, ${abiColumn(sql, 'mempool_txs')}
31033104
FROM mempool_txs WHERE pruned = false AND smart_contract_contract_id = ${principal} LIMIT 1
31043105
`;
31053106
if (contractMempoolTxResult.length > 0) {
@@ -3114,7 +3115,7 @@ export class PgStore extends BasePgStore {
31143115
};
31153116
}
31163117
const contractTxResult = await sql<ContractTxQueryResult[]>`
3117-
SELECT ${unsafeCols(sql, [...TX_COLUMNS, abiColumn()])}
3118+
SELECT ${sql(TX_COLUMNS)}, ${abiColumn(sql)}
31183119
FROM txs
31193120
WHERE smart_contract_contract_id = ${principal}
31203121
ORDER BY canonical DESC, microblock_canonical DESC, block_height DESC
@@ -3259,13 +3260,12 @@ export class PgStore extends BasePgStore {
32593260
${
32603261
args.includeTxMetadata
32613262
? this.sql`
3262-
SELECT ${unsafeCols(this.sql, [
3263+
SELECT ${this.sql([
32633264
'nft.asset_identifier',
32643265
'nft.value',
32653266
...prefixedCols(TX_COLUMNS, 'txs'),
3266-
abiColumn(),
32673267
'nft.count',
3268-
])}
3268+
])}, ${abiColumn(this.sql)}
32693269
FROM nft
32703270
INNER JOIN txs USING (tx_id)
32713271
WHERE txs.canonical = TRUE AND txs.microblock_canonical = TRUE
@@ -3301,16 +3301,15 @@ export class PgStore extends BasePgStore {
33013301
includeTxMetadata: boolean;
33023302
}): Promise<{ results: NftEventWithTxMetadata[]; total: number }> {
33033303
const columns = args.includeTxMetadata
3304-
? unsafeCols(this.sql, [
3304+
? this.sql`${this.sql([
33053305
'asset_identifier',
33063306
'value',
33073307
'event_index',
33083308
'asset_event_type_id',
33093309
'sender',
33103310
'recipient',
33113311
...prefixedCols(TX_COLUMNS, 'txs'),
3312-
abiColumn(),
3313-
])
3312+
])}, ${abiColumn(this.sql)}`
33143313
: this.sql`nft.*`;
33153314
const nftTxResults = await this.sql<(DbNftEvent & ContractTxQueryResult & { count: number })[]>`
33163315
SELECT ${columns}, (COUNT(*) OVER())::INTEGER AS count
@@ -3362,16 +3361,15 @@ export class PgStore extends BasePgStore {
33623361
includeTxMetadata: boolean;
33633362
}): Promise<{ results: NftEventWithTxMetadata[]; total: number }> {
33643363
const columns = args.includeTxMetadata
3365-
? unsafeCols(this.sql, [
3364+
? this.sql`${this.sql([
33663365
'asset_identifier',
33673366
'value',
33683367
'event_index',
33693368
'asset_event_type_id',
33703369
'sender',
33713370
'recipient',
33723371
...prefixedCols(TX_COLUMNS, 'txs'),
3373-
abiColumn(),
3374-
])
3372+
])}, ${abiColumn(this.sql)}`
33753373
: this.sql`nft.*`;
33763374
const nftTxResults = await this.sql<(DbNftEvent & ContractTxQueryResult & { count: number })[]>`
33773375
SELECT ${columns}, (COUNT(*) OVER())::INTEGER AS count
@@ -3442,7 +3440,7 @@ export class PgStore extends BasePgStore {
34423440
return await this.sqlTransaction(async sql => {
34433441
const maxBlockHeight = await this.getMaxBlockHeight(sql, { includeUnanchored });
34443442
const result = await sql<ContractTxQueryResult[]>`
3445-
SELECT ${unsafeCols(sql, [...TX_COLUMNS, abiColumn()])}
3443+
SELECT ${sql(TX_COLUMNS)}, ${abiColumn(sql)}
34463444
FROM txs
34473445
WHERE tx_id IN ${sql(txIds)}
34483446
AND block_height <= ${maxBlockHeight}

0 commit comments

Comments
 (0)