The prepared statement API allows supported SQL statements (see SQL Syntax Permitted in Prepared Statements) to be re-executed without incurring the cost of parsing and optimization each time.
        Prepared statements support parametrization. The question mark
        or interrogation point (?) is used as a
        parameter marker; parameters are updated (bound to values)
        beforehand, each time the statement is executed, using
        PreparedStatement.bind(). See
        the description of this method for more information.
      
        To free up resources taken up by parsed query and statement
        parameters, call
        PreparedStatement.deallocate(),
        which closes the prepared statement and frees its resources.
        Omitting deallocation does not produce an error but memory
        consumed during stored procedure execution is otherwise not
        freed until routine execution has finished. Once a prepared
        statement has been closed (deallocated), it is no longer
        available for execution.
      
Execution flow for prepared statements consists of the following steps:
Prepare statement (
prepare())Update parameters (
bind())Execute statement (
execute())Close statement (
deallocate())
Steps 2 and 3 can be repeated any number of times prior to closing the prepared statement.
        The JavaScript stored procedure jssp_prep1(),
        whown here, accepts an arbitrary SQL statement containing two
        parameter markers, prepares the statement, then executes it
        twice, binding different values to the parameters each time, and
        printing the result to stdout:
      
CREATE PROCEDURE jssp_prep1(IN query VARCHAR(200))
LANGUAGE JAVASCRIPT AS $$
  function print_result(result) {
    console.log(result.getColumnNames())
    let row = result.fetchOne()
    while(row) {
      console.log(row.toArray())
      row = result.fetchOne()
    }
  }
  function fetch_warnings(result) {
    console.log("Number of warnings: " + result.getWarningsCount())
    for (var w in result.getWarnings()) {
      console.log(w.level + ", " + w.code + ", " + w.message)
     }
  }
  let stmt = session.prepare(query)
  stmt.bind(3, 4)
  let res1 = stmt.execute()
  print_result(res1)
  fetch_warnings(res1)
  stmt.bind(2, 3)
  let res2 = stmt.execute()
  print_result(res2)
  fetch_warnings(res2)
  stmt.bind(5)
  let res3 = stmt.execute()
  print_result(res3)
  fetch_warnings(res3)
  stmt.deallocate()
$$;
        When finished with the prepared statement, we close it, freeing
        up any resources used in preparing and executing it, by calling
        deallocate().
      
        Calling
        bind() with
        fewer arguments than there are parameters in the statement is
        allowed after all parameters have been bound at least once. In
        this case, calling stmt.bind(5) after
        previously having called stmt.bind(2,3) is
        the same as calling stmt.bind(5,3)—the
        missing second value is reused from the previous invocation, as
        we can see here:
      
mysql> CALL jssp_prep1("
    ">   SELECT * 
    ">   FROM t1
    ">   WHERE c1 = ? OR c1 = ?
    "> ");
Query OK, 0 rows affected (0.03 sec)
mysql> SELECT mle_session_state("stdout")\G
*************************** 1. row ***************************
mle_session_state('stdout'): c1,c2,c3
3,37,peach
4,221,watermelon
Number of warnings: 0
c1,c2,c3
2,139,apple
3,37,peach
Number of warnings: 0
c1,c2,c3
3,37,peach
5,83,pear
Number of warnings: 0
1 row in set (0.00 sec)