@@ -1491,12 +1491,30 @@ pgsql_drop_replication_slot(PGSQL *pgsql, const char *slotName)
14911491 * We return how many parameters we filled in paramTypes and paramValues from
14921492 * the nodeArray.
14931493 */
1494- static int
1494+ #define NODEID_MAX_LENGTH 20 /* should allow for bigint digits */
1495+
1496+ typedef struct nodesArraysValuesParams
1497+ {
1498+ int count ;
1499+ Oid types [NODE_ARRAY_MAX_COUNT * 2 ];
1500+ char * values [NODE_ARRAY_MAX_COUNT * 2 ];
1501+
1502+ /*
1503+ * Pre-allocate arrays for the data separately from the values array, which
1504+ * needs to be a (const char **) thing rather than a (char [][]) thing,
1505+ * because of the pgsql_execute_with_params and libpq APIs.
1506+ */
1507+ char nodeIds [NODE_ARRAY_MAX_COUNT ][NODEID_MAX_LENGTH ];
1508+ char lsns [NODE_ARRAY_MAX_COUNT ][PG_LSN_MAXLENGTH ];
1509+ } nodesArraysValuesParams ;
1510+
1511+
1512+ static bool
14951513BuildNodesArrayValues (NodeAddressArray * nodeArray ,
1496- Oid * paramTypes , char * * paramValues ,
1514+ nodesArraysValuesParams * sqlParams ,
14971515 char * values , int size )
14981516{
1499- char buffer [BUFSIZE ];
1517+ char buffer [BUFSIZE ] = { 0 } ;
15001518 int nodeIndex = 0 ;
15011519 int paramIndex = 0 ;
15021520 int valuesIndex = 0 ;
@@ -1509,16 +1527,22 @@ BuildNodesArrayValues(NodeAddressArray *nodeArray,
15091527 for (nodeIndex = 0 ; nodeIndex < nodeArray -> count ; nodeIndex ++ )
15101528 {
15111529 NodeAddress * node = & (nodeArray -> nodes [nodeIndex ]);
1512- IntString nodeIdString = intToString (node -> nodeId );
1530+ char * nodeIdString = intToString (node -> nodeId ). strValue ;
15131531
15141532 int idParamIndex = paramIndex ;
15151533 int lsnParamIndex = paramIndex + 1 ;
15161534
1517- paramTypes [idParamIndex ] = INT4OID ;
1518- paramValues [idParamIndex ] = strdup (nodeIdString .strValue );
1535+ sqlParams -> types [idParamIndex ] = INT4OID ;
1536+ strlcpy (sqlParams -> nodeIds [nodeIndex ], nodeIdString , NODEID_MAX_LENGTH );
1537+
1538+ /* store the (char *) pointer to the data in values */
1539+ sqlParams -> values [idParamIndex ] = sqlParams -> nodeIds [nodeIndex ];
15191540
1520- paramTypes [lsnParamIndex ] = LSNOID ;
1521- paramValues [lsnParamIndex ] = node -> lsn ;
1541+ sqlParams -> types [lsnParamIndex ] = LSNOID ;
1542+ strlcpy (sqlParams -> lsns [nodeIndex ], node -> lsn , PG_LSN_MAXLENGTH );
1543+
1544+ /* store the (char *) pointer to the data in values */
1545+ sqlParams -> values [lsnParamIndex ] = sqlParams -> lsns [nodeIndex ];
15221546
15231547 valuesIndex += sformat (buffer + valuesIndex , BUFSIZE - valuesIndex ,
15241548 "%s($%d, $%d%s)" ,
@@ -1542,6 +1566,9 @@ BuildNodesArrayValues(NodeAddressArray *nodeArray,
15421566 paramIndex += 2 ;
15431567 }
15441568
1569+ /* count how many parameters where appended to the VALUES() parts */
1570+ sqlParams -> count = paramIndex ;
1571+
15451572 /* when we didn't find any node to process, return our empty set */
15461573 if (paramIndex == 0 )
15471574 {
@@ -1563,7 +1590,8 @@ BuildNodesArrayValues(NodeAddressArray *nodeArray,
15631590 return false;
15641591 }
15651592 }
1566- return paramIndex ;
1593+
1594+ return true;
15671595}
15681596
15691597
@@ -1615,13 +1643,14 @@ pgsql_replication_slot_create_and_drop(PGSQL *pgsql, NodeAddressArray *nodeArray
16151643 "SELECT 'drop', slot_name, NULL::pg_lsn FROM dropped" ;
16161644 /* *INDENT-ON* */
16171645
1618- Oid paramTypes [NODE_ARRAY_MAX_COUNT * 2 ] = { 0 };
1619- const char * paramValues [NODE_ARRAY_MAX_COUNT * 2 ] = { 0 };
1646+ nodesArraysValuesParams sqlParams = { 0 };
16201647 ReplicationSlotMaintainContext context = { 0 };
16211648
1622- int paramCount = BuildNodesArrayValues (nodeArray ,
1623- paramTypes , (char * * ) paramValues ,
1624- values , BUFSIZE );
1649+ if (!BuildNodesArrayValues (nodeArray , & sqlParams , values , BUFSIZE ))
1650+ {
1651+ /* errors have already been logged */
1652+ return false;
1653+ }
16251654
16261655 /* add the computed ($1,$2), ... string to the query "template" */
16271656 int bytes = sformat (sql , 2 * BUFSIZE , sqlTemplate , values );
@@ -1635,7 +1664,9 @@ pgsql_replication_slot_create_and_drop(PGSQL *pgsql, NodeAddressArray *nodeArray
16351664 }
16361665
16371666 return pgsql_execute_with_params (pgsql , sql ,
1638- paramCount , paramTypes , paramValues ,
1667+ sqlParams .count ,
1668+ sqlParams .types ,
1669+ (const char * * ) sqlParams .values ,
16391670 & context ,
16401671 parseReplicationSlotMaintain );
16411672}
@@ -1686,13 +1717,14 @@ pgsql_replication_slot_maintain(PGSQL *pgsql, NodeAddressArray *nodeArray)
16861717 "SELECT 'advance', slot_name, end_lsn FROM advanced " ;
16871718 /* *INDENT-ON* */
16881719
1689- Oid paramTypes [NODE_ARRAY_MAX_COUNT * 2 ] = { 0 };
1690- const char * paramValues [NODE_ARRAY_MAX_COUNT * 2 ] = { 0 };
1720+ nodesArraysValuesParams sqlParams = { 0 };
16911721 ReplicationSlotMaintainContext context = { 0 };
16921722
1693- int paramCount = BuildNodesArrayValues (nodeArray ,
1694- paramTypes , (char * * ) paramValues ,
1695- values , BUFSIZE );
1723+ if (!BuildNodesArrayValues (nodeArray , & sqlParams , values , BUFSIZE ))
1724+ {
1725+ /* errors have already been logged */
1726+ return false;
1727+ }
16961728
16971729 /* add the computed ($1,$2), ... string to the query "template" */
16981730 int bytes = sformat (sql , 2 * BUFSIZE , sqlTemplate , values );
@@ -1706,7 +1738,9 @@ pgsql_replication_slot_maintain(PGSQL *pgsql, NodeAddressArray *nodeArray)
17061738 }
17071739
17081740 return pgsql_execute_with_params (pgsql , sql ,
1709- paramCount , paramTypes , paramValues ,
1741+ sqlParams .count ,
1742+ sqlParams .types ,
1743+ (const char * * ) sqlParams .values ,
17101744 & context ,
17111745 parseReplicationSlotMaintain );
17121746}
0 commit comments