class_docstr: Renders an SQL plan following ANSI SQL.
class_docstr_tok: ["Renders","an","SQL","plan","following","ANSI","SQL","."]
docstr: Convert the join descriptions into a "JOIN" section.
  
  e.g.
  JOIN (
    SELECT...
  ) right
  ON
    left.ds = right.ds
  
  Returns a tuple of the "JOIN" section as a string and the associated execution parameters.
docstr_tok: ["Convert","the","join","descriptions","into","a","``","JOIN","''","section",".","e.g",".","JOIN","(","SELECT","...",")","right","ON","left.ds","=","right.ds","Returns","a","tuple","of","the","``","JOIN","''","section","as","a","string","and","the","associated","execution","parameters","."]
code: def _render_joins_section(
      self, join_descriptions: Sequence[SqlJoinDescription]
  ) -> Tuple[str, SqlBindParameters]:
      """Convert the join descriptions into a "JOIN" section.
  
      e.g.
      JOIN (
        SELECT...
      ) right
      ON
        left.ds = right.ds
  
      Returns a tuple of the "JOIN" section as a string and the associated execution parameters.
      """
      params = SqlBindParameters()
      join_section_lines = []
      for join_description in join_descriptions:
          # Render the source for the join
          right_source_rendered = self._render_node(
              join_description.right_source
          )
          params = params.combine(right_source_rendered.bind_parameters)
  
          # Render the on condition for the join
          on_condition_rendered: Optional[
              SqlExpressionRenderResult
          ] = None
          if join_description.on_condition:
              on_condition_rendered = (
                  self.EXPR_RENDERER.render_sql_expr(
                      join_description.on_condition
                  )
              )
              params = params.combine(
                  on_condition_rendered.bind_parameters
              )
  
          if join_description.right_source.is_table:
              join_section_lines.append(
                  join_description.join_type.value
              )
              join_section_lines.append(
                  textwrap.indent(
                      f"{right_source_rendered.sql} {join_description.right_source_alias}",
                      prefix=self.INDENT,
                  )
              )
          else:
              join_section_lines.append(
                  f"{join_description.join_type.value} ("
              )
              join_section_lines.append(
                  textwrap.indent(
                      right_source_rendered.sql, prefix=self.INDENT
                  )
              )
              join_section_lines.append(
                  f") {join_description.right_source_alias}"
              )
  
          if on_condition_rendered:
              join_section_lines.append("ON")
              join_section_lines.append(
                  textwrap.indent(
                      on_condition_rendered.sql, prefix=self.INDENT
                  )
              )
  
      return "\n".join(join_section_lines), params
  
imports: from __future__ import annotations
  import logging
  import textwrap
  from abc import ABC, abstractmethod
  from dataclasses import dataclass
  from typing import List, Optional, Sequence, Tuple
  from metricflow.sql.render.expr_renderer import DefaultSqlExpressionRenderer, SqlExpressionRenderer, SqlExpressionRenderResult
  from metricflow.sql.sql_bind_parameters import SqlBindParameters
  from metricflow.sql.sql_plan import SqlJoinDescription, SqlQueryPlan, SqlQueryPlanNode, SqlQueryPlanNodeVisitor, SqlSelectColumn, SqlSelectQueryFromClauseNode, SqlSelectStatementNode, SqlTableFromClauseNode
label_desc: Use image node_id 3 for calling the DefaultSqlQueryPlanRenderer obj's underlying member method code with example usage: obj._render_joins_section(join_descriptions) and returns: str,  params