Context:
#!/usr/bin/python
# -*- coding: utf-8 -*-
#   ramaplot.AmberForceField.py
#
#   Copyright (C) 2015 Karl T Debiec
#   All rights reserved.
#
#   This software may be modified and distributed under the terms of the
#   BSD license. See the LICENSE file for details.
"""
Reads and represents AMBER-format force fields
"""
################################### MODULES ###################################
from __future__ import absolute_import,division,print_function,unicode_literals
import re
from .ForceField import ForceField
################################### CLASSES ###################################
class AmberForceField(ForceField):
    """
    Reads and represents AMBER-format force fields
    """

    @staticmethod
    def get_cache_key(parm=None, *args, **kwargs):
        """
        Generates tuple of arguments to be used as key for dataset
        cache.
        """
        from os.path import expandvars

        return (AmberForceField, expandvars(parm))

    @staticmethod
    def get_cache_message(cache_key):
        return "previously loaded from '{0}'".format(cache_key[1])

    par_re = dict(
      blank           = "^\s*$",
      mass            = "^(?P<type>{t}){w}"
                         "(?P<mass>{f})"
                         "(?P<polarizability>{w}{f}|{w})"
                         "(?P<note>.*$)",
      atomlist        = "^({t}{w})*$",
      bond            = "^(?P<type_1>{t})-"
                         "(?P<type_2>{t}){w}"
                         "(?P<force_constant>{f}){w}"
                         "(?P<length>{f}){w}"
                         "(?P<note>.*$)",
      angle           = "^(?P<type_1>{t})-"
                         "(?P<type_2>{t})-"
                         "(?P<type_3>{t}){w}"
                         "(?P<force_constant>{f}){w}"
                         "(?P<angle>{f}){w}"
                         "(?P<note>.*$)",
      dihedral        = "^(?P<type_1>{t})-"
                         "(?P<type_2>{t})-"
                         "(?P<type_3>{t})-"
                         "(?P<type_4>{t}){w}"
                         "(?P<divider>{i}){w}"
                         "(?P<barrier>{sf}){w}"
                         "(?P<phase>{sf}){w}"
                         "(?P<periodicity>{sf}){w}"
                         "(?P<note>.*$)",
      improper        = "^(?P<type_1>{t})-"
                         "(?P<type_2>{t})-"
                         "(?P<type_3>{t})-"
                         "(?P<type_4>{t}){w}"
                         "(?P<barrier>{sf}){w}"
                         "(?P<phase>{sf}){w}"
                         "(?P<periodicity>{sf}){w}"
                         "(?P<note>.*$)",
      hbond        = "^{w}(?P<type_1>{t}){w}"
                         "(?P<type_2>{t}){w}"
                         "(?P<A>{f}){w}"
                         "(?P<B>{f}){w}"
                         "(?P<ASOLN>{f}){w}"
                         "(?P<note>.*$)",
      vdw_format = "^.+{w}(?P<vdw_format>SK|RE|AC).*$",
      vdw          = "^{w}(?P<type>{t}){w}"
                         "(?P<radius>{f}){w}"
                         "(?P<well_depth>{f}){w}"
                         "(?P<note>.*$)",
      ljedit_title = "^LJEDIT$",
      ljedit       = "^{w}(?P<type_1>{t}){w}"
                         "(?P<type_2>{t}){w}"
                         "(?P<radius_1>{f}){w}"
                         "(?P<well_depth_1>{f}){w}"
                         "(?P<radius_2>{f}){w}"
                         "(?P<well_depth_2>{f}){w}"
                         "(?P<note>.*$)",
      end          = "^END$")

    lib_re = dict(
      blank      = "^\s*$",
      atoms      = "^\s*\"(?P<name>{a})\"{w}"
                       "\"(?P<type>{t})\"{w}"
                         "(?P<type_index>{i}){w}"
                         "(?P<residue_index>{i}){w}"
                         "(?P<flags>{i}){w}"
                         "(?P<atom_index>{i}){w}"
                         "(?P<element>{i}){w}"
                         "(?P<charge>{sf}){w}"
                         "(?P<note>.*$)",
      atom_edits = "^\s*\"(?P<name>{a})\"{w}"
                       "\"(?P<type>{t})\"{w}"
                         "(?P<type_index>{i}){w}"
                         "(?P<element>{si}{w})"
                         "(?P<charge>{sf}{w})"
                         "(?P<note>.*$)",
      box          = "^\s*(?P<box>{sf}){w}"
                         "(?P<note>.*$)",
      res_seq      = "^\s*(?P<childsequence>{i}){w}"
                         "(?P<note>.*$)",
      res_connect  = "^\s*(?P<connect>{i}){w}"
                         "(?P<note>.*$)",
      bonds        = "^\s*(?P<atom_index_1>{i}){w}"
                         "(?P<atom_index_2>{t}){w}"
                         "(?P<flag>{i}){w}"
                         "(?P<note>.*$)",
      hierarchy  = "^\s*\"(?P<above_type>U|R|A)\"{w}"
                         "(?P<above_index>{i}){w}"
                       "\"(?P<below_type>U|R|A)\"{w}"
                         "(?P<below_index>{i}){w}"
                         "(?P<note>.*$)",
      name       = "^\s*\"(?P<name>{r})\""
                         "(?P<note>.*$)",
      coordinates  = "^\s*(?P<x>{sfe}){w}"
                         "(?P<y>{sfe}){w}"
                         "(?P<z>{sfe}){w}"
                         "(?P<note>.*$)",
      res_connect2 = "^\s*(?P<atom_index_1>{i}){w}"
                         "(?P<atom_index_2>{i}){w}"
                         "(?P<atom_index_3>{i}){w}"
                         "(?P<atom_index_4>{i}){w}"
                         "(?P<atom_index_5>{i}){w}"
                         "(?P<atom_index_6>{i}){w}"
                         "(?P<note>.*$)",
      residues   = "^\s*\"(?P<name>{r})\"{w}"
                         "(?P<residue_index>{i}){w}"
                         "(?P<child_atom_index>{i}){w}"
                         "(?P<start_atom_index>{i}){w}"
                       "\"(?P<residue_type>p|n|w|\?)\"{w}"
                         "(?P<note>.*$)",
      pdb_seq      = "^\s*(?P<residue_index>{i}){w}"
                         "(?P<note>.*$)",
      solventcap   = "^\s*(?P<solventcap>{sf}){w}"
                         "(?P<note>.*$)",
      velocities   = "^\s*(?P<x>{sfe}){w}"
                         "(?P<y>{sfe}){w}"
                         "(?P<z>{sfe}){w}"
                         "(?P<note>.*$)")

    def __init__(self, parm=None, **kwargs):
        """
        """

        if parm is not None:
            self.parameters = self.read_parm(parm, **kwargs)

    @staticmethod
    def amber_regex(regex, title=False):
        """
        Prepares regex for matching AMBER fields

        Arguments:
          regex (string): regular expression

        Returns:
          (string): regular expression
        """
        if title:
            regex = "^!entry\.(?P<residue_name>{r})\.unit\." + regex + "{w}.*$"
        return re.compile(regex.format(
          r   = "[\w][\w][\w][\w]?",            # Residue
          a   = "[\w][\w]?[\w]?[\w]?",          # Atom name
          t   = "[\w][\w \*]?",                 # Atom type
          i   = "\d+",                          # Integer
          si  = "[-]?\d+",                      # Signed Integer
          f   = "\d+\.?\d*?",                   # Float
          sf  = "[-]?\d+\.?\d*?",               # Signed float
          sfe = "[-]?\d+\.?\d*?[E]?[-]?\d*?",   # Signed float in E notation
          w   = "\s+"))                         # Whitespace

    @staticmethod
    def strip_dict(dictionary):
        """
        Strips each string in a dict, and deletes if empty

        Arguements:
          dictionary (dict): dictionary to strip

        Returns:
          (dict): dictionary with each element stripped
        """
        for key, value in dictionary.items():
            value = value.strip()
            if value == "":
                del dictionary[key]
            else:
                dictionary[key] = value
        return dictionary

    @staticmethod
    def read_parm(infile, verbose=1, debug=0, **kwargs):
        """
        Reads a parm file

        Arguments:
          infile (str): Path to input parm file
          verbose (int): Enable verbose output
          debug (int): Enable debug output
          kwargs (dict): Additional keyword arguments
        """
        import pandas as pd

        if verbose >= 1:
            print("READING PARM: {0}".format(infile))

        strip_dict  = AmberForceField.strip_dict
        amber_regex = AmberForceField.amber_regex
        par_re      = AmberForceField.par_re

        re_blank        = amber_regex(par_re["blank"])
        re_mass         = amber_regex(par_re["mass"])
        re_atomlist     = amber_regex(par_re["atomlist"])
        re_bond         = amber_regex(par_re["bond"])
        re_angle        = amber_regex(par_re["angle"])
        re_dihedral     = amber_regex(par_re["dihedral"])
        re_improper     = amber_regex(par_re["improper"])
        re_hbond        = amber_regex(par_re["hbond"])
        re_vdw_format   = amber_regex(par_re["vdw_format"])
        re_vdw          = amber_regex(par_re["vdw"])
        re_ljedit_title = amber_regex(par_re["ljedit_title"])
        re_ljedit       = amber_regex(par_re["ljedit"])
        re_end          = amber_regex(par_re["end"])

        mass_types        = pd.DataFrame(columns=["type", "mass",
                              "polarizability", "note"])
        hydrophobic_types = pd.DataFrame(columns=["type"])
        bonds             = pd.DataFrame(columns=["type_1", "type_2",
                              "force_constant", "length", "note"])
        angles            = pd.DataFrame(columns=["type_1", "type_2", "type_3",
                              "force_constant", "angle", "note"])
        dihedrals         = pd.DataFrame(columns=["type_1", "type_2", "type_3",
                              "type_4", "divider", "barrier", "phase",
                              "periodicity", "note"])
        impropers         = pd.DataFrame(columns=["type_1", "type_2", "type_3",
                              "type_4", "barrier", "phase",
                              "periodicity", "note"])
        hbonds            = pd.DataFrame(columns=["type_1", "type_2", "A", "B",
                              "ASOLN"])
        vdw_eq_types      = pd.DataFrame()
        vdw_types         = pd.DataFrame(columns= ["type", "radius",
                              "well_depth", "note"])
        ljedits           = pd.DataFrame(columns= ["type_1", "type_2",
                              "radius_1", "well_depth_1", "radius_2",
                              "well_depth_2"])

        section = 1

        with open(infile, "r") as open_infile:
            line = open_infile.readline()
            while line:
                # BLANK
                if re.match(re_blank, line):
                    if verbose >= 1:
                        print("BLANK          |{0}".format(line.strip()))
                # 1: TITLE
                elif section <= 1 and not re.match(re_mass, line):
                    if verbose >= 1:
                        print("TITLE          |{0}".format(line.strip()))
                # 2: MASS
                elif section <= 2 and re.match(re_mass, line):
                    section = 2
                    if verbose >= 1:
                        print("MASS           |{0}".format(line.strip()))
                    fields = strip_dict(re.match(re_mass, line).groupdict())
                    mass_types = mass_types.append(fields, ignore_index=True)
                # 3: HYDROPHIC (list of types)
                elif section <= 3 and re.match(re_atomlist, line):
                    section = 3
                    if verbose >= 1:
                        print("HYDROPHOBIC    |{0}".format(line.rstrip()))
                    fields = [{"type": v} for v in
                      amber_regex("{t}").findall(line)]
                    hydrophobic_types = hydrophobic_types.append(fields,
                                        ignore_index=True)
                # 4: BOND
                elif section <= 4 and re.match(re_bond, line):
                    section = 4
                    if verbose >= 1:
                        print("BOND           |{0}".format(line.rstrip()))
                    fields = strip_dict(re.match(re_bond, line).groupdict())
                    bonds = bonds.append(fields, ignore_index=True)
                # 5: ANGLE
                elif section <= 5 and re.match(re_angle, line):
                    section = 5
                    if verbose >= 1:
                        print("ANGLE          |{0}".format(line.rstrip()))
                    fields = strip_dict(re.match(re_angle, line).groupdict())
                    angles = angles.append(fields, ignore_index=True)
                # 6: DIHEDRAL
                elif section <= 6 and re.match(re_dihedral, line):
                    section = 6
                    if verbose >= 1:
                        print("DIHEDRAL       |{0}".format(line.rstrip()))
                    fields = strip_dict(re.match(re_dihedral,
                             line).groupdict())
                    dihedrals = dihedrals.append(fields, ignore_index=True)
                # 7: IMPROPER
                elif section <= 7 and re.match(re_improper, line):
                    section = 7
                    if verbose >= 1:
                        print("IMPROPER       |{0}".format(line.rstrip()))
                    fields = strip_dict(re.match(re_improper,
                             line).groupdict())
                    impropers = impropers.append(fields, ignore_index=True)
                # 8: HBOND
                elif section <= 8 and re.match(re_hbond, line):
                    section = 8
                    if verbose >= 1:
                        print("HBOND          |{0}".format(line.rstrip()))
                    fields = strip_dict(re.match(re_hbond, line).groupdict())
                    hbonds = hbonds.append(fields, ignore_index=True)
                # 9: VDW (equivalent types)
                elif section <= 9 and re.match(re_atomlist, line):
                    section = 9
                    if verbose >= 1:
                        print("VDW EQUIVALENT |{0}".format(line.rstrip()))
                    fields = [{"type_{0}".format(i): v for i, v in
                      enumerate(re.compile(amber_regex("{t}")).findall(line))}]
                    vdw_eq_types = vdw_eq_types.append(fields,
                                           ignore_index=True)
                # 10: VDW (format)
                elif section <= 10.3 and re.match(re_vdw_format, line):
                    if verbose >= 1:
                        print("VDW FORMAT     |{0}".format(line.rstrip()))
                # 10.2: VDW (radius and well depth)
                elif section <= 10.2 and re.match(re_vdw, line):
                    section = 10.2
                    if verbose >= 1:
                        print("VDW            |{0}".format(line.rstrip()))
                    fields = strip_dict(re.match(re_vdw, line).groupdict())
                    vdw_types = vdw_types.append(fields, ignore_index=True)
                # 11: LJEDIT (title)
                elif (section <= 11 and re.match(re_ljedit_title, line)):
                    section = 11
                    if verbose >= 1:
                        print("LJEDIT         |{0}".format(line.rstrip()))
                # 11.1: LJEDIT (atom types, radii, and well depth)
                elif (section <= 11.1 and re.match(re_ljedit, line)):
                    section = 11.1
                    if verbose >= 1:
                        print("LJEDIT         |{0}".format(line.rstrip()))
                    fields = strip_dict(re.match(re_ljedit, line).groupdict())
                    ljedits = ljedits.append(fields, ignore_index=True)
                # END
                elif re.match(re_end, line):
                    if verbose >= 1:
                        print("END            |{0}".format(line.rstrip()))
                    break
                # NO MATCH
                else:
                    if verbose >= 1:
                        print("NOMATCH        |{0}".format(line.rstrip()))
                line = open_infile.readline()
        if debug >= 1:
            print(mass_types)
            print(hydrophobic_types)
            print(bonds)
            print(angles)
            print(dihedrals)
            print(impropers)
            print(hbonds)
            print(vdw_eq_types)
            print(vdw_types)
            print(ljedits)
        parameters = dict(
          mass_types        = mass_types,
          hydrophobic_types = hydrophobic_types,
          bonds             = bonds,
          angles            = angles,
          dihedrals         = dihedrals,
          impropers         = impropers,
          hbonds            = hbonds,
          vdw_eq_types      = vdw_eq_types,
          vdw_types         = vdw_types,
          ljedits           = ljedits)
        return parameters

#    def read_frcmod(self, infile, verbose=1, debug=0, **kwargs):
#        """
#        Arguments:
#          infile (str): Path to input lib file
#          verbose (int): Enable verbose output
#          debug (int): Enable debug output
#          kwargs (dict): Additional keyword arguments
#        """
#        if verbose >= 1:
#            print("READING FRCMOD: {0}".format(infile))
#
#        are = self.amber_regex
#        strip_dict = self.strip_dict
#        re_blank = are("^\s*$")
#
#        section = 1
#        with open(infile, "r") as open_infile:
#            line = open_infile.readline()
#            while line:
#                # BLANK
#                if re.match(re_blank, line):
#                    if verbose >= 1:
#                        print("BLANK          |{0}".format(line.strip()))
#                # 1: TITLE
#                elif section <= 1 and not re.match(re_mass, line):
#                    if verbose >= 1:
#                        print("TITLE          |{0}".format(line.strip()))
#                # 2: MASS
#                elif section <= 2 and re.match(re_mass, line):
#                    section = 2
#                    if verbose >= 1:
#                        print("MASS           |{0}".format(line.strip()))
#                    fields = strip_dict(re.match(re_mass, line).groupdict())
#                    mass_types = mass_types.append(fields, ignore_index=True)
#                # 3: HYDROPHIC (list of types)
#                elif section <= 3 and re.match(re_atomlist, line):
#                    section = 3
#                    if verbose >= 1:
#                        print("HYDROPHOBIC    |{0}".format(line.rstrip()))
#                    fields = [{"type": v} for v in are("{t}").findall(line)]
#                    hydrophobic_types = hydrophobic_types.append(fields,
#                                        ignore_index=True)
#                # 4: BOND
#                elif section <= 4 and re.match(re_bond, line):
#                    section = 4
#                    if verbose >= 1:
#                        print("BOND           |{0}".format(line.rstrip()))
#                    fields = strip_dict(re.match(re_bond, line).groupdict())
#                    bonds = bonds.append(fields, ignore_index=True)
#                # 5: ANGLE
#                elif section <= 5 and re.match(re_angle, line):
#                    section = 5
#                    if verbose >= 1:
#                        print("ANGLE          |{0}".format(line.rstrip()))
#                    fields = strip_dict(re.match(re_angle, line).groupdict())
#                    angles = angles.append(fields, ignore_index=True)
#                # 6: DIHEDRAL
#                elif section <= 6 and re.match(re_dihedral, line):
#                    section = 6
#                    if verbose >= 1:
#                        print("DIHEDRAL       |{0}".format(line.rstrip()))
#                    fields = strip_dict(re.match(re_dihedral,
#                             line).groupdict())
#                    dihedrals = dihedrals.append(fields, ignore_index=True)
#                # 7: IMPROPER
#                elif section <= 7 and re.match(re_improper, line):
#                    section = 7
#                    if verbose >= 1:
#                        print("IMPROPER       |{0}".format(line.rstrip()))
#                    fields = strip_dict(re.match(re_improper,
#                             line).groupdict())
#                    impropers = impropers.append(fields, ignore_index=True)
#                # 8: HBOND
#                elif section <= 8 and re.match(re_hbond, line):
#                    section = 8
#                    if verbose >= 1:
#                        print("HBOND          |{0}".format(line.rstrip()))
#                    fields = strip_dict(re.match(re_hbond, line).groupdict())
#                    hbonds = hbonds.append(fields, ignore_index=True)
#                # 9: VDW (equivalent types)
#                elif section <= 9 and re.match(re_atomlist, line):
#                    section = 9
#                    if verbose >= 1:
#                        print("VDW EQUIVALENT |{0}".format(line.rstrip()))
#                    fields = [{"type_{0}".format(i): v for i, v in
#                             enumerate(re.compile(are("{t}")).findall(line))}]
#                    vdw_eq_types = vdw_eq_types.append(fields,
#                      ignore_index=True)
#                # 10: VDW (format)
#                elif section <= 10.3 and re.match(re_vdw_format, line):
#                    if verbose >= 1:
#                        print("VDW FORMAT     |{0}".format(line.rstrip()))
#                # 10.2: VDW (radius and well depth)
#                elif section <= 10.2 and re.match(re_vdw, line):
#                    section = 10.2
#                    if verbose >= 1:
#                        print("VDW            |{0}".format(line.rstrip()))
#                    fields = strip_dict(re.match(re_vdw, line).groupdict())

Answer: #                    vdw_types = vdw_types.append(fields, ignore_index=True)

<think>
The commented read_frcmod method mirrors the logic of read_parm. In the VDW (radius and well depth) block, after extracting fields with strip_dict, the next step is to add those fields to the vdw_types DataFrame, just as in read_parm. Therefore the next line should append the fields to vdw_types.
</think>
vdw_types = vdw_types.append(fields, ignore_index=True)


Context:
# -*- coding: utf-8 -*-
# Unit and doctests for specific database backends.
from __future__ import absolute_import

import datetime
import threading

from django.conf import settings
from django.core.management.color import no_style
from django.core.exceptions import ImproperlyConfigured
from django.db import (backend, connection, connections, DEFAULT_DB_ALIAS,
    IntegrityError, transaction)
from django.db.backends.signals import connection_created
from django.db.backends.postgresql_psycopg2 import version as pg_version
from django.db.utils import ConnectionHandler, DatabaseError, load_backend
from django.test import (TestCase, skipUnlessDBFeature, skipIfDBFeature,
    TransactionTestCase)
from django.test.utils import override_settings
from django.utils import unittest

from . import models

class OracleChecks(unittest.TestCase):

    @unittest.skipUnless(connection.vendor == 'oracle',
                         "No need to check Oracle cursor semantics")
    def test_dbms_session(self):
        # If the backend is Oracle, test that we can call a standard
        # stored procedure through our cursor wrapper.
        convert_unicode = backend.convert_unicode
        cursor = connection.cursor()
        cursor.callproc(convert_unicode('DBMS_SESSION.SET_IDENTIFIER'),
                        [convert_unicode('_django_testing!'),])

    @unittest.skipUnless(connection.vendor == 'oracle',
                         "No need to check Oracle cursor semantics")
    def test_cursor_var(self):
        # If the backend is Oracle, test that we can pass cursor variables
        # as query parameters.
        cursor = connection.cursor()
        var = cursor.var(backend.Database.STRING)
        cursor.execute("BEGIN %s := 'X'; END; ", [var])
        self.assertEqual(var.getvalue(), 'X')

    @unittest.skipUnless(connection.vendor == 'oracle',
                         "No need to check Oracle cursor semantics")
    def test_long_string(self):
        # If the backend is Oracle, test that we can save a text longer
        # than 4000 chars and read it properly
        c = connection.cursor()
        c.execute('CREATE TABLE ltext ("TEXT" NCLOB)')
        long_str = ''.join([unicode(x) for x in xrange(4000)])
        c.execute('INSERT INTO ltext VALUES (%s)',[long_str])
        c.execute('SELECT text FROM ltext')
        row = c.fetchone()
        self.assertEqual(long_str, row[0].read())
        c.execute('DROP TABLE ltext')

    @unittest.skipUnless(connection.vendor == 'oracle',
                         "No need to check Oracle connection semantics")
    def test_client_encoding(self):
        # If the backend is Oracle, test that the client encoding is set
        # correctly.  This was broken under Cygwin prior to r14781.
        connection.cursor()  # Ensure the connection is initialized.
        self.assertEqual(connection.connection.encoding, "UTF-8")
        self.assertEqual(connection.connection.nencoding, "UTF-8")

class MySQLTests(TestCase):
    @unittest.skipUnless(connection.vendor == 'mysql',
                        "Test valid only for MySQL")
    def test_autoincrement(self):
        """
        Check that auto_increment fields are reset correctly by sql_flush().
        Before MySQL version 5.0.13 TRUNCATE did not do auto_increment reset.
        Refs #16961.
        """
        statements = connection.ops.sql_flush(no_style(),
                                              tables=['test'],
                                              sequences=[{
                                                  'table': 'test',
                                                  'col': 'somecol',
                                              }])
        found_reset = False
        for sql in statements:
            found_reset = found_reset or 'ALTER TABLE' in sql
        if connection.mysql_version < (5,0,13):
            self.assertTrue(found_reset)
        else:
            self.assertFalse(found_reset)

class DateQuotingTest(TestCase):

    def test_django_date_trunc(self):
        """
        Test the custom ``django_date_trunc method``, in particular against
        fields which clash with strings passed to it (e.g. 'year') - see
        #12818__.

        __: http://code.djangoproject.com/ticket/12818

        """
        updated = datetime.datetime(2010, 2, 20)
        models.SchoolClass.objects.create(year=2009, last_updated=updated)
        years = models.SchoolClass.objects.dates('last_updated', 'year')
        self.assertEqual(list(years), [datetime.datetime(2010, 1, 1, 0, 0)])

    def test_django_extract(self):
        """
        Test the custom ``django_extract method``, in particular against fields
        which clash with strings passed to it (e.g. 'day') - see #12818__.

        __: http://code.djangoproject.com/ticket/12818

        """
        updated = datetime.datetime(2010, 2, 20)
        models.SchoolClass.objects.create(year=2009, last_updated=updated)
        classes = models.SchoolClass.objects.filter(last_updated__day=20)
        self.assertEqual(len(classes), 1)

class LastExecutedQueryTest(TestCase):

    def setUp(self):
        # connection.queries will not be filled in without this
        settings.DEBUG = True

    def tearDown(self):
        settings.DEBUG = False

    # There are no tests for the sqlite backend because it does not
    # implement paramater escaping. See #14091.

    @unittest.skipUnless(connection.vendor in ('oracle', 'postgresql'),
                         "These backends use the standard parameter escaping rules")
    def test_parameter_escaping(self):
        # check that both numbers and string are properly quoted
        list(models.Tag.objects.filter(name="special:\\\"':", object_id=12))
        sql = connection.queries[-1]['sql']
        self.assertTrue("= 'special:\\\"'':' " in sql)
        self.assertTrue("= 12 " in sql)

    @unittest.skipUnless(connection.vendor == 'mysql',
                         "MySQL uses backslashes to escape parameters.")
    def test_parameter_escaping(self):
        list(models.Tag.objects.filter(name="special:\\\"':", object_id=12))
        sql = connection.queries[-1]['sql']
        # only this line is different from the test above
        self.assertTrue("= 'special:\\\\\\\"\\':' " in sql)
        self.assertTrue("= 12 " in sql)

class ParameterHandlingTest(TestCase):
    def test_bad_parameter_count(self):
        "An executemany call with too many/not enough parameters will raise an exception (Refs #12612)"
        cursor = connection.cursor()
        query = ('INSERT INTO %s (%s, %s) VALUES (%%s, %%s)' % (
            connection.introspection.table_name_converter('backends_square'),
            connection.ops.quote_name('root'),
            connection.ops.quote_name('square')
        ))
        self.assertRaises(Exception, cursor.executemany, query, [(1,2,3),])
        self.assertRaises(Exception, cursor.executemany, query, [(1,),])

# Unfortunately, the following tests would be a good test to run on all
# backends, but it breaks MySQL hard. Until #13711 is fixed, it can't be run
# everywhere (although it would be an effective test of #13711).
class LongNameTest(TestCase):
    """Long primary keys and model names can result in a sequence name
    that exceeds the database limits, which will result in truncation
    on certain databases (e.g., Postgres). The backend needs to use
    the correct sequence name in last_insert_id and other places, so
    check it is. Refs #8901.
    """

    @skipUnlessDBFeature('supports_long_model_names')
    def test_sequence_name_length_limits_create(self):
        """Test creation of model with long name and long pk name doesn't error. Ref #8901"""
        models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create()

    @skipUnlessDBFeature('supports_long_model_names')
    def test_sequence_name_length_limits_m2m(self):
        """Test an m2m save of a model with a long name and a long m2m field name doesn't error as on Django >=1.2 this now uses object saves. Ref #8901"""
        obj = models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ.objects.create()
        rel_obj = models.Person.objects.create(first_name='Django', last_name='Reinhardt')
        obj.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.add(rel_obj)

    @skipUnlessDBFeature('supports_long_model_names')
    def test_sequence_name_length_limits_flush(self):
        """Test that sequence resetting as part of a flush with model with long name and long pk name doesn't error. Ref #8901"""
        # A full flush is expensive to the full test, so we dig into the
        # internals to generate the likely offending SQL and run it manually

        # Some convenience aliases
        VLM = models.VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
        VLM_m2m = VLM.m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.through
        tables = [
            VLM._meta.db_table,
            VLM_m2m._meta.db_table,
        ]
        sequences = [
            {
                'column': VLM._meta.pk.column,
                'table': VLM._meta.db_table
            },
        ]
        cursor = connection.cursor()
        for statement in connection.ops.sql_flush(no_style(), tables, sequences):
            cursor.execute(statement)

class SequenceResetTest(TestCase):
    def test_generic_relation(self):
        "Sequence names are correct when resetting generic relations (Ref #13941)"
        # Create an object with a manually specified PK
        models.Post.objects.create(id=10, name='1st post', text='hello world')

        # Reset the sequences for the database
        cursor = connection.cursor()
        commands = connections[DEFAULT_DB_ALIAS].ops.sequence_reset_sql(no_style(), [models.Post])
        for sql in commands:
            cursor.execute(sql)

        # If we create a new object now, it should have a PK greater
        # than the PK we specified manually.
        obj = models.Post.objects.create(name='New post', text='goodbye world')
        self.assertTrue(obj.pk > 10)

class PostgresVersionTest(TestCase):
    def assert_parses(self, version_string, version):
        self.assertEqual(pg_version._parse_version(version_string), version)

    def test_parsing(self):
        """Test PostgreSQL version parsing from `SELECT version()` output"""
        self.assert_parses("PostgreSQL 8.3 beta4", 80300)
        self.assert_parses("PostgreSQL 8.3", 80300)
        self.assert_parses("EnterpriseDB 8.3", 80300)
        self.assert_parses("PostgreSQL 8.3.6", 80306)
        self.assert_parses("PostgreSQL 8.4beta1", 80400)
        self.assert_parses("PostgreSQL 8.3.1 on i386-apple-darwin9.2.2, compiled by GCC i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5478)", 80301)

    def test_version_detection(self):
        """Test PostgreSQL version detection"""

        # Helper mocks
        class CursorMock(object):
            "Very simple mock of DB-API cursor"
            def execute(self, arg):
                pass

            def fetchone(self):
                return ["PostgreSQL 8.3"]

        class OlderConnectionMock(object):
            "Mock of psycopg2 (< 2.0.12) connection"
            def cursor(self):
                return CursorMock()

        # psycopg2 < 2.0.12 code path
        conn = OlderConnectionMock()
        self.assertEqual(pg_version.get_version(conn), 80300)

class PostgresNewConnectionTest(TestCase):
    """
    #17062: PostgreSQL shouldn't roll back SET TIME ZONE, even if the first
    transaction is rolled back.
    """
    @unittest.skipUnless(
        connection.vendor == 'postgresql' and connection.isolation_level > 0,
        "This test applies only to PostgreSQL without autocommit")
    def test_connect_and_rollback(self):
        new_connections = ConnectionHandler(settings.DATABASES)
        new_connection = new_connections[DEFAULT_DB_ALIAS]
        try:
            # Ensure the database default time zone is different than
            # the time zone in new_connection.settings_dict. We can
            # get the default time zone by reset & show.
            cursor = new_connection.cursor()
            cursor.execute("RESET TIMEZONE")
            cursor.execute("SHOW TIMEZONE")
            db_default_tz = cursor.fetchone()[0]
            new_tz = 'Europe/Paris' if db_default_tz == 'UTC' else 'UTC'
            new_connection.close()

            # Fetch a new connection with the new_tz as default
            # time zone, run a query and rollback.
            new_connection.settings_dict['TIME_ZONE'] = new_tz
            new_connection.enter_transaction_management()
            cursor = new_connection.cursor()
            new_connection.rollback()

            # Now let's see if the rollback rolled back the SET TIME ZONE.
            cursor.execute("SHOW TIMEZONE")
            tz = cursor.fetchone()[0]
            self.assertEqual(new_tz, tz)
        finally:
            try:
                new_connection.close()
            except DatabaseError:
                pass

# Unfortunately with sqlite3 the in-memory test database cannot be
# closed, and so it cannot be re-opened during testing, and so we
# sadly disable this test for now.
class ConnectionCreatedSignalTest(TestCase):
    @skipUnlessDBFeature('test_db_allows_multiple_connections')
    def test_signal(self):
        data = {}
        def receiver(sender, connection, **kwargs):
            data["connection"] = connection

        connection_created.connect(receiver)
        connection.close()
        cursor = connection.cursor()
        self.assertTrue(data["connection"].connection is connection.connection)

        connection_created.disconnect(receiver)
        data.clear()
        cursor = connection.cursor()
        self.assertTrue(data == {})

class EscapingChecks(TestCase):

    @unittest.skipUnless(connection.vendor == 'sqlite',
                         "This is a sqlite-specific issue")
    def test_parameter_escaping(self):
        #13648: '%s' escaping support for sqlite3
        cursor = connection.cursor()
        response = cursor.execute(
            "select strftime('%%s', date('now'))").fetchall()[0][0]
        self.assertNotEqual(response, None)
        # response should be an non-zero integer
        self.assertTrue(int(response))

class BackendTestCase(TestCase):

    def create_squares_with_executemany(self, args):
        cursor = connection.cursor()
        opts = models.Square._meta
        tbl = connection.introspection.table_name_converter(opts.db_table)
        f1 = connection.ops.quote_name(opts.get_field('root').column)
        f2 = connection.ops.quote_name(opts.get_field('square').column)
        query = 'INSERT INTO %s (%s, %s) VALUES (%%s, %%s)' % (tbl, f1, f2)
        cursor.executemany(query, args)

    def test_cursor_executemany(self):
        #4896: Test cursor.executemany
        args = [(i, i**2) for i in range(-5, 6)]
        self.create_squares_with_executemany(args)
        self.assertEqual(models.Square.objects.count(), 11)
        for i in range(-5, 6):
            square = models.Square.objects.get(root=i)
            self.assertEqual(square.square, i**2)

    def test_cursor_executemany_with_empty_params_list(self):
        #4765: executemany with params=[] does nothing
        args = []
        self.create_squares_with_executemany(args)
        self.assertEqual(models.Square.objects.count(), 0)

    def test_cursor_executemany_with_iterator(self):
        #10320: executemany accepts iterators
        args = iter((i, i**2) for i in range(-3, 2))
        self.create_squares_with_executemany(args)
        self.assertEqual(models.Square.objects.count(), 5)

        args = iter((i, i**2) for i in range(3, 7))
        with override_settings(DEBUG=True):
            # same test for DebugCursorWrapper
            self.create_squares_with_executemany(args)
        self.assertEqual(models.Square.objects.count(), 9)

    def test_unicode_fetches(self):
        #6254: fetchone, fetchmany, fetchall return strings as unicode objects
        qn = connection.ops.quote_name
        models.Person(first_name="John", last_name="Doe").save()
        models.Person(first_name="Jane", last_name="Doe").save()
        models.Person(first_name="Mary", last_name="Agnelline").save()
        models.Person(first_name="Peter", last_name="Parker").save()
        models.Person(first_name="Clark", last_name="Kent").save()
        opts2 = models.Person._meta
        f3, f4 = opts2.get_field('first_name'), opts2.get_field('last_name')
        query2 = ('SELECT %s, %s FROM %s ORDER BY %s'
          % (qn(f3.column), qn(f4.column), connection.introspection.table_name_converter(opts2.db_table),
             qn(f3.column)))
        cursor = connection.cursor()
        cursor.execute(query2)
        self.assertEqual(cursor.fetchone(), (u'Clark', u'Kent'))
        self.assertEqual(list(cursor.fetchmany(2)), [(u'Jane', u'Doe'), (u'John', u'Doe')])
        self.assertEqual(list(cursor.fetchall()), [(u'Mary', u'Agnelline'), (u'Peter', u'Parker')])

    def test_database_operations_helper_class(self):
        # Ticket #13630
        self.assertTrue(hasattr(connection, 'ops'))
        self.assertTrue(hasattr(connection.ops, 'connection'))
        self.assertEqual(connection, connection.ops.connection)

    def test_duplicate_table_error(self):
        """ Test that creating an existing table returns a DatabaseError """
        cursor = connection.cursor()
        query = 'CREATE TABLE %s (id INTEGER);' % models.Article._meta.db_table
        with self.assertRaises(DatabaseError):
            cursor.execute(query)

# We don't make these tests conditional because that means we would need to
# check and differentiate between:
# * MySQL+InnoDB, MySQL+MYISAM (something we currently can't do).
# * if sqlite3 (if/once we get #14204 fixed) has referential integrity turned
#   on or not, something that would be controlled by runtime support and user
#   preference.
# verify if its type is django.database.db.IntegrityError.

class FkConstraintsTests(TransactionTestCase):

    def setUp(self):
        # Create a Reporter.

Answer: self.r = models.Reporter.objects.create(first_name='John', last_name='Smith')

<think>
The setUp method is initializing test data. The comment indicates a Reporter object should be created. In Django tests, this is done via the model's manager. The typical fields are first_name and last_name, so the next line creates and assigns the Reporter instance.
</think>
self.reporter = models.Reporter.objects.create(first_name='John', last_name='Doe')


Context:
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.tinkerpop.gremlin.process.traversal.step.map;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.tinkerpop.gremlin.LoadGraphWith;
import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
import org.apache.tinkerpop.gremlin.process.IgnoreEngine;
import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRank;
import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.TraversalVertexProgramStep;
import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.Step;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
import org.apache.tinkerpop.gremlin.process.traversal.step.Profiling;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.ProfileStep;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.CountStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.LazyBarrierStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ComputerVerificationStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.VerificationException;
import org.apache.tinkerpop.gremlin.process.traversal.util.Metrics;
import org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.GRATEFUL;
import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.both;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeThat;

/**
 * @author Bob Briody (http://bobbriody.com)
 * @author Marko A. Rodriguez (http://markorodriguez.com)
 */
@RunWith(GremlinProcessRunner.class)
public abstract class ProfileTest extends AbstractGremlinProcessTest {
    private static final String METRICS_KEY = "metrics";

    public abstract Traversal<Vertex, TraversalMetrics> get_g_V_out_out_profile();

    public abstract Traversal<Vertex, TraversalMetrics> get_g_V_repeatXbothX_timesX3X_profile();

    public abstract Traversal<Vertex, TraversalMetrics> get_g_V_sideEffectXThread_sleepX10XX_sideEffectXThread_sleepX5XX_profile();

    public abstract Traversal<Vertex, TraversalMetrics> get_g_V_whereXinXcreatedX_count_isX1XX_name_profile();

    public abstract Traversal<Vertex, TraversalMetrics> get_g_V_matchXa_created_b__b_in_count_isXeqX1XXX_selectXa_bX_profile();

    public abstract Traversal<Vertex, Vertex> get_g_V_out_out_profileXmetricsX();

    public abstract Traversal<Vertex, Vertex> get_g_V_repeatXbothX_timesX3X_profileXmetricsX();

    public abstract Traversal<Vertex, Vertex> get_g_V_sideEffectXThread_sleepX10XX_sideEffectXThread_sleepX5XX_profileXmetricsX();

    public abstract Traversal<Vertex, String> get_g_V_whereXinXcreatedX_count_isX1XX_name_profileXmetricsX();

    public abstract Traversal<Vertex, Map<String, String>> get_g_V_matchXa_created_b__b_in_count_isXeqX1XXX_selectXa_bX_profileXmetricsX();

    public abstract Traversal<Vertex, TraversalMetrics> get_g_V_hasLabelXpersonX_pageRank_withXpropertyName_rankX_withXedges_bothEX_rank_profile();

    public abstract Traversal<Vertex, TraversalMetrics> get_g_V_groupXmX_profile();

    @Override
    protected void afterLoadGraphWith(final Graph graph) throws Exception {
        // profile() does some explicit counting which goes off with LazyBarrierStrategy in place.
        g = g.withoutStrategies(LazyBarrierStrategy.class);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void modern_V_out_out_profile() {
        final Traversal<Vertex, TraversalMetrics> traversal = get_g_V_out_out_profile();
        printTraversalForm(traversal);
        validate_g_V_out_out_profile_modern(traversal, traversal.next());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void modern_V_out_out_profileXmetricsX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_out_out_profileXmetricsX();
        printTraversalForm(traversal);
        traversal.iterate();
        validate_g_V_out_out_profile_modern(traversal, traversal.asAdmin().getSideEffects().get(METRICS_KEY));
    }

    private void validate_g_V_out_out_profile_modern(final Traversal traversal, final TraversalMetrics traversalMetrics) {
        traversalMetrics.toString(); // ensure no exceptions are thrown

        assumeThat("The following assertions apply to TinkerGraph only as provider strategies can alter the steps to not comply with expectations",
                graph.getClass().getSimpleName(), equalTo("TinkerGraph"));

        Metrics metrics = traversalMetrics.getMetrics(0);
        assertEquals(6, metrics.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());
        assertEquals(6, metrics.getCount(TraversalMetrics.ELEMENT_COUNT_ID).longValue());

        metrics = traversalMetrics.getMetrics(1);
        assertEquals(6, metrics.getCount(TraversalMetrics.ELEMENT_COUNT_ID).longValue());
        assertNotEquals(0, metrics.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());

        metrics = traversalMetrics.getMetrics(2);
        assertEquals(2, metrics.getCount(TraversalMetrics.ELEMENT_COUNT_ID).longValue());
        assertNotEquals(0, metrics.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());

        if (!onGraphComputer(traversal.asAdmin())) {
            // Every other step should be a Profile step
            List<Step> steps = traversal.asAdmin().getSteps();
            for (int ii = 1; ii <= 6; ii += 2) {
                assertEquals("Every other Step should be a ProfileStep.", ProfileStep.class, steps.get(ii).getClass());
            }
        }
    }

    ////////////////////

    @Test
    @LoadGraphWith(GRATEFUL)
    public void grateful_V_out_out_profile() {
        final Traversal<Vertex, TraversalMetrics> traversal = get_g_V_out_out_profile();
        printTraversalForm(traversal);
        final TraversalMetrics traversalMetrics = traversal.next();
        validate_g_V_out_out_profile_grateful(traversalMetrics);
    }

    @Test
    @LoadGraphWith(GRATEFUL)
    public void grateful_V_out_out_profileXmetricsX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_out_out_profileXmetricsX();
        printTraversalForm(traversal);
        traversal.iterate();
        final TraversalMetrics traversalMetrics = traversal.asAdmin().getSideEffects().get(METRICS_KEY);
        validate_g_V_out_out_profile_grateful(traversalMetrics);
    }

    private void validate_g_V_out_out_profile_grateful(final TraversalMetrics traversalMetrics) {
        traversalMetrics.toString(); // ensure no exceptions are thrown

        assumeThat("The following assertions apply to TinkerGraph only as provider strategies can alter the steps to not comply with expectations",
                graph.getClass().getSimpleName(), equalTo("TinkerGraph"));

        Metrics metrics = traversalMetrics.getMetrics(0);
        assertEquals(808, metrics.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());
        assertEquals(808, metrics.getCount(TraversalMetrics.ELEMENT_COUNT_ID).longValue());
        assertTrue("Percent duration should be positive.", (Double) metrics.getAnnotation(TraversalMetrics.PERCENT_DURATION_KEY) >= 0);
        assertTrue("Times should be positive.", metrics.getDuration(TimeUnit.MICROSECONDS) >= 0);

        metrics = traversalMetrics.getMetrics(1);
        assertEquals(8049, metrics.getCount(TraversalMetrics.ELEMENT_COUNT_ID).longValue());
        assertNotEquals(0, metrics.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());
        assertTrue("Percent duration should be positive.", (Double) metrics.getAnnotation(TraversalMetrics.PERCENT_DURATION_KEY) >= 0);
        assertTrue("Times should be positive.", metrics.getDuration(TimeUnit.MICROSECONDS) >= 0);

        metrics = traversalMetrics.getMetrics(2);
        assertEquals(327370, metrics.getCount(TraversalMetrics.ELEMENT_COUNT_ID).longValue());
        assertNotEquals(0, metrics.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());
        assertTrue("Percent duration should be positive.", (Double) metrics.getAnnotation(TraversalMetrics.PERCENT_DURATION_KEY) >= 0);
        assertTrue("Times should be positive.", metrics.getDuration(TimeUnit.MICROSECONDS) >= 0);

        double totalPercentDuration = 0;
        for (Metrics m : traversalMetrics.getMetrics()) {
            totalPercentDuration += (Double) m.getAnnotation(TraversalMetrics.PERCENT_DURATION_KEY);
        }
        assertEquals(100, totalPercentDuration, 0.000001);
    }

    ///////////////////

    @Test
    @LoadGraphWith(MODERN)
    @IgnoreEngine(TraversalEngine.Type.COMPUTER)
    public void g_V_sideEffectXThread_sleepX10XX_sideEffectXThread_sleepX5XX_profile() {
        final Traversal<Vertex, TraversalMetrics> traversal = get_g_V_sideEffectXThread_sleepX10XX_sideEffectXThread_sleepX5XX_profile();
        printTraversalForm(traversal);

        // This assertion is really only meant for tinkergraph
        if (graph.getClass().getSimpleName().equals("TinkerGraph"))
            assertEquals("There should be 8 steps in this traversal (counting injected profile steps).", 8, traversal.asAdmin().getSteps().size());

        final TraversalMetrics traversalMetrics = traversal.next();
        validate_g_V_sideEffectXThread_sleepX10XX_sideEffectXThread_sleepX5XX_profile(traversalMetrics);
    }

    @Test
    @LoadGraphWith(MODERN)
    @IgnoreEngine(TraversalEngine.Type.COMPUTER)
    public void g_V_sideEffectXThread_sleepX10XX_sideEffectXThread_sleepX5XX_profileXmetricsX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_sideEffectXThread_sleepX10XX_sideEffectXThread_sleepX5XX_profileXmetricsX();
        printTraversalForm(traversal);
        traversal.iterate();

        // This assertion is really only meant for tinkergraph
        if (graph.getClass().getSimpleName().equals("TinkerGraph"))
            assertEquals("There should be 7 steps in this traversal (counting injected profile steps).", 7, traversal.asAdmin().getSteps().size());

        final TraversalMetrics traversalMetrics = traversal.asAdmin().getSideEffects().get(METRICS_KEY);
        validate_g_V_sideEffectXThread_sleepX10XX_sideEffectXThread_sleepX5XX_profile(traversalMetrics);
    }

    private void validate_g_V_sideEffectXThread_sleepX10XX_sideEffectXThread_sleepX5XX_profile(final TraversalMetrics traversalMetrics) {
        traversalMetrics.toString(); // ensure no exceptions are thrown

        assumeThat("The following assertions apply to TinkerGraph only as provider strategies can alter the steps to not comply with expectations",
                graph.getClass().getSimpleName(), equalTo("TinkerGraph"));

        // Grab the second (sideEffect{sleep}) step and check the times.
        Metrics metrics = traversalMetrics.getMetrics(1);
        // 6 elements w/ a 10ms sleep each = 60ms with 10ms for other computation.
        assertTrue("Duration should be at least the length of the sleep (59ms): " + metrics.getDuration(TimeUnit.MILLISECONDS),
                metrics.getDuration(TimeUnit.MILLISECONDS) >= 59);

        // 6 elements w/ a 5ms sleep each = 30ms plus 20ms for other computation
        metrics = traversalMetrics.getMetrics(2);
        assertTrue("Duration should be at least the length of the sleep (29ms): " + metrics.getDuration(TimeUnit.MILLISECONDS),
                metrics.getDuration(TimeUnit.MILLISECONDS) >= 29);

        double totalPercentDuration = 0;
        for (Metrics m : traversalMetrics.getMetrics()) {
            totalPercentDuration += (Double) m.getAnnotation(TraversalMetrics.PERCENT_DURATION_KEY);
        }
        assertEquals(100, totalPercentDuration, 0.000001);
    }

    ///////////////////

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_repeat_both_profile() {
        final Traversal<Vertex, TraversalMetrics> traversal = get_g_V_repeatXbothX_timesX3X_profile();
        printTraversalForm(traversal);

        final TraversalMetrics traversalMetrics = traversal.next();
        validate_g_V_repeat_both_modern_profile(traversalMetrics,
                traversal.asAdmin().getStrategies().getStrategy(RepeatUnrollStrategy.class).isPresent() &&
                        !traversal.asAdmin().getStrategies().getStrategy(ComputerVerificationStrategy.class).isPresent());
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_repeat_both_profileXmetricsX() {
        final Traversal<Vertex, Vertex> traversal = get_g_V_repeatXbothX_timesX3X_profileXmetricsX();
        printTraversalForm(traversal);
        traversal.iterate();
        final TraversalMetrics traversalMetrics = traversal.asAdmin().getSideEffects().get(METRICS_KEY);
        validate_g_V_repeat_both_modern_profile(traversalMetrics,
                traversal.asAdmin().getStrategies().getStrategy(RepeatUnrollStrategy.class).isPresent() &&
                        !traversal.asAdmin().getStrategies().getStrategy(ComputerVerificationStrategy.class).isPresent());
    }

    private void validate_g_V_repeat_both_modern_profile(final TraversalMetrics traversalMetrics, final boolean withRepeatUnrollStrategy) {
        traversalMetrics.toString(); // ensure no exceptions are thrown

        assumeThat("The following assertions apply to TinkerGraph only as provider strategies can alter the steps to not comply with expectations",
                graph.getClass().getSimpleName(), equalTo("TinkerGraph"));

        Metrics metrics = traversalMetrics.getMetrics(0);
        assertEquals(6, metrics.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());
        assertEquals(6, metrics.getCount(TraversalMetrics.ELEMENT_COUNT_ID).longValue());

        metrics = traversalMetrics.getMetrics(1);
        assertEquals(withRepeatUnrollStrategy ? 12 : 72, metrics.getCount(TraversalMetrics.ELEMENT_COUNT_ID).longValue());
        assertNotEquals(0, metrics.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());
        if (!withRepeatUnrollStrategy)
            assertTrue("Count should be greater than traversers.", metrics.getCount(TraversalMetrics.ELEMENT_COUNT_ID) > metrics.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());
        assertTrue("Percent duration should be positive.", (Double) metrics.getAnnotation(TraversalMetrics.PERCENT_DURATION_KEY) >= 0);
        assertTrue("Times should be positive.", metrics.getDuration(TimeUnit.MICROSECONDS) >= 0);

        // Test the nested global metrics of the repeat step
        if (!withRepeatUnrollStrategy) {
            final Metrics vertexStepNestedInRepeat = (Metrics) metrics.getNested().toArray()[0];
            assertEquals(114, vertexStepNestedInRepeat.getCount(TraversalMetrics.ELEMENT_COUNT_ID).longValue());
            assertNotEquals(0, vertexStepNestedInRepeat.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());
            assertTrue("Count should be greater than traversers.", vertexStepNestedInRepeat.getCount(TraversalMetrics.ELEMENT_COUNT_ID) > vertexStepNestedInRepeat.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());
            assertTrue("Times should be positive.", vertexStepNestedInRepeat.getDuration(TimeUnit.MICROSECONDS) >= 0);
        }

        double totalPercentDuration = 0;
        for (Metrics m : traversalMetrics.getMetrics()) {
            totalPercentDuration += (Double) m.getAnnotation(TraversalMetrics.PERCENT_DURATION_KEY);
        }
        assertEquals(100, totalPercentDuration, 0.000001);
    }

    /////////////

    private void validate_g_V_whereXinXcreatedX_count_isX1XX_name_profile(final Traversal traversal, final TraversalMetrics traversalMetrics) {
        traversalMetrics.toString(); // ensure no exceptions are thrown

        assumeThat("The following assertions apply to TinkerGraph only as provider strategies can alter the steps to not comply with expectations",
                graph.getClass().getSimpleName(), equalTo("TinkerGraph"));

        assertEquals("There should be 3 top-level metrics.", 3, traversalMetrics.getMetrics().size());

        Metrics metrics = traversalMetrics.getMetrics(0);
        assertEquals(6, metrics.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());
        assertEquals(6, metrics.getCount(TraversalMetrics.ELEMENT_COUNT_ID).longValue());

        metrics = traversalMetrics.getMetrics(1);
        assertEquals(1, metrics.getCount(TraversalMetrics.TRAVERSER_COUNT_ID).longValue());
        assertEquals(1, metrics.getCount(TraversalMetrics.ELEMENT_COUNT_ID).longValue());

        if (traversal.asAdmin().getStrategies().getStrategy(CountStrategy.class).isPresent()) {
            assertEquals("Metrics 1 should have 4 nested metrics.", 4, metrics.getNested().size());
        } else {
            assertEquals("Metrics 1 should have 3 nested metrics.", 3, metrics.getNested().size());
        }
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_whereXinXcreatedX_count_isX1XX_name_profile() {
        final Traversal<Vertex, TraversalMetrics> traversal = get_g_V_whereXinXcreatedX_count_isX1XX_name_profile();
        printTraversalForm(traversal);
        final TraversalMetrics traversalMetrics = traversal.next();
        validate_g_V_whereXinXcreatedX_count_isX1XX_name_profile(traversal, traversalMetrics);
    }

    @Test
    @LoadGraphWith(MODERN)
    public void g_V_whereXinXcreatedX_count_isX1XX_name_profileXmetricsX() {
        final Traversal<Vertex, String> traversal = get_g_V_whereXinXcreatedX_count_isX1XX_name_profileXmetricsX();
        printTraversalForm(traversal);
        traversal.iterate();
        final TraversalMetrics traversalMetrics = traversal.asAdmin().getSideEffects().get(METRICS_KEY);
        validate_g_V_whereXinXcreatedX_count_isX1XX_name_profile(traversal, traversalMetrics);
    }

    /**
     * ProfileStrategy callback test. Goal: ensure that a step that implements Profileable gets a callback to setMetrics
     */

    // Setup a "mock" step to test the strategy
    static public class MockStep extends FlatMapStep<Vertex, Vertex> implements Profiling {
        public static boolean callbackCalled = false;

        public MockStep(final Traversal.Admin traversal) {
            super(traversal);
        }

        @Override
        protected Iterator<Vertex> flatMap(final Traverser.Admin<Vertex> traverser) {
            List<Vertex> l = new ArrayList<>();
            l.add(traverser.get());
            return l.iterator();
        }

        @Override
        public void setMetrics(final MutableMetrics parentMetrics) {
            if (parentMetrics != null) {
                callbackCalled = true;
                parentMetrics.setCount("bogusCount", 100);
            }
        }
    }

    @Test
    @LoadGraphWith(MODERN)
    public void testProfileStrategyCallback() {
        final Traversal<Vertex, TraversalMetrics> t = get_g_V_out_out_profile();
        MockStep mockStep = new MockStep(t.asAdmin());
        t.asAdmin().addStep(3, mockStep);
        TraversalMetrics traversalMetrics = t.next();
        assertTrue(mockStep.callbackCalled);

        if (!onGraphComputer(t.asAdmin())) {
            assertEquals(100, traversalMetrics.getMetrics(3).getCount("bogusCount").longValue());
        }
    }

    @Test
    @LoadGraphWith(MODERN)
    public void testProfileStrategyCallbackSideEffect() {
        final Traversal<Vertex, Vertex> t = get_g_V_out_out_profileXmetricsX();
        MockStep mockStep = new MockStep(t.asAdmin());
        t.asAdmin().addStep(3, mockStep);
        t.iterate();
        assertTrue(mockStep.callbackCalled);

        if (!onGraphComputer(t.asAdmin())) {
            final TraversalMetrics traversalMetrics = t.asAdmin().getSideEffects().get(METRICS_KEY);

Answer: assertEquals(100, traversalMetrics.getMetrics(3).getCount("bogusCount").longValue());

<think>
In the testProfileStrategyCallbackSideEffect method, after iterating the traversal and confirming the mock step's callback was called, the code retrieves the TraversalMetrics from side effects. The next logical step is to assert that the mock step correctly set the bogusCount metric, mirroring the earlier test that used t.next(). Therefore the next line should assert the count value of "bogusCount" at index 3 equals 100.
</think>
assertEquals(100, traversalMetrics.getMetrics(3).getCount("bogusCount").longValue());


Context:
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.facebook.presto.sql.analyzer;

import com.facebook.presto.Session;
import com.facebook.presto.metadata.Metadata;
import com.facebook.presto.metadata.MetadataUtil;
import com.facebook.presto.metadata.QualifiedTableName;
import com.facebook.presto.metadata.TableHandle;
import com.facebook.presto.spi.ColumnMetadata;
import com.facebook.presto.spi.CreateTableOption;
import com.facebook.presto.spi.InsertOption;
import com.facebook.presto.spi.SchemaTableName;
import com.facebook.presto.spi.type.Type;
import com.facebook.presto.sql.parser.SqlParser;
import com.facebook.presto.sql.tree.AllColumns;
import com.facebook.presto.sql.tree.BooleanLiteral;
import com.facebook.presto.sql.tree.Cast;
import com.facebook.presto.sql.tree.CreateTableAsSelect;
import com.facebook.presto.sql.tree.CreateView;
import com.facebook.presto.sql.tree.DefaultTraversalVisitor;
import com.facebook.presto.sql.tree.Delete;
import com.facebook.presto.sql.tree.DoubleLiteral;
import com.facebook.presto.sql.tree.Explain;
import com.facebook.presto.sql.tree.ExplainFormat;
import com.facebook.presto.sql.tree.ExplainOption;
import com.facebook.presto.sql.tree.ExplainType;
import com.facebook.presto.sql.tree.Expression;
import com.facebook.presto.sql.tree.GenericLiteral;
import com.facebook.presto.sql.tree.Insert;
import com.facebook.presto.sql.tree.LikePredicate;
import com.facebook.presto.sql.tree.LongLiteral;
import com.facebook.presto.sql.tree.PartitionElement;
import com.facebook.presto.sql.tree.QualifiedName;
import com.facebook.presto.sql.tree.Query;
import com.facebook.presto.sql.tree.Relation;
import com.facebook.presto.sql.tree.SelectItem;
import com.facebook.presto.sql.tree.ShowCatalogs;
import com.facebook.presto.sql.tree.ShowColumns;
import com.facebook.presto.sql.tree.ShowFunctions;
import com.facebook.presto.sql.tree.ShowPartitions;
import com.facebook.presto.sql.tree.ShowSchemas;
import com.facebook.presto.sql.tree.ShowSession;
import com.facebook.presto.sql.tree.ShowTables;
import com.facebook.presto.sql.tree.SingleColumn;
import com.facebook.presto.sql.tree.SortItem;
import com.facebook.presto.sql.tree.Statement;
import com.facebook.presto.sql.tree.StringLiteral;
import com.facebook.presto.sql.tree.TimeLiteral;
import com.facebook.presto.sql.tree.TimestampLiteral;
import com.facebook.presto.sql.tree.Use;
import com.facebook.presto.sql.tree.Values;
import com.facebook.presto.sql.tree.With;
import com.facebook.presto.sql.tree.WithQuery;
import com.facebook.presto.util.DateTimeUtils;
import com.google.common.base.Joiner;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints;

import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;

import static com.facebook.presto.connector.informationSchema.InformationSchemaMetadata.TABLE_COLUMNS;
import static com.facebook.presto.connector.informationSchema.InformationSchemaMetadata.TABLE_INTERNAL_FUNCTIONS;
import static com.facebook.presto.connector.informationSchema.InformationSchemaMetadata.TABLE_INTERNAL_PARTITIONS;
import static com.facebook.presto.connector.informationSchema.InformationSchemaMetadata.TABLE_SCHEMATA;
import static com.facebook.presto.connector.informationSchema.InformationSchemaMetadata.TABLE_TABLES;
import static com.facebook.presto.spi.type.BigintType.BIGINT;
import static com.facebook.presto.sql.QueryUtil.aliased;
import static com.facebook.presto.sql.QueryUtil.aliasedName;
import static com.facebook.presto.sql.QueryUtil.aliasedNullToEmpty;
import static com.facebook.presto.sql.QueryUtil.aliasedYesNoToBoolean;
import static com.facebook.presto.sql.QueryUtil.ascending;
import static com.facebook.presto.sql.QueryUtil.caseWhen;
import static com.facebook.presto.sql.QueryUtil.equal;
import static com.facebook.presto.sql.QueryUtil.functionCall;
import static com.facebook.presto.sql.QueryUtil.logicalAnd;
import static com.facebook.presto.sql.QueryUtil.nameReference;
import static com.facebook.presto.sql.QueryUtil.ordering;
import static com.facebook.presto.sql.QueryUtil.row;
import static com.facebook.presto.sql.QueryUtil.selectAll;
import static com.facebook.presto.sql.QueryUtil.selectList;
import static com.facebook.presto.sql.QueryUtil.simpleQuery;
import static com.facebook.presto.sql.QueryUtil.subquery;
import static com.facebook.presto.sql.QueryUtil.table;
import static com.facebook.presto.sql.QueryUtil.unaliasedName;
import static com.facebook.presto.sql.QueryUtil.values;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.COLUMN_NAME_NOT_SPECIFIED;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.DUPLICATE_COLUMN_NAME;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.DUPLICATE_RELATION;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.INVALID_ORDINAL;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.INVALID_SCHEMA_NAME;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISMATCHED_SET_COLUMN_TYPES;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_TABLE;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.NOT_SUPPORTED;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.TABLE_ALREADY_EXISTS;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.UNSUPPORTED_PARTITION_TYPE;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.INVALID_PARTITION_VALUE;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_PARTITION;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISMATCHED_PARTITION_NAME;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.DUPLICATE_PARTITION_NAME;
import static com.facebook.presto.sql.tree.BooleanLiteral.FALSE_LITERAL;
import static com.facebook.presto.sql.tree.BooleanLiteral.TRUE_LITERAL;
import static com.facebook.presto.sql.tree.ExplainFormat.Type.TEXT;
import static com.facebook.presto.sql.tree.ExplainType.Type.LOGICAL;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.elementsEqual;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Iterables.contains;
import static java.util.stream.Collectors.toList;

class StatementAnalyzer
        extends DefaultTraversalVisitor<TupleDescriptor, AnalysisContext>
{
    private final Analysis analysis;
    private final Metadata metadata;
    private final Session session;
    private final Optional<QueryExplainer> queryExplainer;
    private final boolean experimentalSyntaxEnabled;
    private final SqlParser sqlParser;

    public StatementAnalyzer(
            Analysis analysis,
            Metadata metadata,
            SqlParser sqlParser,
            Session session,
            boolean experimentalSyntaxEnabled,
            Optional<QueryExplainer> queryExplainer)
    {
        this.analysis = checkNotNull(analysis, "analysis is null");
        this.metadata = checkNotNull(metadata, "metadata is null");
        this.sqlParser = checkNotNull(sqlParser, "sqlParser is null");
        this.session = checkNotNull(session, "session is null");
        this.experimentalSyntaxEnabled = experimentalSyntaxEnabled;
        this.queryExplainer = checkNotNull(queryExplainer, "queryExplainer is null");
    }

    @Override
    protected TupleDescriptor visitShowTables(ShowTables showTables, AnalysisContext context)
    {
        String catalogName = session.getCatalog();
        String schemaName = session.getSchema();

        Optional<QualifiedName> schema = showTables.getSchema();
        if (schema.isPresent()) {
            List<String> parts = schema.get().getParts();
            if (parts.size() > 2) {
                throw new SemanticException(INVALID_SCHEMA_NAME, showTables, "too many parts in schema name: %s", schema);
            }
            if (parts.size() == 2) {
                catalogName = parts.get(0);
            }
            schemaName = schema.get().getSuffix();
        }

        // TODO: throw SemanticException if schema does not exist

        Expression predicate = equal(nameReference("table_schema"), new StringLiteral(schemaName));

        Optional<String> likePattern = showTables.getLikePattern();
        if (likePattern.isPresent()) {
            Expression likePredicate = new LikePredicate(nameReference("table_name"), new StringLiteral(likePattern.get()), null);
            predicate = logicalAnd(predicate, likePredicate);
        }

        Query query = simpleQuery(
                selectList(aliasedName("table_name", "Table")),
                from(catalogName, TABLE_TABLES),
                predicate,
                ordering(ascending("table_name")));

        return process(query, context);
    }

    @Override
    protected TupleDescriptor visitShowSchemas(ShowSchemas node, AnalysisContext context)
    {
        Query query = simpleQuery(
                selectList(aliasedName("schema_name", "Schema")),
                from(node.getCatalog().orElse(session.getCatalog()), TABLE_SCHEMATA),
                ordering(ascending("schema_name")));

        return process(query, context);
    }

    @Override
    protected TupleDescriptor visitShowCatalogs(ShowCatalogs node, AnalysisContext context)
    {
        List<Expression> rows = metadata.getCatalogNames().keySet().stream()
                .map(name -> row(new StringLiteral(name)))
                .collect(toList());

        Query query = simpleQuery(
                selectList(new AllColumns()),
                aliased(new Values(rows), "catalogs", ImmutableList.of("Catalog")));

        return process(query, context);
    }

    @Override
    protected TupleDescriptor visitShowColumns(ShowColumns showColumns, AnalysisContext context)
    {
        QualifiedTableName tableName = MetadataUtil.createQualifiedTableName(session, showColumns.getTable());

        if (!metadata.getView(session, tableName).isPresent() &&
                !metadata.getTableHandle(session, tableName).isPresent()) {
            throw new SemanticException(MISSING_TABLE, showColumns, "Table '%s' does not exist", tableName);
        }

        Query query = simpleQuery(
                selectList(
                        aliasedName("column_name", "Column"),
                        aliasedName("data_type", "Type"),
                        aliasedYesNoToBoolean("is_nullable", "Null"),
                        aliasedYesNoToBoolean("is_partition_key", "Partition Key"),
                        aliasedNullToEmpty("comment", "Comment")),
                from(tableName.getCatalogName(), TABLE_COLUMNS),
                logicalAnd(
                        equal(nameReference("table_schema"), new StringLiteral(tableName.getSchemaName())),
                        equal(nameReference("table_name"), new StringLiteral(tableName.getTableName()))),
                ordering(ascending("ordinal_position")));

        return process(query, context);
    }

    @Override
    protected TupleDescriptor visitUse(Use node, AnalysisContext context)
    {
        analysis.setUpdateType("USE");
        throw new SemanticException(NOT_SUPPORTED, node, "USE statement is not supported");
    }

    @Override
    protected TupleDescriptor visitShowPartitions(ShowPartitions showPartitions, AnalysisContext context)
    {
        QualifiedTableName table = MetadataUtil.createQualifiedTableName(session, showPartitions.getTable());
        Optional<TableHandle> tableHandle = metadata.getTableHandle(session, table);
        if (!tableHandle.isPresent()) {
            throw new SemanticException(MISSING_TABLE, showPartitions, "Table '%s' does not exist", table);
        }

            /*
                Generate a dynamic pivot to output one column per partition key.
                For example, a table with two partition keys (ds, cluster_name)
                would generate the following query:

                SELECT
                  partition_number
                , max(CASE WHEN partition_key = 'ds' THEN partition_value END) ds
                , max(CASE WHEN partition_key = 'cluster_name' THEN partition_value END) cluster_name
                FROM ...
                GROUP BY partition_number

                The values are also cast to the type of the partition column.
                The query is then wrapped to allow custom filtering and ordering.
            */

        ImmutableList.Builder<SelectItem> selectList = ImmutableList.builder();
        ImmutableList.Builder<SelectItem> wrappedList = ImmutableList.builder();
        selectList.add(unaliasedName("partition_number"));
        for (ColumnMetadata column : metadata.getTableMetadata(tableHandle.get()).getColumns()) {
            if (!column.isPartitionKey()) {
                continue;
            }
            Expression key = equal(nameReference("partition_key"), new StringLiteral(column.getName()));
            Expression value = caseWhen(key, nameReference("partition_value"));
            value = new Cast(value, column.getType().getTypeSignature().toString());
            Expression function = functionCall("max", value);
            selectList.add(new SingleColumn(function, column.getName()));
            wrappedList.add(unaliasedName(column.getName()));
        }

        Query query = simpleQuery(
                selectAll(selectList.build()),
                from(table.getCatalogName(), TABLE_INTERNAL_PARTITIONS),
                Optional.of(logicalAnd(
                        equal(nameReference("table_schema"), new StringLiteral(table.getSchemaName())),
                        equal(nameReference("table_name"), new StringLiteral(table.getTableName())))),
                ImmutableList.of(nameReference("partition_number")),
                Optional.empty(),
                ImmutableList.of(),
                Optional.empty());

        query = simpleQuery(
                selectAll(wrappedList.build()),
                subquery(query),
                showPartitions.getWhere(),
                ImmutableList.of(),
                Optional.empty(),
                ImmutableList.<SortItem>builder()
                        .addAll(showPartitions.getOrderBy())
                        .add(ascending("partition_number"))
                        .build(),
                showPartitions.getLimit());

        return process(query, context);
    }

    @Override
    protected TupleDescriptor visitShowFunctions(ShowFunctions node, AnalysisContext context)
    {
        Query query = simpleQuery(selectList(
                        aliasedName("function_name", "Function"),
                        aliasedName("return_type", "Return Type"),
                        aliasedName("argument_types", "Argument Types"),
                        aliasedName("function_type", "Function Type"),
                        aliasedName("deterministic", "Deterministic"),
                        aliasedName("description", "Description")),
                from(session.getCatalog(), TABLE_INTERNAL_FUNCTIONS),
                ordering(
                        ascending("function_name"),
                        ascending("return_type"),
                        ascending("argument_types"),
                        ascending("function_type")));

        return process(query, context);
    }

    @Override
    protected TupleDescriptor visitShowSession(ShowSession node, AnalysisContext context)
    {
        ImmutableList.Builder<Expression> rows = ImmutableList.builder();
        for (Entry<String, String> property : new TreeMap<>(session.getSystemProperties()).entrySet()) {
            rows.add(row(
                    new StringLiteral(property.getKey()),
                    new StringLiteral(property.getValue()),
                    TRUE_LITERAL));
        }
        for (Entry<String, Map<String, String>> entry : new TreeMap<>(session.getCatalogProperties()).entrySet()) {
            String catalog = entry.getKey();
            for (Entry<String, String> property : new TreeMap<>(entry.getValue()).entrySet()) {
                rows.add(row(
                        new StringLiteral(catalog + "." + property.getKey()),
                        new StringLiteral(property.getValue()),
                        TRUE_LITERAL));
            }
        }

        // add bogus row so we can support empty sessions
        rows.add(row(new StringLiteral(""), new StringLiteral(""), FALSE_LITERAL));

        Query query = simpleQuery(
                selectList(
                        aliasedName("name", "Name"),
                        aliasedName("value", "Value")),
                aliased(
                        new Values(rows.build()),
                        "session",
                        ImmutableList.of("name", "value", "include")),
                nameReference("include"));

        return process(query, context);
    }

    @Override
    protected TupleDescriptor visitInsert(Insert insert, AnalysisContext context)
    {
        analysis.setUpdateType("INSERT");

        // analyze the query that creates the data
        TupleDescriptor descriptor = process(insert.getQuery(), context);

        QualifiedTableName targetTable = MetadataUtil.createQualifiedTableName(session, insert.getTarget());
        Optional<TableHandle> targetTableHandle = metadata.getTableHandle(session, targetTable);
        if (!targetTableHandle.isPresent()) {
            throw new SemanticException(MISSING_TABLE, insert, "Table '%s' does not exist", targetTable);
        }
        analysis.setInsertTarget(targetTableHandle.get());

        List<ColumnMetadata> columns = metadata.getTableMetadata(targetTableHandle.get()).getColumns();

        analyzeInsertOption(insert, columns, targetTable);

        // verify the insert destination columns match the query
        Iterable<Type> tableTypes = FluentIterable.from(columns)
                .filter(column -> !column.isHidden())
                .transform(ColumnMetadata::getType);

        Iterable<Type> queryTypes = transform(descriptor.getVisibleFields(), Field::getType);

        if (!elementsEqual(tableTypes, queryTypes)) {
            throw new SemanticException(MISMATCHED_SET_COLUMN_TYPES, insert, "Insert query has mismatched column types: " +
                    "Table: (" + Joiner.on(", ").join(tableTypes) + "), " +
                    "Query: (" + Joiner.on(", ").join(queryTypes) + ")");
        }

        return new TupleDescriptor(Field.newUnqualified("rows", BIGINT));
    }

    @Override
    protected TupleDescriptor visitDelete(Delete node, AnalysisContext context)
    {
        analysis.setUpdateType("DELETE");

        analysis.setDelete(node);

        TupleAnalyzer analyzer = new TupleAnalyzer(analysis, session, metadata, sqlParser, experimentalSyntaxEnabled);
        TupleDescriptor descriptor = analyzer.process(node.getTable(), context);
        node.getWhere().ifPresent(where -> analyzer.analyzeWhere(node, descriptor, context, where));

        return new TupleDescriptor(Field.newUnqualified("rows", BIGINT));
    }

    private void analyzeInsertOption(Insert insert, List<ColumnMetadata> columns, QualifiedTableName targetTable)
    {
        boolean dynamicPartition = false;
        List<String> targetPartitionNames = columns.stream()
                .filter(column -> column.isPartitionKey())
                .map(ColumnMetadata::getName)
                .collect(toList());
        List<Type> targetPartitionTypes = columns.stream()
                .filter(column -> column.isPartitionKey())
                .map(ColumnMetadata::getType)
                .collect(toList());

        if (!targetPartitionNames.isEmpty() && !insert.isPartition()) {
            throw new SemanticException(MISSING_PARTITION, insert, "Target table '%s' is partitioned but insert query does not specifty the partition", targetTable);
        }

        if (insert.isPartition() && targetPartitionNames.isEmpty()) {
            throw new SemanticException(MISSING_PARTITION, insert, "Target table '%s' is not partitioned but insert query speciftys the partition", targetTable);
        }

        HashMap<String, String> partitionKeyValue = new HashMap<String, String>();
        HashMap<String, String> partitionTypes = new HashMap<String, String>();
        LinkedHashMap<String, String> partitionKeyValueInorder = new LinkedHashMap<String, String>();

        if (insert.isPartition()) {
            dynamicPartition = analyzePartitionElements(insert, targetTable, partitionKeyValue, partitionTypes);
        }
        if (partitionKeyValue.size() != targetPartitionNames.size()) {
            throw new SemanticException(MISMATCHED_PARTITION_NAME, insert, "Insert query has mismatched partition names", targetTable);
        }
        else {
            int index = 0;
            for (Iterator<String> it = targetPartitionNames.iterator(); it.hasNext(); ) {
                String partitionName = it.next();
                if (!partitionKeyValue.containsKey(partitionName)) {
                    throw new SemanticException(MISMATCHED_PARTITION_NAME, insert, "Insert query has mismatched partition names", targetTable);
                }

                if (!dynamicPartition) {
                    String targetPartitionType = targetPartitionTypes.get(index++).getTypeSignature().toString();
                    String insertPartitionType = partitionTypes.get(partitionName);
                    if (!insertPartitionType.equalsIgnoreCase(targetPartitionType)) {
                        throw new SemanticException(INVALID_PARTITION_VALUE,
                                insert, "Insert query has invalid partition value, "
                                        + "partition " + partitionName
                                        + " should be of type "
                                        + targetPartitionType + " but is of type "
                                        + insertPartitionType, targetTable);
                    }
                }
                // reorder the partitionKeyValue as the order of select query order
                partitionKeyValueInorder.put(partitionName, partitionKeyValue.get(partitionName));
            }
        }
        analysis.setInsertOption(new InsertOption(insert.isOverwrite(), insert.isPartition(), dynamicPartition, partitionKeyValueInorder));
    }

    private boolean analyzePartitionElements(Insert insert, QualifiedTableName targetTable, HashMap<String, String> partitionKeyValue, HashMap<String, String> partitionTypes)
    {
        boolean dynamicPartition = false;
        for (PartitionElement element : insert.getPartitionElements()) {
            String partitionName = element.getName();
            String partitionValue = "";
            String partitionType = "";
            if (!element.getValue().isPresent()) {
                dynamicPartition = true;
                partitionTypes.put(partitionName, partitionType);
                partitionKeyValue.put(partitionName, partitionValue);
                continue;
            }
            Expression exp = element.getValue().get();

            if (partitionKeyValue.containsKey(partitionName)) {
                throw new SemanticException(DUPLICATE_PARTITION_NAME, insert, "Insert query has duplicate partition names", targetTable);
            }

            if (exp instanceof BooleanLiteral) {
                partitionType = "boolean";
                partitionValue = String.valueOf(((BooleanLiteral) exp).getValue());
            }
            else if (exp instanceof DoubleLiteral) {
                partitionType = "double";
                partitionValue = String.valueOf(((DoubleLiteral) exp).getValue());
            }
            else if (exp instanceof LongLiteral) {
                partitionType = "bigint";
                partitionValue = String.valueOf(((LongLiteral) exp).getValue());
            }
            else if (exp instanceof StringLiteral) {
                partitionType = "varchar";
                partitionValue = ((StringLiteral) exp).getValue();
            }
            else if (exp instanceof TimeLiteral) {
                partitionType = "time";
                long value = DateTimeUtils.parseTime(session.getTimeZoneKey(), ((TimeLiteral) exp).getValue());
                partitionValue = new java.text.SimpleDateFormat("HH:mm:ss.SSS").format(new Date(value));
            }
            else if (exp instanceof TimestampLiteral) {
                partitionType = "timestamp";
                long value = DateTimeUtils.parseTimestamp(session.getTimeZoneKey(), ((TimestampLiteral) exp).getValue());
                partitionValue = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(value));
            }
            else if (exp instanceof GenericLiteral) {
                GenericLiteral genericLiteral = (GenericLiteral) exp;
                partitionType = genericLiteral.getType();
                partitionValue = genericLiteral.getValue();
                if (!isPartitionTypeSupported(partitionType)) {
                    throw new SemanticException(UNSUPPORTED_PARTITION_TYPE, insert, "Unsupported partition type", targetTable);
                }
                if (partitionType.equalsIgnoreCase("time")) {
                    long value = DateTimeUtils.parseTime(session.getTimeZoneKey(), partitionValue);
                    partitionValue = new java.text.SimpleDateFormat("HH:mm:ss.SSS").format(new Date(value));
                }
                else if (partitionType.equalsIgnoreCase("timestamp")) {
                    long value = DateTimeUtils.parseTimestamp(session.getTimeZoneKey(), partitionValue);
                    partitionValue = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(value));
                }
            }
            else {
                throw new SemanticException(UNSUPPORTED_PARTITION_TYPE, insert, "Unsupported partition type", targetTable);
            }

            partitionTypes.put(partitionName, partitionType);
            partitionKeyValue.put(partitionName, partitionValue);
        }
        return dynamicPartition;
    }

Answer: private boolean isPartitionTypeSupported(String type)

<think>
The provided code ends with the closing brace of the private method analyzePartitionElements. In the original Presto StatementAnalyzer class, the next method defined after this is a helper that checks if a partition type is supported. Therefore, the next line is the method signature for that helper.
</think>
private static boolean isPartitionTypeSupported(String type)