docs: private void processQuery() throws SQLException {
  		if (preparedStatement != null) {
  			return;
  		}
  
  		if (query == null) {
  			throw new RuntimeException("Invalid NamedParameterStatement: no query!");
  		}
  
  		logger.debug("Orig Query: {}", query);
  		StringBuffer builder = new StringBuffer();
  
  		String queryByPlugin = query;
  		for (INpsPlugin plugin : plugins) {
  			queryByPlugin = plugin.process(queryByPlugin, params);
  			if (logger.isDebugEnabled()) {
  				logger.debug("Apply plugin: name=[{}] query=[{}] params={}",
  					plugin.getClass().getSimpleName(), queryByPlugin, params);
  			}
  		}
  
  		Matcher matcher = PARAM_PATTERN.matcher(queryByPlugin);
  		int noOfParams = 0;
  		while (matcher.find()) {
  			if (matcher.group(4) != null) {
  				noOfParams++;
  				String param = matcher.group("PARAM");
  				logger.debug("Param: {}", param);
  				if (!paramsPlacement.containsKey(param)) {
  					paramsPlacement.put(param, new ArrayList<>());
  				}
  				paramsPlacement.get(param).add(noOfParams);
  
  				Object paramValue = params.get(param);
  				StringBuilder paramReplacementBuilder = new StringBuilder("?");
  				if (paramValue != null && (paramValue instanceof Collection || paramValue.getClass().isArray())) {
  					int size = paramValue instanceof Collection ?
  						((Collection) paramValue).size() :
  						((Object[]) paramValue).length;
  					for (int i = 1; i < size; i++) {
  						paramReplacementBuilder.append(",?");
  					}
  				}
  				matcher.appendReplacement(builder, paramReplacementBuilder.toString());
  			}
  		}
  		matcher.appendTail(builder);
  		finalQuery = builder.toString();
  
  		logger.debug("Final SQL: {}", finalQuery);
  		logger.debug("Number of params: {}", noOfParams);
  
  		if (!ignoreExtraPassedParam) {
  			for (String param : params.keySet()) {
  				if (!paramsPlacement.containsKey(param)) {
  					throw new SQLException("Passed parameter not found: " + param);
  				}
  			}
  		}
  
  		preparedStatement = connection.prepareStatement(finalQuery);
  		if (fetchSize != null) {
  			preparedStatement.setFetchSize(fetchSize);
  		}
  
  		if (queryTimeout != null) {
  			preparedStatement.setQueryTimeout(queryTimeout);
  		}
  
  		if (maxRows != null) {
  			preparedStatement.setMaxRows(maxRows);
  		}
  
  		builder = new StringBuffer();
  		matcher = PARAM_Q_MARK_PATTERN.matcher(finalQuery);
  		int idx = 1;
  		while (matcher.find()) {
  			if (matcher.group("QMARK") != null) {
  				String replacement = String.format(" ?%s ", idx++);
  				matcher.appendReplacement(builder, replacement);
  			}
  		}
  		matcher.appendTail(builder);
  
  		finalIndexedQuery = builder.toString();
  	}