diff --git a/.github/workflows/check_make_parser.yml b/.github/workflows/check_make_parser.yml index 2cb6ecb9536..18860b94dbf 100644 --- a/.github/workflows/check_make_parser.yml +++ b/.github/workflows/check_make_parser.yml @@ -16,23 +16,14 @@ jobs: run: | echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range - # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 - - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file - run: | - echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! - - name: Check out code uses: actions/checkout@v2 - name: Get dependencies run: | sudo apt-get update - sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget - sudo service mysql stop + sudo apt-get install -y make unzip g++ etcd curl git wget sudo service etcd stop - sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ - sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld go mod download - name: Run make minimaltools diff --git a/.github/workflows/check_make_sizegen.yml b/.github/workflows/check_make_sizegen.yml index bbb085a50f5..24e08c996f4 100644 --- a/.github/workflows/check_make_sizegen.yml +++ b/.github/workflows/check_make_sizegen.yml @@ -16,23 +16,14 @@ jobs: run: | echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range - # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 - - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file - run: | - echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! - - name: Check out code uses: actions/checkout@v2 - name: Get dependencies run: | sudo apt-get update - sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget - sudo service mysql stop + sudo apt-get install -y make unzip g++ etcd curl git wget sudo service etcd stop - sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ - sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld go mod download - name: Run make minimaltools diff --git a/.github/workflows/check_make_visitor.yml b/.github/workflows/check_make_visitor.yml index 3269390b7e9..2d0f0405a65 100644 --- a/.github/workflows/check_make_visitor.yml +++ b/.github/workflows/check_make_visitor.yml @@ -16,23 +16,14 @@ jobs: run: | echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range - # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 - - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file - run: | - echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! - - name: Check out code uses: actions/checkout@v2 - name: Get dependencies run: | sudo apt-get update - sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget - sudo service mysql stop + sudo apt-get install -y make unzip g++ etcd curl git wget sudo service etcd stop - sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ - sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld go mod download - name: Run make minimaltools diff --git a/.github/workflows/cluster_endtoend_mysql80.yml b/.github/workflows/cluster_endtoend_mysql80.yml new file mode 100644 index 00000000000..3d2386be2c2 --- /dev/null +++ b/.github/workflows/cluster_endtoend_mysql80.yml @@ -0,0 +1,71 @@ +# DO NOT MODIFY: THIS FILE IS GENERATED USING "make generate_ci_workflows" + +name: Cluster (mysql80) +on: [push, pull_request] +jobs: + + build: + name: Run endtoend tests on Cluster (mysql80) + runs-on: ubuntu-20.04 + + steps: + - name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: 1.16 + + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + + - name: Check out code + uses: actions/checkout@v2 + + - name: Get dependencies + run: | + + sudo DEBIAN_FRONTEND="noninteractive" apt-get update + + # Uninstall any previously installed MySQL first + sudo systemctl stop apparmor + sudo DEBIAN_FRONTEND="noninteractive" apt-get remove -y --purge mysql-server mysql-client mysql-common + sudo apt-get -y autoremove + sudo apt-get -y autoclean + sudo deluser mysql + sudo rm -rf /var/lib/mysql + sudo rm -rf /etc/mysql + + # Install mysql80 + wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.20-1_all.deb + echo mysql-apt-config mysql-apt-config/select-server select mysql-8.0 | sudo debconf-set-selections + sudo DEBIAN_FRONTEND="noninteractive" dpkg -i mysql-apt-config* + sudo apt-get update + sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y mysql-server mysql-client + + # Install everything else we need, and configure + sudo apt-get install -y make unzip g++ etcd curl git wget eatmydata + sudo service mysql stop + sudo service etcd stop + sudo bash -c "echo '/usr/sbin/mysqld { }' > /etc/apparmor.d/usr.sbin.mysqld" # https://bugs.launchpad.net/ubuntu/+source/mariadb-10.1/+bug/1806263 + sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ + sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld || echo "could not remove mysqld profile" + + go mod download + + wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb + sudo apt-get install -y gnupg2 + sudo dpkg -i percona-release_latest.$(lsb_release -sc)_all.deb + sudo apt-get update + sudo apt-get install percona-xtrabackup-24 + + - name: Run cluster endtoend test + timeout-minutes: 30 + run: | + source build.env + eatmydata -- go run test.go -docker=false -print-log -follow -shard mysql80 diff --git a/.github/workflows/cluster_endtoend_upgrade.yml b/.github/workflows/cluster_endtoend_upgrade.yml index 13ba77b7363..8cf33424706 100644 --- a/.github/workflows/cluster_endtoend_upgrade.yml +++ b/.github/workflows/cluster_endtoend_upgrade.yml @@ -32,12 +32,32 @@ jobs: run: | # This prepares general purpose binary dependencies # as well as v9.0.0 specific go modules + + sudo DEBIAN_FRONTEND="noninteractive" apt-get update + + # Uninstall any previously installed MySQL first + sudo systemctl stop apparmor + sudo DEBIAN_FRONTEND="noninteractive" apt-get remove -y --purge mysql-server mysql-client mysql-common + sudo apt-get -y autoremove + sudo apt-get -y autoclean + sudo deluser mysql + sudo rm -rf /var/lib/mysql + sudo rm -rf /etc/mysql + + # Install mysql80 + wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.20-1_all.deb + echo mysql-apt-config mysql-apt-config/select-server select mysql-8.0 | sudo debconf-set-selections + sudo DEBIAN_FRONTEND="noninteractive" dpkg -i mysql-apt-config* sudo apt-get update - sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget eatmydata + sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y mysql-server mysql-client + + # Install everything else we need, and configure + sudo apt-get install -y make unzip g++ etcd curl git wget eatmydata sudo service mysql stop sudo service etcd stop + sudo bash -c "echo '/usr/sbin/mysqld { }' > /etc/apparmor.d/usr.sbin.mysqld" # https://bugs.launchpad.net/ubuntu/+source/mariadb-10.1/+bug/1806263 sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ - sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld + sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld || echo "could not remove mysqld profile" go mod download wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb diff --git a/.github/workflows/cluster_endtoend_vstream_failover.yml b/.github/workflows/cluster_endtoend_vstream_failover.yml new file mode 100644 index 00000000000..087fd039cd2 --- /dev/null +++ b/.github/workflows/cluster_endtoend_vstream_failover.yml @@ -0,0 +1,53 @@ +# DO NOT MODIFY: THIS FILE IS GENERATED USING "make generate_ci_workflows" + +name: Cluster (vstream_failover) +on: [push, pull_request] +concurrency: + group: format('{0}-{1}', ${{ github.ref }}, 'Cluster (vstream_failover)') + cancel-in-progress: true + +jobs: + build: + name: Run endtoend tests on Cluster (vstream_failover) + runs-on: ubuntu-18.04 + + steps: + - name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: 1.16 + + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + + - name: Check out code + uses: actions/checkout@v2 + + - name: Get dependencies + run: | + sudo apt-get update + sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget eatmydata + sudo service mysql stop + sudo service etcd stop + sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ + sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld + go mod download + + wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb + sudo apt-get install -y gnupg2 + sudo dpkg -i percona-release_latest.$(lsb_release -sc)_all.deb + sudo apt-get update + sudo apt-get install percona-xtrabackup-24 + + - name: Run cluster endtoend test + timeout-minutes: 30 + run: | + source build.env + eatmydata -- go run test.go -docker=false -print-log -follow -shard vstream_failover diff --git a/.github/workflows/cluster_endtoend_vstream_stoponreshard_false.yml b/.github/workflows/cluster_endtoend_vstream_stoponreshard_false.yml new file mode 100644 index 00000000000..701d7048050 --- /dev/null +++ b/.github/workflows/cluster_endtoend_vstream_stoponreshard_false.yml @@ -0,0 +1,53 @@ +# DO NOT MODIFY: THIS FILE IS GENERATED USING "make generate_ci_workflows" + +name: Cluster (vstream_stoponreshard_false) +on: [push, pull_request] +concurrency: + group: format('{0}-{1}', ${{ github.ref }}, 'Cluster (vstream_stoponreshard_false)') + cancel-in-progress: true + +jobs: + build: + name: Run endtoend tests on Cluster (vstream_stoponreshard_false) + runs-on: ubuntu-18.04 + + steps: + - name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: 1.16 + + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + + - name: Check out code + uses: actions/checkout@v2 + + - name: Get dependencies + run: | + sudo apt-get update + sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget eatmydata + sudo service mysql stop + sudo service etcd stop + sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ + sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld + go mod download + + wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb + sudo apt-get install -y gnupg2 + sudo dpkg -i percona-release_latest.$(lsb_release -sc)_all.deb + sudo apt-get update + sudo apt-get install percona-xtrabackup-24 + + - name: Run cluster endtoend test + timeout-minutes: 30 + run: | + source build.env + eatmydata -- go run test.go -docker=false -print-log -follow -shard vstream_stoponreshard_false diff --git a/.github/workflows/cluster_endtoend_vstream_stoponreshard_true.yml b/.github/workflows/cluster_endtoend_vstream_stoponreshard_true.yml new file mode 100644 index 00000000000..4302908c726 --- /dev/null +++ b/.github/workflows/cluster_endtoend_vstream_stoponreshard_true.yml @@ -0,0 +1,53 @@ +# DO NOT MODIFY: THIS FILE IS GENERATED USING "make generate_ci_workflows" + +name: Cluster (vstream_stoponreshard_true) +on: [push, pull_request] +concurrency: + group: format('{0}-{1}', ${{ github.ref }}, 'Cluster (vstream_stoponreshard_true)') + cancel-in-progress: true + +jobs: + build: + name: Run endtoend tests on Cluster (vstream_stoponreshard_true) + runs-on: ubuntu-18.04 + + steps: + - name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: 1.16 + + - name: Tune the OS + run: | + echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range + + # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 + - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file + run: | + echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts + # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! + + - name: Check out code + uses: actions/checkout@v2 + + - name: Get dependencies + run: | + sudo apt-get update + sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget eatmydata + sudo service mysql stop + sudo service etcd stop + sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ + sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld + go mod download + + wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb + sudo apt-get install -y gnupg2 + sudo dpkg -i percona-release_latest.$(lsb_release -sc)_all.deb + sudo apt-get update + sudo apt-get install percona-xtrabackup-24 + + - name: Run cluster endtoend test + timeout-minutes: 30 + run: | + source build.env + eatmydata -- go run test.go -docker=false -print-log -follow -shard vstream_stoponreshard_true diff --git a/.github/workflows/e2e_race.yml b/.github/workflows/e2e_race.yml index 65b3c246425..6c9901bfdc3 100644 --- a/.github/workflows/e2e_race.yml +++ b/.github/workflows/e2e_race.yml @@ -16,23 +16,38 @@ jobs: run: | echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range - # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 - - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file - run: | - echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! - - name: Check out code uses: actions/checkout@v2 - name: Get dependencies run: | + + sudo DEBIAN_FRONTEND="noninteractive" apt-get update + + # Uninstall any previously installed MySQL first + sudo systemctl stop apparmor + sudo DEBIAN_FRONTEND="noninteractive" apt-get remove -y --purge mysql-server mysql-client mysql-common + sudo apt-get -y autoremove + sudo apt-get -y autoclean + sudo deluser mysql + sudo rm -rf /var/lib/mysql + sudo rm -rf /etc/mysql + + # Install mysql80 + wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.20-1_all.deb + echo mysql-apt-config mysql-apt-config/select-server select mysql-8.0 | sudo debconf-set-selections + sudo DEBIAN_FRONTEND="noninteractive" dpkg -i mysql-apt-config* sudo apt-get update - sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget + sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y mysql-server mysql-client + + # Install everything else we need, and configure + sudo apt-get install -y make unzip g++ etcd curl git wget eatmydata sudo service mysql stop sudo service etcd stop + sudo bash -c "echo '/usr/sbin/mysqld { }' > /etc/apparmor.d/usr.sbin.mysqld" # https://bugs.launchpad.net/ubuntu/+source/mariadb-10.1/+bug/1806263 sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ - sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld + sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld || echo "could not remove mysqld profile" + go mod download - name: Run make minimaltools diff --git a/.github/workflows/legacy_local_example.yml b/.github/workflows/legacy_local_example.yml index 3eb66555d6a..b7c2f8145f2 100644 --- a/.github/workflows/legacy_local_example.yml +++ b/.github/workflows/legacy_local_example.yml @@ -21,24 +21,38 @@ jobs: run: | echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range - # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 - - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file - run: | - echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! - - name: Check out code uses: actions/checkout@v2 - name: Get dependencies run: | if [ ${{matrix.os}} = "ubuntu-latest" ]; then + + sudo DEBIAN_FRONTEND="noninteractive" apt-get update + + # Uninstall any previously installed MySQL first + sudo systemctl stop apparmor + sudo DEBIAN_FRONTEND="noninteractive" apt-get remove -y --purge mysql-server mysql-client mysql-common + sudo apt-get -y autoremove + sudo apt-get -y autoclean + sudo deluser mysql + sudo rm -rf /var/lib/mysql + sudo rm -rf /etc/mysql + + # Install mysql80 + wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.20-1_all.deb + echo mysql-apt-config mysql-apt-config/select-server select mysql-8.0 | sudo debconf-set-selections + sudo DEBIAN_FRONTEND="noninteractive" dpkg -i mysql-apt-config* sudo apt-get update - sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget eatmydata + sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y mysql-server mysql-client + + # Install everything else we need, and configure + sudo apt-get install -y make unzip g++ etcd curl git wget eatmydata sudo service mysql stop sudo service etcd stop + sudo bash -c "echo '/usr/sbin/mysqld { }' > /etc/apparmor.d/usr.sbin.mysqld" # https://bugs.launchpad.net/ubuntu/+source/mariadb-10.1/+bug/1806263 sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ - sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld + sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld || echo "could not remove mysqld profile" elif [ ${{matrix.os}} = "macos-latest" ]; then brew install mysql@5.7 make unzip etcd curl git wget fi diff --git a/.github/workflows/local_example.yml b/.github/workflows/local_example.yml index ec93726eaa7..e9e1430704a 100644 --- a/.github/workflows/local_example.yml +++ b/.github/workflows/local_example.yml @@ -21,24 +21,38 @@ jobs: run: | echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range - # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 - - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file - run: | - echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! - - name: Check out code uses: actions/checkout@v2 - name: Get dependencies run: | if [ ${{matrix.os}} = "ubuntu-latest" ]; then + + sudo DEBIAN_FRONTEND="noninteractive" apt-get update + + # Uninstall any previously installed MySQL first + sudo systemctl stop apparmor + sudo DEBIAN_FRONTEND="noninteractive" apt-get remove -y --purge mysql-server mysql-client mysql-common + sudo apt-get -y autoremove + sudo apt-get -y autoclean + sudo deluser mysql + sudo rm -rf /var/lib/mysql + sudo rm -rf /etc/mysql + + # Install mysql80 + wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.20-1_all.deb + echo mysql-apt-config mysql-apt-config/select-server select mysql-8.0 | sudo debconf-set-selections + sudo DEBIAN_FRONTEND="noninteractive" dpkg -i mysql-apt-config* sudo apt-get update - sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget eatmydata + sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y mysql-server mysql-client + + # Install everything else we need, and configure + sudo apt-get install -y make unzip g++ etcd curl git wget eatmydata sudo service mysql stop sudo service etcd stop + sudo bash -c "echo '/usr/sbin/mysqld { }' > /etc/apparmor.d/usr.sbin.mysqld" # https://bugs.launchpad.net/ubuntu/+source/mariadb-10.1/+bug/1806263 sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ - sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld + sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld || echo "could not remove mysqld profile" elif [ ${{matrix.os}} = "macos-latest" ]; then brew install mysql@5.7 make unzip etcd curl git wget fi diff --git a/.github/workflows/region_example.yml b/.github/workflows/region_example.yml index 6bb3ce83187..a50784718d0 100644 --- a/.github/workflows/region_example.yml +++ b/.github/workflows/region_example.yml @@ -21,24 +21,38 @@ jobs: run: | echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range - # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185 - - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file - run: | - echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED! - - name: Check out code uses: actions/checkout@v2 - name: Get dependencies run: | if [ ${{matrix.os}} = "ubuntu-latest" ]; then + + sudo DEBIAN_FRONTEND="noninteractive" apt-get update + + # Uninstall any previously installed MySQL first + sudo systemctl stop apparmor + sudo DEBIAN_FRONTEND="noninteractive" apt-get remove -y --purge mysql-server mysql-client mysql-common + sudo apt-get -y autoremove + sudo apt-get -y autoclean + sudo deluser mysql + sudo rm -rf /var/lib/mysql + sudo rm -rf /etc/mysql + + # Install mysql80 + wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.20-1_all.deb + echo mysql-apt-config mysql-apt-config/select-server select mysql-8.0 | sudo debconf-set-selections + sudo DEBIAN_FRONTEND="noninteractive" dpkg -i mysql-apt-config* sudo apt-get update - sudo apt-get install -y mysql-server mysql-client make unzip g++ etcd curl git wget eatmydata + sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y mysql-server mysql-client + + # Install everything else we need, and configure + sudo apt-get install -y make unzip g++ etcd curl git wget eatmydata sudo service mysql stop sudo service etcd stop + sudo bash -c "echo '/usr/sbin/mysqld { }' > /etc/apparmor.d/usr.sbin.mysqld" # https://bugs.launchpad.net/ubuntu/+source/mariadb-10.1/+bug/1806263 sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/ - sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld + sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld || echo "could not remove mysqld profile" elif [ ${{matrix.os}} = "macos-latest" ]; then brew install mysql@5.7 make unzip etcd curl git wget fi diff --git a/Makefile b/Makefile index d5494494339..91120cfa11b 100644 --- a/Makefile +++ b/Makefile @@ -353,6 +353,7 @@ endif git add --all git commit -n -s -m "Release commit for $(RELEASE_VERSION)" git tag -m Version\ $(RELEASE_VERSION) v$(RELEASE_VERSION) + git tag -a v$(GODOC_RELEASE_VERSION) -m "Tagging $(RELEASE_VERSION) also as $(GODOC_RELEASE_VERSION) for godoc/go modules" cd java && mvn versions:set -DnewVersion=$(DEV_VERSION) echo package servenv > go/vt/servenv/version.go echo >> go/vt/servenv/version.go @@ -360,8 +361,8 @@ endif git add --all git commit -n -s -m "Back to dev mode" echo "Release preparations successful" - echo "A git tag was created, you can push it with:" - echo " git push upstream v$(RELEASE_VERSION)" + echo "Two git tags were created, you can push them with:" + echo " git push upstream v$(RELEASE_VERSION) && git push upstream v$(GODOC_RELEASE_VERSION)" echo "The git branch has also been updated. You need to push it and get it merged" tools: diff --git a/doc/releasenotes/11_0_0_release_notes.md b/doc/releasenotes/11_0_0_release_notes.md index a50e4a7469f..9b2d1458446 100644 --- a/doc/releasenotes/11_0_0_release_notes.md +++ b/doc/releasenotes/11_0_0_release_notes.md @@ -1,5 +1,14 @@ This release complies with VEP-3 which removes the upgrade order requirement. Components can be upgraded in any order. It is recommended that the upgrade order should still be followed if possible, except to canary test the new version of VTGate before upgrading the rest of the components. +## Known Issues + +- A critical vulnerability [CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228) in the Apache Log4j logging library was disclosed on Dec 9 2021. + The project provided release `2.15.0` with a patch that mitigates the impact of this CVE. It was quickly found that the initial patch was insufficient, and additional CVEs + [CVE-2021-45046](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-45046) and [CVE-2021-44832](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44832) followed. + These have been fixed in release `2.17.1`. This release of Vitess, `v11.0.0`, uses a version of Log4j below `2.17.1`, for this reason, we encourage you to use version `v11.0.4` instead, to benefit from the vulnerability patches. + +- An issue where the value of the `-force` flag is used instead of `-keep_data` flag's value in v2 vreplication workflows (#9174) is known to be present in this release. A workaround is available in the description of issue #9174. + ## Bug fixes ### Build/CI * update moby/term to fix darwin build issue #7787 @@ -38,22 +47,31 @@ This release complies with VEP-3 which removes the upgrade order requirement. Co * PRIMARY in index hint list for master #8160 * Signed int parse #8189 * Delete table reference alias support #8393 + * Fix for function calls in DEFAULT value of CREATE TABLE statement in release-11.0 #8476 + * Backport: Fixing multiple issues related to onlineddl/lifecycle #8517 + * boolean values should not be parenthesised in default clause - release 11 #8531 ### VReplication * VDiff: Use byte compare if weight_string() returns null for either source or target #7696 * Rowlog: Update rowlog for the API change made for the vstream skew alignment feature #7809 - * VReplication: Pad binlog values for binary() columns to match the value returned by mysql selects #7969 + * Pad binlog values for binary() columns to match the value returned by mysql selects #7969 * Change vreplication error metric name to start with a string to pass prometheus validations #7983 * Pass the provided keyspace through to `UpdateDisableQueryService` rather than hard-coding the sourceKeyspace #8020 - * vreplication: fix vreplication timing metrics #8024 + * Fix vreplication timing metrics #8024 * Switchwrites: error if no tablets available on target for reverse replication #8142 - * VReplication: remove noisy vexec logs #8144 + * Remove noisy vexec logs #8144 * VReplicationExec: don't create new stats objects on a select #8166 * Binlog JSON Parser: handle inline types correctly for large documents #8187 * Schema Tracking Flaky Test: Ignore unrelated gtid progress events #8283 * Adds padding to keyrange comparison #8296 * VReplication Reverse Workflows: add keyspace scope to vindex while creating reverse vreplication streams #8385 + * OnlineDDL/Vreplication stress test: investigating failures #8390 + * Ignore SBR statements from pt-table-checksum #8396 + * Return from throttler goroutine if context is cancelled to prevent goroutine leaks #8489 + * VDiff: Add BIT datatype to list of byte comparable types #8401 + * Fix excessive VReplication logging to file and db #8521 + ### VTAdmin * Add missing return in `vtctld-*` DSN case, and log any flag that gets ignored #7872 * [vtadmin-web] Do not parse numbers/booleans in URL query parameters by default #8100 @@ -104,6 +122,8 @@ This release complies with VEP-3 which removes the upgrade order requirement. Co ### vttestserver * docker/vttestserver: Set max_connections in default-fast.cnf at container build time #7810 ## Documentation +### Cluster management + * Enhance k8stopo flag documentation #8458 ### Build/CI * Update version for latest snapshot #7801 * v10 GA Release Notes #7964 @@ -198,14 +218,18 @@ This release complies with VEP-3 which removes the upgrade order requirement. Co * Gen4: expand star in projection list #8325 * gen4: Fail all queries not handled well by gen4 #8359 * Gen4 fail more2 #8382 + * SHOW VITESS_MIGRATION '...' LOGS, retain logs for 24 hours #8532 + * [11.0] query serving to continue when topo server restarts #8533 + * [11.0] Disable allowing set statements on system settings by default #8540 ### VReplication + * Change local example to use v2 vreplication flows and make v2 flows as the default #8527 * Use Dba user when Vexec is runAsAdmin #7731 - * VReplication: add table for logging stream errors, state changes and key workflow steps #7831 + * Add table for logging stream errors, state changes and key workflow steps #7831 * Fix some static check warning #7960 * VSchema Validation on ReshardWorkflow Creation #7977 - * VReplication: tracking `rows_copied` #7980 + * Tracking `rows_copied` #7980 * Vdiff formatting improvements #8079 - * VReplication: ignore generated columns in workflows #8129 + * Ignore generated columns in workflows #8129 * VReplication Copy Phase: Increase default replica lag tolerance. Also make it and copy timeout modifiable via flags #8130 * Materialize: Add additional comparison operators in Materialize and fix bug where they not applied for sharded keyspaces #8247 * Copy Phase: turn on OptimizeInserts by default #8248 @@ -218,6 +242,8 @@ This release complies with VEP-3 which removes the upgrade order requirement. Co * Online DDL/Vreplication suite: fix test for no shared UK #8334 * Online DDL/VReplication: support DROP+ADD column of same name #8337 * Online DDL/VReplication test suite: support ENUM as part of PRIMARY KEY #8345 + * Change local example to use v2 vreplication flows #8527 + * Tablet Picker: add metric to record lack of available tablets #8403 ### VTAdmin * [vtadmin-web] Add useSyncedURLParam hook to persist filter parameter in the URL #7857 * [vtadmin-web] Display more data on /gates view and add filtering #7876 @@ -290,7 +316,8 @@ This release complies with VEP-3 which removes the upgrade order requirement. Co * [wrangler|workflow] Extract `workflowState` and `workflowType` out to `package workflow` #7967 * [wrangler|workflow] extract `*wrangler.streamMigrater` to `workflow.StreamMigrator` #8008 * [workflow] Migrate `getCellsWith{Shard,Table}ReadsSwitched`, `TrafficSwitchDirection` and `TableRemovalType` to package workflow #8190 - * [workflow] Cleanup wrangler wrappers, migrate `checkIfJournalExistsOnTablet` to package workflow #8193 + * [workflow] Cleanup wrangler wrappers, migrate `checkIfJournalExistsOnTablet` to package workflow #8193 + * Backports of #8403 #8483 #8489 #8401 #8521 #8396 from main into release 11.0 #8536 ### VTAdmin * [vtadmin-api] Replace magic numbers with `net/http` constants #8127 * [vtadmin-web] Move single-entity view components into subfolders #8202 @@ -330,10 +357,10 @@ This release complies with VEP-3 which removes the upgrade order requirement. Co * vttablet: stream consolidation #7752 * perf: optimize bind var generation #7828 ### VReplication - * VReplication: optimize the catchup phases by filtering out rows which not within range of copied pks during inserts #7708 - * VReplication: ability to compress gtid when stored in _vt.vreplication's pos column #7877 - * vreplication: performance & benchmarks (table copying) #7881 - * vreplication: dynamic packet sizing #7933 + * Optimize the catchup phases by filtering out rows which not within range of copied pks during inserts #7708 + * Ability to compress gtid when stored in _vt.vreplication's pos column #7877 + * Performance & benchmarks (table copying) #7881 + * Dynamic packet sizing #7933 * perf: vreplication client CPU usage #7951 * VDIff: fix performance regression introduced by progress logging #8016 * proto: Generate faster code using vtprotobuf #8173 @@ -369,6 +396,6 @@ This release complies with VEP-3 which removes the upgrade order requirement. Co * Make timestamp authoritative for master information #8381 -The release includes 1041 commits (excluding merges) +The release includes 1080 commits (excluding merges) -Thanks to all our contributors: @AdamKorcz, @GuptaManan100, @Hellcatlk, @Johnny-Three, @acharisshopify, @ajm188, @alexrs, @aquarapid, @askdba, @deepthi, @dependabot[bot], @doeg, @dyv, @enisoc, @frouioui, @gedgar, @guidoiaquinti, @harshit-gangal, @hkdsun, @idvoretskyi, @kirs, @mcronce, @narcsfz, @noxiouz, @rafael, @rohit-nayak-ps, @setassociative, @shlomi-noach, @systay, @tokikanno, @vmg, @wangmeng99, @yangxuanjia, @zhangshj-inspur +Thanks to all our contributors: @AdamKorcz, @GuptaManan100, @Hellcatlk, @Johnny-Three, @acharisshopify, @ajm188, @alexrs, @aquarapid, @askdba, @deepthi, @doeg, @dyv, @enisoc, @frouioui, @gedgar, @guidoiaquinti, @harshit-gangal, @hkdsun, @idvoretskyi, @jmoldow, @kirs, @mcronce, @narcsfz, @noxiouz, @rafael, @rohit-nayak-ps, @setassociative, @shlomi-noach, @systay, @tokikanno, @vmg, @wangmeng99, @yangxuanjia, @zhangshj-inspur diff --git a/doc/releasenotes/11_0_1_release_notes.md b/doc/releasenotes/11_0_1_release_notes.md new file mode 100644 index 00000000000..77c9b4acd1e --- /dev/null +++ b/doc/releasenotes/11_0_1_release_notes.md @@ -0,0 +1,27 @@ +## Known Issues + +- A critical vulnerability [CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228) in the Apache Log4j logging library was disclosed on Dec 9 2021. + The project provided release `2.15.0` with a patch that mitigates the impact of this CVE. It was quickly found that the initial patch was insufficient, and additional CVEs + [CVE-2021-45046](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-45046) and [CVE-2021-44832](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44832) followed. + These have been fixed in release `2.17.1`. This release of Vitess, `v11.0.1`, uses a version of Log4j below `2.17.1`, for this reason, we encourage you to use version `v11.0.4` instead, to benefit from the vulnerability patches. + +- An issue where the value of the `-force` flag is used instead of `-keep_data` flag's value in v2 vreplication workflows (#9174) is known to be present in this release. A workaround is available in the description of issue #9174. + + +## Bug fixes +### Cluster management + * Port #8422 to 11.0 branch #8744 +### Query Serving + * Handle subquery merging with references correctly #8661 + * onlineddl Executor: build schema with DBA user #8667 + * Backport to 11: Fixing a panic in vtgate with OLAP mode #8746 + * Backport into 11: default to primary tablet if not set in VStream api #8766 +### VReplication + * Refresh SrvVSchema after an ExternalizeVindex: was missing #8669 +## CI/Build +### Build/CI + * Vitess Release 11.0.0 #8549 + * Backport to 11: Updated Makefile do_release script to include godoc steps #8787 + +The release includes 18 commits (excluding merges) +Thanks to all our contributors: @aquarapid, @askdba, @frouioui, @harshit-gangal, @rohit-nayak-ps, @shlomi-noach, @systay diff --git a/doc/releasenotes/11_0_2_release_notes.md b/doc/releasenotes/11_0_2_release_notes.md new file mode 100644 index 00000000000..cc079f27566 --- /dev/null +++ b/doc/releasenotes/11_0_2_release_notes.md @@ -0,0 +1,31 @@ +# Release of Vitess v11.0.2 +## Announcement + +This patch is providing an update regarding the Apache Log4j security vulnerability (CVE-2021-44228) (#9364), along with a few bug fixes. + +## Known Issues + +- A critical vulnerability [CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228) in the Apache Log4j logging library was disclosed on Dec 9 2021. + The project provided release `2.15.0` with a patch that mitigates the impact of this CVE. It was quickly found that the initial patch was insufficient, and additional CVEs + [CVE-2021-45046](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-45046) and [CVE-2021-44832](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44832) followed. + These have been fixed in release `2.17.1`. This release of Vitess, `v11.0.2`, uses a version of Log4j below `2.17.1`, for this reason, we encourage you to use version `v11.0.4` instead, to benefit from the vulnerability patches. + +- An issue where the value of the `-force` flag is used instead of `-keep_data` flag's value in v2 vreplication workflows (#9174) is known to be present in this release. A workaround is available in the description of issue #9174. + +------------ +## Changelog + +### Bug fixes +#### VReplication +* Fix how we identify MySQL generated columns #8796 +### CI/Build +#### Build/CI +* CI: ubuntu-latest now has MySQL 8.0.26, let us override it with latest 8.0.x #9374 +### Internal Cleanup +#### Java +* build(deps): bump log4j-api from 2.13.3 to 2.15.0 in /java #9364 + + +The release includes 7 commits (excluding merges) + +Thanks to all our contributors: @askdba, @deepthi, @systay, @tokikanno \ No newline at end of file diff --git a/doc/releasenotes/11_0_2_summary.md b/doc/releasenotes/11_0_2_summary.md new file mode 100644 index 00000000000..248b19c7d18 --- /dev/null +++ b/doc/releasenotes/11_0_2_summary.md @@ -0,0 +1,12 @@ +## Major Changes + +This patch is providing an update regarding the Apache Log4j security vulnerability (CVE-2021-44228) (#9364), along with a few bug fixes. + +## Known Issues + +- A critical vulnerability [CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228) in the Apache Log4j logging library was disclosed on Dec 9 2021. + The project provided release `2.15.0` with a patch that mitigates the impact of this CVE. It was quickly found that the initial patch was insufficient, and additional CVEs + [CVE-2021-45046](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-45046) and [CVE-2021-44832](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44832) followed. + These have been fixed in release `2.17.1`. This release of Vitess, `v11.0.2`, uses a version of Log4j below `2.17.1`, for this reason, we encourage you to use version `v11.0.4` instead, to benefit from the vulnerability patches. + +- An issue where the value of the `-force` flag is used instead of `-keep_data` flag's value in v2 vreplication workflows (#9174) is known to be present in this release. A workaround is available in the description of issue #9174. diff --git a/doc/releasenotes/11_0_3_release_notes.md b/doc/releasenotes/11_0_3_release_notes.md new file mode 100644 index 00000000000..96f74b2987e --- /dev/null +++ b/doc/releasenotes/11_0_3_release_notes.md @@ -0,0 +1,27 @@ +# Release of Vitess v11.0.3 +## Announcement + +This patch is providing an update regarding the Apache Log4j security vulnerability (CVE-2021-45046) (#9395). + +## Known Issues + +- A critical vulnerability [CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228) in the Apache Log4j logging library was disclosed on Dec 9 2021. + The project provided release `2.15.0` with a patch that mitigates the impact of this CVE. It was quickly found that the initial patch was insufficient, and additional CVEs + [CVE-2021-45046](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-45046) and [CVE-2021-44832](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44832) followed. + These have been fixed in release `2.17.1`. This release of Vitess, `v11.0.3`, uses a version of Log4j below `2.17.1`, for this reason, we encourage you to use version `v11.0.4` instead, to benefit from the vulnerability patches. + +- An issue where the value of the `-force` flag is used instead of `-keep_data` flag's value in v2 vreplication workflows (#9174) is known to be present in this release. A workaround is available in the description of issue #9174. + +------------ +## Changelog + +### Dependabot +#### Java +* build(deps): bump log4j-core from 2.15.0 to 2.16.0 in /java #9395 +### Documentation +#### Examples +* change operator example to use v11.0.3 docker images #9403 + + +The release includes 3 commits (excluding merges) +Thanks to all our contributors: @frouioui \ No newline at end of file diff --git a/doc/releasenotes/11_0_3_summary.md b/doc/releasenotes/11_0_3_summary.md new file mode 100644 index 00000000000..af73528db91 --- /dev/null +++ b/doc/releasenotes/11_0_3_summary.md @@ -0,0 +1,12 @@ +## Major Changes + +This patch is providing an update regarding the Apache Log4j security vulnerability (CVE-2021-45046) (#9395). + +## Known Issues + +- A critical vulnerability [CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228) in the Apache Log4j logging library was disclosed on Dec 9 2021. + The project provided release `2.15.0` with a patch that mitigates the impact of this CVE. It was quickly found that the initial patch was insufficient, and additional CVEs + [CVE-2021-45046](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-45046) and [CVE-2021-44832](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44832) followed. + These have been fixed in release `2.17.1`. This release of Vitess, `v11.0.3`, uses a version of Log4j below `2.17.1`, for this reason, we encourage you to use version `v11.0.4` instead, to benefit from the vulnerability patches. + +- An issue where the value of the `-force` flag is used instead of `-keep_data` flag's value in v2 vreplication workflows (#9174) is known to be present in this release. A workaround is available in the description of issue #9174. diff --git a/doc/releasenotes/11_0_4_release_notes.md b/doc/releasenotes/11_0_4_release_notes.md new file mode 100644 index 00000000000..90222c96a66 --- /dev/null +++ b/doc/releasenotes/11_0_4_release_notes.md @@ -0,0 +1,19 @@ +# Release of Vitess v11.0.4 +## Announcement + +This patch is providing an update regarding the Apache Log4j security vulnerability ([CVE-2021-44832](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44832)) (#9464). + +## Known Issues + +- An issue where the value of the `-force` flag is used instead of `-keep_data` flag's value in v2 vreplication workflows (#9174) is known to be present in this release. A workaround is available in the description of issue #9174. + +------------ +## Changelog + +### Dependabot +#### Java +* build(deps): bump log4j-api from 2.16.0 to 2.17.1 in /java #9464 + +The release includes 6 commits (excluding merges) + +Thanks to all our contributors: @dbussink, @frouioui \ No newline at end of file diff --git a/doc/releasenotes/11_0_4_summary.md b/doc/releasenotes/11_0_4_summary.md new file mode 100644 index 00000000000..3ed0c070782 --- /dev/null +++ b/doc/releasenotes/11_0_4_summary.md @@ -0,0 +1,7 @@ +## Announcement + +This patch is providing an update regarding the Apache Log4j security vulnerability ([CVE-2021-44832](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44832)) (#9464). + +## Known Issues + +- An issue where the value of the `-force` flag is used instead of `-keep_data` flag's value in v2 vreplication workflows (#9174) is known to be present in this release. A workaround is available in the description of issue #9174. diff --git a/examples/local/202_move_tables.sh b/examples/local/202_move_tables.sh index 8bf69cf95dd..4cb25390e07 100755 --- a/examples/local/202_move_tables.sh +++ b/examples/local/202_move_tables.sh @@ -19,4 +19,4 @@ source ./env.sh -vtctlclient MoveTables -workflow=commerce2customer commerce customer '{"customer":{}, "corder":{}}' +vtctlclient MoveTables -source commerce -tables 'customer,corder' Create customer.commerce2customer diff --git a/examples/local/203_switch_reads.sh b/examples/local/203_switch_reads.sh index 93b4a31b76c..04f73c17f2c 100755 --- a/examples/local/203_switch_reads.sh +++ b/examples/local/203_switch_reads.sh @@ -19,5 +19,4 @@ source ./env.sh -vtctlclient SwitchReads -tablet_type=rdonly customer.commerce2customer -vtctlclient SwitchReads -tablet_type=replica customer.commerce2customer +vtctlclient MoveTables -tablet_types=rdonly,replica SwitchTraffic customer.commerce2customer diff --git a/examples/local/204_switch_writes.sh b/examples/local/204_switch_writes.sh index b2a6434ad17..b2d85708a33 100755 --- a/examples/local/204_switch_writes.sh +++ b/examples/local/204_switch_writes.sh @@ -19,4 +19,4 @@ source ./env.sh -vtctlclient SwitchWrites customer.commerce2customer +vtctlclient MoveTables -tablet_types=master SwitchTraffic customer.commerce2customer diff --git a/examples/local/205_clean_commerce.sh b/examples/local/205_clean_commerce.sh index 203464aa5fa..37824052d27 100755 --- a/examples/local/205_clean_commerce.sh +++ b/examples/local/205_clean_commerce.sh @@ -19,5 +19,5 @@ source ./env.sh -vtctlclient DropSources customer.commerce2customer +vtctlclient MoveTables Complete customer.commerce2customer diff --git a/examples/local/303_reshard.sh b/examples/local/303_reshard.sh index 2e980a8fee7..0334b256bef 100755 --- a/examples/local/303_reshard.sh +++ b/examples/local/303_reshard.sh @@ -19,4 +19,4 @@ source ./env.sh -vtctlclient Reshard customer.cust2cust '0' '-80,80-' +vtctlclient Reshard -source_shards '0' -target_shards '-80,80-' Create customer.cust2cust diff --git a/examples/local/304_switch_reads.sh b/examples/local/304_switch_reads.sh index 041d4206048..29f143a878f 100755 --- a/examples/local/304_switch_reads.sh +++ b/examples/local/304_switch_reads.sh @@ -18,5 +18,4 @@ source ./env.sh -vtctlclient SwitchReads -tablet_type=rdonly customer.cust2cust -vtctlclient SwitchReads -tablet_type=replica customer.cust2cust +vtctlclient Reshard -tablet_types=rdonly,replica SwitchTraffic customer.cust2cust diff --git a/examples/local/305_switch_writes.sh b/examples/local/305_switch_writes.sh index 94a276e3867..2f9c5ad7aa7 100755 --- a/examples/local/305_switch_writes.sh +++ b/examples/local/305_switch_writes.sh @@ -18,4 +18,4 @@ source ./env.sh -vtctlclient SwitchWrites customer.cust2cust +vtctlclient Reshard -tablet_types=master SwitchTraffic customer.cust2cust diff --git a/examples/local/306_down_shard_0.sh b/examples/local/306_down_shard_0.sh index 9b6a0ed8180..0d956553cd5 100755 --- a/examples/local/306_down_shard_0.sh +++ b/examples/local/306_down_shard_0.sh @@ -17,6 +17,8 @@ source ./env.sh +vtctlclient Reshard Complete customer.cust2cust + for i in 200 201 202; do CELL=zone1 TABLET_UID=$i ./scripts/vttablet-down.sh CELL=zone1 TABLET_UID=$i ./scripts/mysqlctl-down.sh diff --git a/examples/operator/101_initial_cluster.yaml b/examples/operator/101_initial_cluster.yaml index 8df5c19c8e1..4cb47c95342 100644 --- a/examples/operator/101_initial_cluster.yaml +++ b/examples/operator/101_initial_cluster.yaml @@ -8,12 +8,12 @@ metadata: name: example spec: images: - vtctld: vitess/lite:latest - vtgate: vitess/lite:latest - vttablet: vitess/lite:latest - vtbackup: vitess/lite:latest + vtctld: vitess/lite:v11.0.3 + vtgate: vitess/lite:v11.0.3 + vttablet: vitess/lite:v11.0.3 + vtbackup: vitess/lite:v11.0.3 mysqld: - mysql56Compatible: vitess/lite:latest + mysql56Compatible: vitess/lite:v11.0.3 mysqldExporter: prom/mysqld-exporter:v0.11.0 cells: - name: zone1 diff --git a/examples/operator/201_customer_tablets.yaml b/examples/operator/201_customer_tablets.yaml index 44938131139..d0567f74836 100644 --- a/examples/operator/201_customer_tablets.yaml +++ b/examples/operator/201_customer_tablets.yaml @@ -4,12 +4,12 @@ metadata: name: example spec: images: - vtctld: vitess/lite:latest - vtgate: vitess/lite:latest - vttablet: vitess/lite:latest - vtbackup: vitess/lite:latest + vtctld: vitess/lite:v11.0.3 + vtgate: vitess/lite:v11.0.3 + vttablet: vitess/lite:v11.0.3 + vtbackup: vitess/lite:v11.0.3 mysqld: - mysql56Compatible: vitess/lite:latest + mysql56Compatible: vitess/lite:v11.0.3 mysqldExporter: prom/mysqld-exporter:v0.11.0 cells: - name: zone1 diff --git a/examples/operator/302_new_shards.yaml b/examples/operator/302_new_shards.yaml index 2ea942bfdb4..5c48f36c1ea 100644 --- a/examples/operator/302_new_shards.yaml +++ b/examples/operator/302_new_shards.yaml @@ -4,12 +4,12 @@ metadata: name: example spec: images: - vtctld: vitess/lite:latest - vtgate: vitess/lite:latest - vttablet: vitess/lite:latest - vtbackup: vitess/lite:latest + vtctld: vitess/lite:v11.0.3 + vtgate: vitess/lite:v11.0.3 + vttablet: vitess/lite:v11.0.3 + vtbackup: vitess/lite:v11.0.3 mysqld: - mysql56Compatible: vitess/lite:latest + mysql56Compatible: vitess/lite:v11.0.3 mysqldExporter: prom/mysqld-exporter:v0.11.0 cells: - name: zone1 diff --git a/examples/operator/306_down_shard_0.yaml b/examples/operator/306_down_shard_0.yaml index bcf56db7699..a077e26521e 100644 --- a/examples/operator/306_down_shard_0.yaml +++ b/examples/operator/306_down_shard_0.yaml @@ -4,12 +4,12 @@ metadata: name: example spec: images: - vtctld: vitess/lite:latest - vtgate: vitess/lite:latest - vttablet: vitess/lite:latest - vtbackup: vitess/lite:latest + vtctld: vitess/lite:v11.0.3 + vtgate: vitess/lite:v11.0.3 + vttablet: vitess/lite:v11.0.3 + vtbackup: vitess/lite:v11.0.3 mysqld: - mysql56Compatible: vitess/lite:latest + mysql56Compatible: vitess/lite:v11.0.3 mysqldExporter: prom/mysqld-exporter:v0.11.0 cells: - name: zone1 diff --git a/examples/operator/vtorc_example.yaml b/examples/operator/vtorc_example.yaml index ccaa74bc295..7e712c991c9 100644 --- a/examples/operator/vtorc_example.yaml +++ b/examples/operator/vtorc_example.yaml @@ -8,13 +8,13 @@ metadata: name: example spec: images: - vtctld: vitess/lite:latest - vtorc: vitess/lite:latest - vtgate: vitess/lite:latest - vttablet: vitess/lite:latest - vtbackup: vitess/lite:latest + vtctld: vitess/lite:v11.0.3 + vtorc: vitess/lite:v11.0.3 + vtgate: vitess/lite:v11.0.3 + vttablet: vitess/lite:v11.0.3 + vtbackup: vitess/lite:v11.0.3 mysqld: - mysql56Compatible: vitess/lite:latest + mysql56Compatible: vitess/lite:v11.0.3 mysqldExporter: prom/mysqld-exporter:v0.11.0 cells: - name: zone1 diff --git a/examples/region_sharding/203_reshard.sh b/examples/region_sharding/203_reshard.sh index b868885aa39..ce1a7f45587 100755 --- a/examples/region_sharding/203_reshard.sh +++ b/examples/region_sharding/203_reshard.sh @@ -16,4 +16,4 @@ source ./env.sh -vtctlclient Reshard -tablet_types=MASTER main.main2regions '0' '-40,40-80,80-c0,c0-' +vtctlclient Reshard -v1 -tablet_types=MASTER main.main2regions '0' '-40,40-80,80-c0,c0-' diff --git a/go.mod b/go.mod index e1695bf5304..f8855a308ee 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect github.com/aws/aws-sdk-go v1.28.8 github.com/buger/jsonparser v0.0.0-20200322175846-f7e751efca13 - github.com/cespare/xxhash/v2 v2.1.1 + github.com/cespare/xxhash/v2 v2.2.0 github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect github.com/corpix/uarand v0.1.1 // indirect @@ -77,6 +77,7 @@ require ( github.com/prometheus/client_golang v1.11.0 github.com/prometheus/common v0.29.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 + github.com/redis/go-redis/v9 v9.5.1 github.com/samuel/go-zookeeper v0.0.0-20200724154423-2164a8ac840e github.com/satori/go.uuid v1.2.0 // indirect github.com/sjmudd/stopwatch v0.0.0-20170613150411-f380bf8a9be1 diff --git a/go.sum b/go.sum index 7f22e4595d9..4d59c4dcfff 100644 --- a/go.sum +++ b/go.sum @@ -126,13 +126,18 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/buger/jsonparser v0.0.0-20200322175846-f7e751efca13 h1:+qUNY4VRkEH46bLUwxCyUU+iOGJMQBVibAaYzWiwWcg= github.com/buger/jsonparser v0.0.0-20200322175846-f7e751efca13/go.mod h1:tgcrVJ81GPSF0mz+0nu1Xaz0fazGPrmmJfJtxjbHhUQ= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -176,6 +181,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -639,6 +646,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8= +github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= diff --git a/go/cache/redis/cache.go b/go/cache/redis/cache.go new file mode 100644 index 00000000000..7fb052fd5db --- /dev/null +++ b/go/cache/redis/cache.go @@ -0,0 +1,50 @@ +package redis + +import ( + "time" + + gredis "github.com/redis/go-redis/v9" + "golang.org/x/net/context" +) + +const defaultTimeout = 15 * time.Second +const defaultRecordTtl = 5 * time.Minute + +type Cache struct { + client *gredis.Client +} + +func NewCache() *Cache { + opts := &gredis.Options{ + Addr: "localhost:6379", + Password: "", + DB: 0, + } + + client := gredis.NewClient(opts) + + return &Cache{ + client: client, + } +} + +func (c *Cache) Get(key string) (string, error) { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + + return c.client.Get(ctx, key).Result() +} + +func (c *Cache) Set(key, value string) error { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + + return c.client.Set(ctx, key, value, defaultRecordTtl).Err() +} + +func (c *Cache) Delete(key ...string) error { + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + + return c.client.Del(ctx, key...).Err() +} diff --git a/go/cache/redis/cache_test.go b/go/cache/redis/cache_test.go new file mode 100644 index 00000000000..535dec74fcc --- /dev/null +++ b/go/cache/redis/cache_test.go @@ -0,0 +1,74 @@ +package redis_test + +import ( + "testing" + + "vitess.io/vitess/go/cache/redis" +) + +func Test_RedisStringSet(t *testing.T) { + t.Skip("E2E not set up") + + cache := redis.NewCache() + + if err := cache.Set("hi", "mom"); err != nil { + t.Error(err) + } + + val, err := cache.Get("hi") + if err != nil { + t.Error(err) + } + + if val != "mom" { + t.Error("Value is not \"mom\"") + } +} + +func Test_RedisStringSetAndDel(t *testing.T) { + t.Skip("E2E not set up") + + cache := redis.NewCache() + + if err := cache.Set("hi", "mom"); err != nil { + t.Error(err) + } + + val, err := cache.Get("hi") + if err != nil || len(val) == 0 { + t.Error(err) + } + + if err = cache.Delete("hi"); err != nil { + t.Error(err) + } + + val_ex, err := cache.Get("hi") + if err == nil || len(val_ex) != 0 { + t.Error(err) + } +} + +func Test_RedisOperationsWithKeyGen(t *testing.T) { + t.Skip("E2E not set up") + + cache := redis.NewCache() + + cols := []string{"id", "user_id"} + vtgs := []string{"1323", "4362"} + + key := redis.GenerateCacheKey(append(cols, vtgs...)...) + + if err := cache.Set(key, "mom"); err != nil { + t.Error(err) + } + + val, err := cache.Get(key) + if err != nil || len(val) == 0 { + t.Error(err) + } + + if err = cache.Delete(key); err != nil { + t.Error(err) + } +} diff --git a/go/cache/redis/keygen.go b/go/cache/redis/keygen.go new file mode 100644 index 00000000000..a0d090c620a --- /dev/null +++ b/go/cache/redis/keygen.go @@ -0,0 +1,7 @@ +package redis + +import "strings" + +func GenerateCacheKey(args ...string) string { + return strings.Join(args, "_") +} diff --git a/go/cache/redis/keygen_test.go b/go/cache/redis/keygen_test.go new file mode 100644 index 00000000000..2d39af32992 --- /dev/null +++ b/go/cache/redis/keygen_test.go @@ -0,0 +1,17 @@ +package redis_test + +import ( + "strings" + "testing" + + "vitess.io/vitess/go/cache/redis" +) + +func Test_GenerateCacheKey_GeneratesACacheKey(t *testing.T) { + expected := "id_user_id_4_5" + key := redis.GenerateCacheKey("id", "user_id", "4", "5") + + if strings.Compare(expected, key) != 0 { + t.Error() + } +} diff --git a/go/cmd/vtcombo/main.go b/go/cmd/vtcombo/main.go index f425ce40761..d1757acdb77 100644 --- a/go/cmd/vtcombo/main.go +++ b/go/cmd/vtcombo/main.go @@ -59,6 +59,8 @@ var ( mysqlPort = flag.Int("mysql_port", 3306, "mysql port") + configPath = flag.String("boost_configs_path", "./boost_query_configs.yaml", "path to the boost query configurations file") + ts *topo.Server resilientServer *srvtopo.ResilientServer ) @@ -214,7 +216,7 @@ func main() { vtgate.QueryLogHandler = "/debug/vtgate/querylog" vtgate.QueryLogzHandler = "/debug/vtgate/querylogz" vtgate.QueryzHandler = "/debug/vtgate/queryz" - vtg := vtgate.Init(context.Background(), resilientServer, tpb.Cells[0], tabletTypesToWait) + vtg := vtgate.Init(context.Background(), resilientServer, tpb.Cells[0], tabletTypesToWait, configPath) // vtctld configuration and init vtctld.InitVtctld(ts) diff --git a/go/cmd/vtgate/vtgate.go b/go/cmd/vtgate/vtgate.go index 3f98b7d6212..fb59a51ceb1 100644 --- a/go/cmd/vtgate/vtgate.go +++ b/go/cmd/vtgate/vtgate.go @@ -44,6 +44,8 @@ var ( tabletTypesToWait = flag.String("tablet_types_to_wait", "", "wait till connected for specified tablet types during Gateway initialization") ) +var configPath = flag.String("boost_configs_path", "./boost_query_configs.yaml", "path to the boost query configurations file") + var resilientServer *srvtopo.ResilientServer var legacyHealthCheck discovery.LegacyHealthCheck @@ -153,7 +155,7 @@ func main() { vtg = vtgate.LegacyInit(context.Background(), legacyHealthCheck, resilientServer, *cell, *vtgate.RetryCount, tabletTypes) } else { // use new Init otherwise - vtg = vtgate.Init(context.Background(), resilientServer, *cell, tabletTypes) + vtg = vtgate.Init(context.Background(), resilientServer, *cell, tabletTypes, configPath) } servenv.OnRun(func() { diff --git a/go/mysql/binlog_event_json.go b/go/mysql/binlog_event_json.go index efc5648f326..9d4ee9e02d6 100644 --- a/go/mysql/binlog_event_json.go +++ b/go/mysql/binlog_event_json.go @@ -470,7 +470,7 @@ func (oh opaquePlugin) getNode(typ jsonDataType, data []byte, pos int) (node *aj precision := decimalData[0] scale := decimalData[1] metadata := (uint16(precision) << 8) + uint16(scale) - val, _, err := CellValue(decimalData, 2, TypeNewDecimal, metadata, querypb.Type_DECIMAL) + val, _, err := CellValue(decimalData, 2, TypeNewDecimal, metadata, &querypb.Field{Type: querypb.Type_DECIMAL}) if err != nil { return nil, err } diff --git a/go/mysql/binlog_event_rbr.go b/go/mysql/binlog_event_rbr.go index 906ccba5c39..20c41acfe4c 100644 --- a/go/mysql/binlog_event_rbr.go +++ b/go/mysql/binlog_event_rbr.go @@ -331,12 +331,14 @@ func printTimestamp(v uint32) *bytes.Buffer { } // CellValue returns the data for a cell as a sqltypes.Value, and how -// many bytes it takes. It only uses the querypb.Type value for the -// signed flag. -func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Type) (sqltypes.Value, int, error) { +// many bytes it takes. It uses source type in querypb.Type and vitess type +// byte to determine general shared aspects of types and the querypb.Field to +// determine other info specifically about its underlying column (SQL column +// type, column length, charset, etc) +func CellValue(data []byte, pos int, typ byte, metadata uint16, field *querypb.Field) (sqltypes.Value, int, error) { switch typ { case TypeTiny: - if sqltypes.IsSigned(styp) { + if sqltypes.IsSigned(field.Type) { return sqltypes.MakeTrusted(querypb.Type_INT8, strconv.AppendInt(nil, int64(int8(data[pos])), 10)), 1, nil } @@ -352,14 +354,14 @@ func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Typ strconv.AppendUint(nil, uint64(data[pos])+1900, 10)), 1, nil case TypeShort: val := binary.LittleEndian.Uint16(data[pos : pos+2]) - if sqltypes.IsSigned(styp) { + if sqltypes.IsSigned(field.Type) { return sqltypes.MakeTrusted(querypb.Type_INT16, strconv.AppendInt(nil, int64(int16(val)), 10)), 2, nil } return sqltypes.MakeTrusted(querypb.Type_UINT16, strconv.AppendUint(nil, uint64(val), 10)), 2, nil case TypeInt24: - if sqltypes.IsSigned(styp) && data[pos+2]&128 > 0 { + if sqltypes.IsSigned(field.Type) && data[pos+2]&128 > 0 { // Negative number, have to extend the sign. val := int32(uint32(data[pos]) + uint32(data[pos+1])<<8 + @@ -376,7 +378,7 @@ func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Typ strconv.AppendUint(nil, val, 10)), 3, nil case TypeLong: val := binary.LittleEndian.Uint32(data[pos : pos+4]) - if sqltypes.IsSigned(styp) { + if sqltypes.IsSigned(field.Type) { return sqltypes.MakeTrusted(querypb.Type_INT32, strconv.AppendInt(nil, int64(int32(val)), 10)), 4, nil } @@ -399,7 +401,7 @@ func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Typ txt.Bytes()), 4, nil case TypeLongLong: val := binary.LittleEndian.Uint64(data[pos : pos+8]) - if sqltypes.IsSigned(styp) { + if sqltypes.IsSigned(field.Type) { return sqltypes.MakeTrusted(querypb.Type_INT64, strconv.AppendInt(nil, int64(val), 10)), 8, nil } @@ -448,11 +450,11 @@ func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Typ return sqltypes.MakeTrusted(querypb.Type_DATETIME, []byte(fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second))), 8, nil case TypeVarchar, TypeVarString: - // We trust that styp is compatible with the column type + // We trust that typ is compatible with the field.Type // Length is encoded in 1 or 2 bytes. typeToUse := querypb.Type_VARCHAR - if styp == querypb.Type_VARBINARY || styp == querypb.Type_BINARY || styp == querypb.Type_BLOB { - typeToUse = styp + if field.Type == querypb.Type_VARBINARY || field.Type == querypb.Type_BINARY || field.Type == querypb.Type_BLOB { + typeToUse = field.Type } if metadata > 255 { l := int(uint64(data[pos]) | @@ -894,15 +896,17 @@ func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Typ } l := int(data[pos]) mdata := data[pos+1 : pos+1+l] - if sqltypes.IsBinary(styp) { + if sqltypes.IsBinary(field.Type) { // For binary(n) column types, mysql pads the data on the right with nulls. However the binlog event contains // the data without this padding. This causes several issues: // * if a binary(n) column is part of the sharding key, the keyspace_id() returned during the copy phase // (where the value is the result of a mysql query) is different from the one during replication // (where the value is the one from the binlogs) // * mysql where clause comparisons do not do the right thing without padding - // So for fixed length binary() columns we right-pad it with nulls if necessary - if l < max { + // So for fixed length BINARY columns we right-pad it with nulls if necessary to match what MySQL returns. + // Because CHAR columns with a binary collation (e.g. utf8mb4_bin) have the same metadata as a BINARY column + // in binlog events, we also need to check for this case based on the underlying column type. + if l < max && strings.HasPrefix(strings.ToLower(field.ColumnType), "binary") { paddedData := make([]byte, max) copy(paddedData[:l], mdata) mdata = paddedData @@ -1094,7 +1098,7 @@ func (rs *Rows) StringValuesForTests(tm *TableMap, rowIndex int) ([]string, erro } // We have real data - value, l, err := CellValue(data, pos, tm.Types[c], tm.Metadata[c], querypb.Type_UINT64) + value, l, err := CellValue(data, pos, tm.Types[c], tm.Metadata[c], &querypb.Field{Type: querypb.Type_UINT64}) if err != nil { return nil, err } @@ -1129,7 +1133,7 @@ func (rs *Rows) StringIdentifiesForTests(tm *TableMap, rowIndex int) ([]string, } // We have real data - value, l, err := CellValue(data, pos, tm.Types[c], tm.Metadata[c], querypb.Type_UINT64) + value, l, err := CellValue(data, pos, tm.Types[c], tm.Metadata[c], &querypb.Field{Type: querypb.Type_UINT64}) if err != nil { return nil, err } diff --git a/go/mysql/binlog_event_rbr_test.go b/go/mysql/binlog_event_rbr_test.go index d225b2b555f..357ab88422e 100644 --- a/go/mysql/binlog_event_rbr_test.go +++ b/go/mysql/binlog_event_rbr_test.go @@ -550,7 +550,7 @@ func TestCellLengthAndData(t *testing.T) { } // Test CellValue. - out, l, err := CellValue(padded, 1, tcase.typ, tcase.metadata, tcase.styp) + out, l, err := CellValue(padded, 1, tcase.typ, tcase.metadata, &querypb.Field{Type: tcase.styp}) if err != nil || l != len(tcase.data) || out.Type() != tcase.out.Type() || !bytes.Equal(out.Raw(), tcase.out.Raw()) { t.Errorf("testcase cellData(%v,%v) returned unexpected result: %v %v %v, was expecting %v %v ", tcase.typ, tcase.data, out, l, err, tcase.out, len(tcase.data)) diff --git a/go/mysql/conn.go b/go/mysql/conn.go index ae0b58a3ee7..edb1201afe3 100644 --- a/go/mysql/conn.go +++ b/go/mysql/conn.go @@ -952,7 +952,7 @@ func (c *Conn) handleComStmtReset(data []byte) bool { } func (c *Conn) handleComStmtSendLongData(data []byte) bool { - stmtID, paramID, chunkData, ok := c.parseComStmtSendLongData(data) + stmtID, paramID, chunk, ok := c.parseComStmtSendLongData(data) c.recycleReadPacket() if !ok { err := fmt.Errorf("error parsing statement send long data from client %v, returning error: %v", c.ConnectionID, data) @@ -972,9 +972,6 @@ func (c *Conn) handleComStmtSendLongData(data []byte) bool { return c.writeErrorPacketFromErrorAndLog(err) } - chunk := make([]byte, len(chunkData)) - copy(chunk, chunkData) - key := fmt.Sprintf("v%d", paramID+1) if val, ok := prepare.BindVars[key]; ok { val.Value = append(val.Value, chunk...) diff --git a/go/mysql/conn_test.go b/go/mysql/conn_test.go index fb3cb1a9f7a..58fc9d7bcc1 100644 --- a/go/mysql/conn_test.go +++ b/go/mysql/conn_test.go @@ -18,7 +18,9 @@ package mysql import ( "bytes" + "context" crypto_rand "crypto/rand" + "encoding/binary" "encoding/hex" "fmt" "math/rand" @@ -81,6 +83,7 @@ func createSocketPair(t *testing.T) (net.Listener, *Conn, *Conn) { // Create a Conn on both sides. cConn := newConn(clientConn) sConn := newConn(serverConn) + sConn.PrepareData = map[uint32]*PrepareData{} return listener, sConn, cConn } @@ -643,49 +646,6 @@ func TestConnectionErrorWhileWritingComStmtExecute(t *testing.T) { require.False(t, res, "we should beak the connection in case of error writing error packet") } -type testRun struct { - t *testing.T - err error -} - -func (t testRun) NewConnection(c *Conn) { - panic("implement me") -} - -func (t testRun) ConnectionClosed(c *Conn) { - panic("implement me") -} - -func (t testRun) ComQuery(c *Conn, query string, callback func(*sqltypes.Result) error) error { - if strings.Contains(query, "error") { - return t.err - } - if strings.Contains(query, "panic") { - panic("test panic attack!") - } - if strings.Contains(query, "twice") { - callback(selectRowsResult) - } - callback(selectRowsResult) - return nil -} - -func (t testRun) ComPrepare(c *Conn, query string, bindVars map[string]*querypb.BindVariable) ([]*querypb.Field, error) { - panic("implement me") -} - -func (t testRun) ComStmtExecute(c *Conn, prepare *PrepareData, callback func(*sqltypes.Result) error) error { - panic("implement me") -} - -func (t testRun) WarningCount(c *Conn) uint16 { - return 0 -} - -func (t testRun) ComResetConnection(c *Conn) { - panic("implement me") -} - var _ Handler = (*testRun)(nil) type testConn struct { @@ -748,3 +708,151 @@ func (m mockAddress) String() string { } var _ net.Addr = (*mockAddress)(nil) + +var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + +func randSeq(n int) string { + b := make([]rune, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} + +func TestPrepareAndExecute(t *testing.T) { + // this test starts a lot of clients that all send prepared statement parameter values + // and check that the handler received the correct input + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + for i := 0; i < 1000; i++ { + startGoRoutine(ctx, t, randSeq(i)) + } + + for { + select { + case <-ctx.Done(): + return + default: + if t.Failed() { + return + } + } + } +} + +func startGoRoutine(ctx context.Context, t *testing.T, s string) { + go func(longData string) { + listener, sConn, cConn := createSocketPair(t) + defer func() { + listener.Close() + sConn.Close() + cConn.Close() + }() + + sql := "SELECT * FROM test WHERE id = ?" + mockData := preparePacket(t, sql) + + err := cConn.writePacket(mockData) + require.NoError(t, err) + + handler := &testRun{ + t: t, + expParamCounts: 1, + expQuery: sql, + expStmtID: 1, + } + + ok := sConn.handleNextCommand(handler) + require.True(t, ok, "oh noes") + + resp, err := cConn.ReadPacket() + require.NoError(t, err) + require.EqualValues(t, 0, resp[0]) + + for count := 0; ; count++ { + select { + case <-ctx.Done(): + return + default: + } + cConn.sequence = 0 + longDataPacket := createSendLongDataPacket(sConn.StatementID, 0, []byte(longData)) + err = cConn.writePacket(longDataPacket) + assert.NoError(t, err) + + assert.True(t, sConn.handleNextCommand(handler)) + data := sConn.PrepareData[sConn.StatementID] + assert.NotNil(t, data) + variable := data.BindVars["v1"] + assert.NotNil(t, variable, fmt.Sprintf("%#v", data.BindVars)) + assert.Equalf(t, []byte(longData), variable.Value[len(longData)*count:], "failed at: %d", count) + } + }(s) +} + +func createSendLongDataPacket(stmtID uint32, paramID uint16, data []byte) []byte { + stmtIDBinary := make([]byte, 4) + binary.LittleEndian.PutUint32(stmtIDBinary, stmtID) + + paramIDBinary := make([]byte, 2) + binary.LittleEndian.PutUint16(paramIDBinary, paramID) + + packet := []byte{0, 0, 0, 0, ComStmtSendLongData} + packet = append(packet, stmtIDBinary...) // append stmt ID + packet = append(packet, paramIDBinary...) // append param ID + packet = append(packet, data...) // append data + return packet +} + +type testRun struct { + t *testing.T + err error + expParamCounts int + expQuery string + expStmtID int +} + +func (t testRun) ComStmtExecute(c *Conn, prepare *PrepareData, callback func(*sqltypes.Result) error) error { + panic("implement me") +} + +func (t testRun) NewConnection(c *Conn) { + panic("implement me") +} + +func (t testRun) ConnectionClosed(c *Conn) { + panic("implement me") +} + +func (t testRun) ComQuery(c *Conn, query string, callback func(*sqltypes.Result) error) error { + if strings.Contains(query, "error") { + return t.err + } + if strings.Contains(query, "panic") { + panic("test panic attack!") + } + if strings.Contains(query, "twice") { + callback(selectRowsResult) + } + callback(selectRowsResult) + return nil +} + +func (t testRun) ComPrepare(c *Conn, query string, bv map[string]*querypb.BindVariable) ([]*querypb.Field, error) { + assert.Equal(t.t, t.expQuery, query) + assert.EqualValues(t.t, t.expStmtID, c.StatementID) + assert.NotNil(t.t, c.PrepareData[c.StatementID]) + assert.EqualValues(t.t, t.expParamCounts, c.PrepareData[c.StatementID].ParamsCount) + assert.Len(t.t, c.PrepareData, int(c.PrepareData[c.StatementID].ParamsCount)) + return nil, nil +} + +func (t testRun) WarningCount(c *Conn) uint16 { + return 0 +} + +func (t testRun) ComResetConnection(c *Conn) { + panic("implement me") +} + +var _ Handler = (*testRun)(nil) diff --git a/go/mysql/endtoend/replication_test.go b/go/mysql/endtoend/replication_test.go index 8e0d302c6cb..9978682714e 100644 --- a/go/mysql/endtoend/replication_test.go +++ b/go/mysql/endtoend/replication_test.go @@ -1098,7 +1098,7 @@ func valuesForTests(t *testing.T, rs *mysql.Rows, tm *mysql.TableMap, rowIndex i } // We have real data - value, l, err := mysql.CellValue(data, pos, tm.Types[c], tm.Metadata[c], querypb.Type_UINT64) + value, l, err := mysql.CellValue(data, pos, tm.Types[c], tm.Metadata[c], &querypb.Field{Type: querypb.Type_UINT64}) if err != nil { return nil, err } diff --git a/go/mysql/mysql56_gtid_set.go b/go/mysql/mysql56_gtid_set.go index 408c3cac0d6..071e0d929b7 100644 --- a/go/mysql/mysql56_gtid_set.go +++ b/go/mysql/mysql56_gtid_set.go @@ -573,7 +573,11 @@ func (set Mysql56GTIDSet) Difference(other Mysql56GTIDSet) Mysql56GTIDSet { diffIntervals = append(diffIntervals, intervals...) } - differenceSet[sid] = diffIntervals + if len(diffIntervals) == 0 { + delete(differenceSet, sid) + } else { + differenceSet[sid] = diffIntervals + } } return differenceSet diff --git a/go/mysql/mysql56_gtid_set_test.go b/go/mysql/mysql56_gtid_set_test.go index fdb0569c1a2..e30e6fbef0e 100644 --- a/go/mysql/mysql56_gtid_set_test.go +++ b/go/mysql/mysql56_gtid_set_test.go @@ -481,6 +481,20 @@ func TestMysql56GTIDSetDifference(t *testing.T) { if !got.Equal(want) { t.Errorf("got %#v; want %#v", got, want) } + + sid10 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + sid11 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + set10 := Mysql56GTIDSet{ + sid10: []interval{{1, 30}}, + } + set11 := Mysql56GTIDSet{ + sid11: []interval{{1, 30}}, + } + got = set10.Difference(set11) + want = Mysql56GTIDSet{} + if !got.Equal(want) { + t.Errorf("got %#v; want %#v", got, want) + } } func TestMysql56GTIDSetSIDBlock(t *testing.T) { diff --git a/go/mysql/query.go b/go/mysql/query.go index 2c9e78d7651..3bea7b5f516 100644 --- a/go/mysql/query.go +++ b/go/mysql/query.go @@ -867,7 +867,11 @@ func (c *Conn) parseComStmtSendLongData(data []byte) (uint32, uint16, []byte, bo return 0, 0, nil, false } - return statementID, paramID, data[pos:], true + chunkData := data[pos:] + chunk := make([]byte, len(chunkData)) + copy(chunk, chunkData) + + return statementID, paramID, chunk, true } func (c *Conn) parseComStmtClose(data []byte) (uint32, bool) { diff --git a/go/mysql/query_test.go b/go/mysql/query_test.go index aab9b6197ec..0a3689b719c 100644 --- a/go/mysql/query_test.go +++ b/go/mysql/query_test.go @@ -33,7 +33,7 @@ import ( ) // Utility function to write sql query as packets to test parseComPrepare -func MockQueryPackets(t *testing.T, query string) []byte { +func preparePacket(t *testing.T, query string) []byte { data := make([]byte, len(query)+1+packetHeaderSize) // Not sure if it makes a difference pos := packetHeaderSize @@ -130,7 +130,7 @@ func TestComStmtPrepare(t *testing.T) { }() sql := "select * from test_table where id = ?" - mockData := MockQueryPackets(t, sql) + mockData := preparePacket(t, sql) if err := cConn.writePacket(mockData); err != nil { t.Fatalf("writePacket failed: %v", err) @@ -173,7 +173,7 @@ func TestComStmtPrepareUpdStmt(t *testing.T) { }() sql := "UPDATE test SET __bit = ?, __tinyInt = ?, __tinyIntU = ?, __smallInt = ?, __smallIntU = ?, __mediumInt = ?, __mediumIntU = ?, __int = ?, __intU = ?, __bigInt = ?, __bigIntU = ?, __decimal = ?, __float = ?, __double = ?, __date = ?, __datetime = ?, __timestamp = ?, __time = ?, __year = ?, __char = ?, __varchar = ?, __binary = ?, __varbinary = ?, __tinyblob = ?, __tinytext = ?, __blob = ?, __text = ?, __enum = ?, __set = ? WHERE __id = 0" - mockData := MockQueryPackets(t, sql) + mockData := preparePacket(t, sql) err := cConn.writePacket(mockData) require.NoError(t, err, "writePacket failed") diff --git a/go/mysql/replication_status.go b/go/mysql/replication_status.go index 58f17835b5f..38503e10d0e 100644 --- a/go/mysql/replication_status.go +++ b/go/mysql/replication_status.go @@ -112,7 +112,7 @@ func ProtoToReplicationStatus(s *replicationdatapb.Status) ReplicationStatus { // provided as a list of ReplicationStatus's. This method only works if the flavor for all retrieved ReplicationStatus's is MySQL. // The result is returned as a Mysql56GTIDSet, each of whose elements is a found errant GTID. func (s *ReplicationStatus) FindErrantGTIDs(otherReplicaStatuses []*ReplicationStatus) (Mysql56GTIDSet, error) { - set, ok := s.RelayLogPosition.GTIDSet.(Mysql56GTIDSet) + relayLogSet, ok := s.RelayLogPosition.GTIDSet.(Mysql56GTIDSet) if !ok { return nil, fmt.Errorf("errant GTIDs can only be computed on the MySQL flavor") } @@ -136,8 +136,8 @@ func (s *ReplicationStatus) FindErrantGTIDs(otherReplicaStatuses []*ReplicationS } // Copy set for final diffSet so we don't mutate receiver. - diffSet := make(Mysql56GTIDSet, len(set)) - for sid, intervals := range set { + diffSet := make(Mysql56GTIDSet, len(relayLogSet)) + for sid, intervals := range relayLogSet { if sid == s.MasterUUID { continue } diff --git a/go/sqltypes/bind_variables.go b/go/sqltypes/bind_variables.go index 9473f0efa73..124a9c9d488 100644 --- a/go/sqltypes/bind_variables.go +++ b/go/sqltypes/bind_variables.go @@ -65,6 +65,16 @@ func BuildBindVariables(in map[string]interface{}) (map[string]*querypb.BindVari return out, nil } +// HexNumBindVariable converts bytes representing a hex number to a bind var. +func HexNumBindVariable(v []byte) *querypb.BindVariable { + return ValueBindVariable(NewHexNum(v)) +} + +// HexValBindVariable converts bytes representing a hex encoded string to a bind var. +func HexValBindVariable(v []byte) *querypb.BindVariable { + return ValueBindVariable(NewHexVal(v)) +} + // Int8BindVariable converts an int8 to a bind var. func Int8BindVariable(v int8) *querypb.BindVariable { return ValueBindVariable(NewInt8(v)) diff --git a/go/sqltypes/result.go b/go/sqltypes/result.go index b9c0d55e0fa..602b9fa5c8e 100644 --- a/go/sqltypes/result.go +++ b/go/sqltypes/result.go @@ -17,6 +17,8 @@ limitations under the License. package sqltypes import ( + "crypto/sha256" + "fmt" "reflect" "google.golang.org/protobuf/proto" @@ -183,6 +185,61 @@ func ResultsEqual(r1, r2 []Result) bool { return true } +// ResultsEqualUnordered compares two unordered arrays of Result. +func ResultsEqualUnordered(r1, r2 []Result) bool { + if len(r1) != len(r2) { + return false + } + + // allRows is a hash map that contains a row hashed as a key and + // the number of occurrence as the value. we use this map to ensure + // equality between the two result sets. when analyzing r1, we + // increment each key's value by one for each row's occurrence, and + // then we decrement it by one each time we see the same key in r2. + // if one of the key's value is not equal to zero, then r1 and r2 do + // not match. + allRows := map[string]int{} + countRows := 0 + for _, r := range r1 { + saveRowsAnalysis(r, allRows, &countRows, true) + } + for _, r := range r2 { + saveRowsAnalysis(r, allRows, &countRows, false) + } + if countRows != 0 { + return false + } + for _, i := range allRows { + if i != 0 { + return false + } + } + return true +} + +func saveRowsAnalysis(r Result, allRows map[string]int, totalRows *int, increment bool) { + for _, row := range r.Rows { + newHash := hashCodeForRow(row) + if increment { + allRows[newHash] += 1 + } else { + allRows[newHash] -= 1 + } + } + if increment { + *totalRows += int(r.RowsAffected) + } else { + *totalRows -= int(r.RowsAffected) + } +} + +func hashCodeForRow(val []Value) string { + h := sha256.New() + h.Write([]byte(fmt.Sprintf("%v", val))) + + return fmt.Sprintf("%x", h.Sum(nil)) +} + // MakeRowTrusted converts a *querypb.Row to []Value based on the types // in fields. It does not sanity check the values against the type. // Every place this function is called, a comment is needed that explains diff --git a/go/sqltypes/type.go b/go/sqltypes/type.go index 45edc7b62b5..39afa48a5c1 100644 --- a/go/sqltypes/type.go +++ b/go/sqltypes/type.go @@ -140,6 +140,8 @@ const ( Geometry = querypb.Type_GEOMETRY TypeJSON = querypb.Type_JSON Expression = querypb.Type_EXPRESSION + HexNum = querypb.Type_HEXNUM + HexVal = querypb.Type_HEXVAL ) // bit-shift the mysql flags by two byte so we diff --git a/go/sqltypes/type_test.go b/go/sqltypes/type_test.go index efaeb726121..c21e330a6f3 100644 --- a/go/sqltypes/type_test.go +++ b/go/sqltypes/type_test.go @@ -119,6 +119,12 @@ func TestTypeValues(t *testing.T) { }, { defined: Expression, expected: 31, + }, { + defined: HexNum, + expected: 32 | flagIsText, + }, { + defined: HexVal, + expected: 33 | flagIsText, }} for _, tcase := range testcases { if int(tcase.defined) != tcase.expected { @@ -162,6 +168,8 @@ func TestCategory(t *testing.T) { Geometry, TypeJSON, Expression, + HexNum, + HexVal, } for _, typ := range alltypes { matched := false @@ -192,7 +200,7 @@ func TestCategory(t *testing.T) { } matched = true } - if typ == Null || typ == Decimal || typ == Expression || typ == Bit { + if typ == Null || typ == Decimal || typ == Expression || typ == Bit || typ == HexNum || typ == HexVal { if matched { t.Errorf("%v matched more than one category", typ) } diff --git a/go/sqltypes/value.go b/go/sqltypes/value.go index 491ee7d7059..e017f57f6db 100644 --- a/go/sqltypes/value.go +++ b/go/sqltypes/value.go @@ -19,16 +19,21 @@ package sqltypes import ( "encoding/base64" + "encoding/hex" "encoding/json" "errors" "fmt" + "regexp" "strconv" "strings" "vitess.io/vitess/go/bytes2" "vitess.io/vitess/go/hack" + "vitess.io/vitess/go/vt/log" querypb "vitess.io/vitess/go/vt/proto/query" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) var ( @@ -79,7 +84,7 @@ func NewValue(typ querypb.Type, val []byte) (v Value, err error) { return NULL, err } return MakeTrusted(typ, val), nil - case IsQuoted(typ) || typ == Bit || typ == Null: + case IsQuoted(typ) || typ == Bit || typ == HexNum || typ == HexVal || typ == Null: return MakeTrusted(typ, val), nil } // All other types are unsafe or invalid. @@ -102,6 +107,16 @@ func MakeTrusted(typ querypb.Type, val []byte) Value { return Value{typ: typ, val: val} } +// NewHexNum builds an Hex Value. +func NewHexNum(v []byte) Value { + return MakeTrusted(HexNum, v) +} + +// NewHexVal builds a HexVal Value. +func NewHexVal(v []byte) Value { + return MakeTrusted(HexVal, v) +} + // NewInt64 builds an Int64 Value. func NewInt64(v int64) Value { return MakeTrusted(Int64, strconv.AppendInt(nil, v, 10)) @@ -200,6 +215,20 @@ func (v Value) ToBytes() []byte { if v.typ == Expression { return nil } + if v.typ == HexVal { + dv, err := v.decodeHexVal() + if err != nil { + log.Errorf("Unexpected error seen when returning MySQL representation of SQL Hex value: %v", err) + } + return dv + } + if v.typ == HexNum { + dv, err := v.decodeHexNum() + if err != nil { + log.Errorf("Unexpected error seen when returning MySQL representation of SQL Hex number: %v", err) + } + return dv + } return v.val } @@ -415,6 +444,38 @@ func (v *Value) UnmarshalJSON(b []byte) error { return err } +// decodeHexVal decodes the SQL hex value of the form x'A1' into a byte +// array matching what MySQL would return when querying the column where +// an INSERT was performed with x'A1' having been specified as a value +func (v *Value) decodeHexVal() ([]byte, error) { + match, err := regexp.Match("^x'.*'$", v.val) + if !match || err != nil { + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "invalid hex value: %v", v.val) + } + hexBytes := v.val[2 : len(v.val)-1] + decodedHexBytes, err := hex.DecodeString(string(hexBytes)) + if err != nil { + return nil, err + } + return decodedHexBytes, nil +} + +// decodeHexNum decodes the SQL hex value of the form 0xA1 into a byte +// array matching what MySQL would return when querying the column where +// an INSERT was performed with 0xA1 having been specified as a value +func (v *Value) decodeHexNum() ([]byte, error) { + match, err := regexp.Match("^0x.*$", v.val) + if !match || err != nil { + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "invalid hex number: %v", v.val) + } + hexBytes := v.val[2:] + decodedHexBytes, err := hex.DecodeString(string(hexBytes)) + if err != nil { + return nil, err + } + return decodedHexBytes, nil +} + func encodeBytesSQL(val []byte, b BinWriter) { buf := &bytes2.Buffer{} encodeBytesSQLBytes2(val, buf) diff --git a/go/test/endtoend/cluster/topo_process.go b/go/test/endtoend/cluster/topo_process.go index ca0fef4e2e0..0378b915330 100644 --- a/go/test/endtoend/cluster/topo_process.go +++ b/go/test/endtoend/cluster/topo_process.go @@ -17,6 +17,7 @@ limitations under the License. package cluster import ( + "encoding/json" "fmt" "io/ioutil" "net/http" @@ -147,25 +148,65 @@ func (topo *TopoProcess) SetupZookeeper(cluster *LocalProcessCluster) (err error return } +// ConsulConfigs are the configurations that are added the config files which are used by consul +type ConsulConfigs struct { + Ports PortsInfo `json:"ports"` + DataDir string `json:"data_dir"` + LogFile string `json:"log_file"` +} + +// PortsInfo is the different ports used by consul +type PortsInfo struct { + DNS int `json:"dns"` + HTTP int `json:"http"` + SerfLan int `json:"serf_lan"` + SerfWan int `json:"serf_wan"` + Server int `json:"server"` +} + // SetupConsul spawns a new consul service and initializes it with the defaults. // The service is kept running in the background until TearDown() is called. func (topo *TopoProcess) SetupConsul(cluster *LocalProcessCluster) (err error) { topo.VerifyURL = fmt.Sprintf("http://%s:%d/v1/kv/?keys", topo.Host, topo.Port) + _ = os.MkdirAll(topo.LogDirectory, os.ModePerm) + _ = os.MkdirAll(topo.DataDirectory, os.ModePerm) + configFile := path.Join(os.Getenv("VTDATAROOT"), "consul.json") - config := fmt.Sprintf(`{"ports":{"dns":%d,"http":%d,"serf_lan":%d,"serf_wan":%d}}`, - cluster.GetAndReservePort(), topo.Port, cluster.GetAndReservePort(), cluster.GetAndReservePort()) + logFile := path.Join(topo.LogDirectory, "/consul.log") + _, _ = os.Create(logFile) + + var config []byte + configs := ConsulConfigs{ + Ports: PortsInfo{ + DNS: cluster.GetAndReservePort(), + HTTP: topo.Port, + SerfLan: cluster.GetAndReservePort(), + SerfWan: cluster.GetAndReservePort(), + Server: cluster.GetAndReservePort(), + }, + DataDir: topo.DataDirectory, + LogFile: logFile, + } + config, err = json.Marshal(configs) + if err != nil { + log.Error(err.Error()) + return + } - err = ioutil.WriteFile(configFile, []byte(config), 0666) + err = ioutil.WriteFile(configFile, config, 0666) if err != nil { return } topo.proc = exec.Command( topo.Binary, "agent", - "-dev", + "-server", + "-ui", + "-bootstrap-expect", "1", + "-bind", "127.0.0.1", "-config-file", configFile, ) @@ -174,7 +215,7 @@ func (topo *TopoProcess) SetupConsul(cluster *LocalProcessCluster) (err error) { topo.proc.Env = append(topo.proc.Env, os.Environ()...) - log.Infof("Starting consul with args %v", strings.Join(topo.proc.Args, " ")) + log.Errorf("Starting consul with args %v", strings.Join(topo.proc.Args, " ")) err = topo.proc.Start() if err != nil { return @@ -225,7 +266,9 @@ func (topo *TopoProcess) TearDown(Cell string, originalVtRoot string, currentRoo return nil } - topo.removeTopoDirectories(Cell) + if !(*keepData || keepdata) { + topo.removeTopoDirectories(Cell) + } // Attempt graceful shutdown with SIGTERM first _ = topo.proc.Process.Signal(syscall.SIGTERM) @@ -233,8 +276,8 @@ func (topo *TopoProcess) TearDown(Cell string, originalVtRoot string, currentRoo if !(*keepData || keepdata) { _ = os.RemoveAll(topo.DataDirectory) _ = os.RemoveAll(currentRoot) + _ = os.Setenv("VTDATAROOT", originalVtRoot) } - _ = os.Setenv("VTDATAROOT", originalVtRoot) select { case <-topo.exit: diff --git a/go/test/endtoend/cluster/vtctl_process.go b/go/test/endtoend/cluster/vtctl_process.go index b2dfe753f37..b27cdea9911 100644 --- a/go/test/endtoend/cluster/vtctl_process.go +++ b/go/test/endtoend/cluster/vtctl_process.go @@ -58,19 +58,11 @@ func (vtctl *VtctlProcess) AddCellInfo(Cell string) (err error) { // CreateKeyspace executes vtctl command to create keyspace func (vtctl *VtctlProcess) CreateKeyspace(keyspace string) (err error) { - tmpProcess := exec.Command( - vtctl.Binary, - "-topo_implementation", vtctl.TopoImplementation, - "-topo_global_server_address", vtctl.TopoGlobalAddress, - "-topo_global_root", vtctl.TopoGlobalRoot, - ) - if *isCoverage { - tmpProcess.Args = append(tmpProcess.Args, "-test.coverprofile="+getCoveragePath("vtctl-create-ks.out")) + output, err := vtctl.ExecuteCommandWithOutput("CreateKeyspace", keyspace) + if err != nil { + log.Errorf("CreateKeyspace returned err: %s, output: %s", err, output) } - tmpProcess.Args = append(tmpProcess.Args, - "CreateKeyspace", keyspace) - log.Infof("Running CreateKeyspace with command: %v", strings.Join(tmpProcess.Args, " ")) - return tmpProcess.Run() + return err } // ExecuteCommandWithOutput executes any vtctlclient command and returns output diff --git a/go/test/endtoend/cluster/vtgate_process.go b/go/test/endtoend/cluster/vtgate_process.go index c7fc39a77d5..6aa4b9b635b 100644 --- a/go/test/endtoend/cluster/vtgate_process.go +++ b/go/test/endtoend/cluster/vtgate_process.go @@ -193,6 +193,7 @@ func (vtgate *VtgateProcess) TearDown() error { if vtgate.proc == nil || vtgate.exit == nil { return nil } + // graceful shutdown is not currently working with vtgate, attempting a force-kill to make tests less flaky // Attempt graceful shutdown with SIGTERM first vtgate.proc.Process.Signal(syscall.SIGTERM) diff --git a/go/test/endtoend/onlineddl/ghost/onlineddl_ghost_test.go b/go/test/endtoend/onlineddl/ghost/onlineddl_ghost_test.go index 8efe3bbc708..50459fec41d 100644 --- a/go/test/endtoend/onlineddl/ghost/onlineddl_ghost_test.go +++ b/go/test/endtoend/onlineddl/ghost/onlineddl_ghost_test.go @@ -236,6 +236,15 @@ func TestSchemaChange(t *testing.T) { totalRowsCopied += rowsCopied } require.Equal(t, uint64(len(insertStatements)), totalRowsCopied) + + // See that we're able to read logs after successful migration: + expectedMessage := "starting gh-ost" + logs := onlineddl.ReadMigrationLogs(t, &vtParams, uuid) + assert.Equal(t, len(shards), len(logs)) + for i := range logs { + require.Contains(t, logs[i], expectedMessage) + } + }) t.Run("successful online alter, vtctl", func(t *testing.T) { uuid := testOnlineDDLStatement(t, alterTableTrivialStatement, "gh-ost", "vtctl", "ghost_col") @@ -320,14 +329,21 @@ func TestSchemaChange(t *testing.T) { uuid := testOnlineDDLStatement(t, alterTableTrivialStatement, "gh-ost --skip-topo", "vtgate", "") onlineddl.CheckMigrationStatus(t, &vtParams, shards, uuid, schema.OnlineDDLStatusFailed) + expectedMessage := "No PRIMARY nor UNIQUE key found" rs := onlineddl.ReadMigrations(t, &vtParams, uuid) require.NotNil(t, rs) for _, row := range rs.Named().Rows { message := row["message"].ToString() // the following message is generated by gh-ost. We test that it is captured in our 'message' column: - expectedMessage := "No PRIMARY nor UNIQUE key found" require.Contains(t, message, expectedMessage) } + + // See that we're able to read logs after failed migration: + logs := onlineddl.ReadMigrationLogs(t, &vtParams, uuid) + assert.Equal(t, len(shards), len(logs)) + for i := range logs { + require.Contains(t, logs[i], expectedMessage) + } }) } diff --git a/go/test/endtoend/onlineddl/vrepl_suite/onlineddl_vrepl_suite_test.go b/go/test/endtoend/onlineddl/vrepl_suite/onlineddl_vrepl_suite_test.go index 3af42dff93b..a170be6bf4d 100644 --- a/go/test/endtoend/onlineddl/vrepl_suite/onlineddl_vrepl_suite_test.go +++ b/go/test/endtoend/onlineddl/vrepl_suite/onlineddl_vrepl_suite_test.go @@ -61,7 +61,7 @@ var ( const ( testDataPath = "testdata" - defaultSQLMode = "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" + defaultSQLMode = "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION" ) func TestMain(m *testing.M) { diff --git a/go/test/endtoend/onlineddl/vrepl_suite/testdata/char-collate-binary/alter b/go/test/endtoend/onlineddl/vrepl_suite/testdata/char-collate-binary/alter new file mode 100644 index 00000000000..0768d2bb537 --- /dev/null +++ b/go/test/endtoend/onlineddl/vrepl_suite/testdata/char-collate-binary/alter @@ -0,0 +1 @@ +change id id bigint diff --git a/go/test/endtoend/onlineddl/vrepl_suite/testdata/char-collate-binary/create.sql b/go/test/endtoend/onlineddl/vrepl_suite/testdata/char-collate-binary/create.sql new file mode 100644 index 00000000000..3120e0cfd49 --- /dev/null +++ b/go/test/endtoend/onlineddl/vrepl_suite/testdata/char-collate-binary/create.sql @@ -0,0 +1,24 @@ +drop table if exists onlineddl_test; +create table onlineddl_test ( + id bigint auto_increment, + country_code char(3) collate utf8mb4_bin, + primary key(id) +) auto_increment=1; + +insert into onlineddl_test values (null, 'ABC'); +insert into onlineddl_test values (null, 'DEF'); +insert into onlineddl_test values (null, 'GHI'); + +drop event if exists onlineddl_test; +delimiter ;; +create event onlineddl_test + on schedule every 1 second + starts current_timestamp + ends current_timestamp + interval 60 second + on completion not preserve + enable + do +begin + insert into onlineddl_test values (null, 'jkl'); + insert into onlineddl_test values (null, 'MNO'); +end ;; diff --git a/go/test/endtoend/onlineddl/vrepl_suite/testdata/enum/alter b/go/test/endtoend/onlineddl/vrepl_suite/testdata/enum/alter index f52057984f9..7dccd41a2be 100644 --- a/go/test/endtoend/onlineddl/vrepl_suite/testdata/enum/alter +++ b/go/test/endtoend/onlineddl/vrepl_suite/testdata/enum/alter @@ -1 +1 @@ -change e e enum('red', 'green', 'blue', 'orange', 'yellow') null default null collate 'utf8_bin' +change e e enum('red', 'green', 'blue', 'orange', 'yellow') collate 'utf8_bin' null default null diff --git a/go/test/endtoend/onlineddl/vtgate_util.go b/go/test/endtoend/onlineddl/vtgate_util.go index bd7150d65f1..65ebedf2748 100644 --- a/go/test/endtoend/onlineddl/vtgate_util.go +++ b/go/test/endtoend/onlineddl/vtgate_util.go @@ -190,3 +190,18 @@ func ReadMigrations(t *testing.T, vtParams *mysql.ConnParams, like string) *sqlt return VtgateExecQuery(t, vtParams, query, "") } + +// ReadMigrationLogs reads migration logs for a given migration, on all shards +func ReadMigrationLogs(t *testing.T, vtParams *mysql.ConnParams, uuid string) (logs []string) { + query, err := sqlparser.ParseAndBind("show vitess_migration %a logs", + sqltypes.StringBindVariable(uuid), + ) + require.NoError(t, err) + + r := VtgateExecQuery(t, vtParams, query, "") + for _, row := range r.Named().Rows { + migrationLog := row["migration_log"].ToString() + logs = append(logs, migrationLog) + } + return logs +} diff --git a/go/test/endtoend/recovery/pitr/shardedpitr_test.go b/go/test/endtoend/recovery/pitr/shardedpitr_test.go index c7c89630651..52c38c7a6a4 100644 --- a/go/test/endtoend/recovery/pitr/shardedpitr_test.go +++ b/go/test/endtoend/recovery/pitr/shardedpitr_test.go @@ -299,7 +299,7 @@ func performResharding(t *testing.T) { require.NoError(t, err) } - err = clusterInstance.VtctlclientProcess.ExecuteCommand("Reshard", "ks.reshardWorkflow", "0", "-80,80-") + err = clusterInstance.VtctlclientProcess.ExecuteCommand("Reshard", "-v1", "ks.reshardWorkflow", "0", "-80,80-") require.NoError(t, err) err = clusterInstance.VtctlclientProcess.ExecuteCommand("SwitchReads", "-tablet_type=rdonly", "ks.reshardWorkflow") diff --git a/go/test/endtoend/reparent/reparent_test.go b/go/test/endtoend/reparent/reparent_test.go index 5884a62e48a..8363d5eb1f1 100644 --- a/go/test/endtoend/reparent/reparent_test.go +++ b/go/test/endtoend/reparent/reparent_test.go @@ -117,6 +117,23 @@ func TestReparentNoChoiceDownMaster(t *testing.T) { resurrectTablet(ctx, t, tab1) } +func TestTrivialERS(t *testing.T) { + defer cluster.PanicHandler(t) + setupReparentCluster(t) + defer teardownCluster() + + confirmReplication(t, tab1, []*cluster.Vttablet{tab2, tab3, tab4}) + + // We should be able to do a series of ERS-es, even if nothing + // is down, without issue + for i := 1; i <= 4; i++ { + out, err := ers(t, nil, "30s") + log.Infof("ERS loop %d. EmergencyReparentShard Output: %v", i, out) + require.NoError(t, err) + time.Sleep(5 * time.Second) + } +} + func TestReparentIgnoreReplicas(t *testing.T) { defer cluster.PanicHandler(t) setupReparentCluster(t) diff --git a/go/test/endtoend/topotest/consul/main_test.go b/go/test/endtoend/topotest/consul/main_test.go index f805c7c00b0..563f646f55e 100644 --- a/go/test/endtoend/topotest/consul/main_test.go +++ b/go/test/endtoend/topotest/consul/main_test.go @@ -96,7 +96,7 @@ func TestMain(m *testing.M) { os.Exit(exitCode) } -func TestTopoDownServingQuery(t *testing.T) { +func TestTopoRestart(t *testing.T) { defer cluster.PanicHandler(t) ctx := context.Background() vtParams := mysql.ConnParams{ @@ -107,16 +107,40 @@ func TestTopoDownServingQuery(t *testing.T) { require.Nil(t, err) defer conn.Close() - defer exec(t, conn, `delete from t1`) - execMulti(t, conn, `insert into t1(c1, c2, c3, c4) values (300,100,300,'abc'); ;; insert into t1(c1, c2, c3, c4) values (301,101,301,'abcd');;`) assertMatches(t, conn, `select c1,c2,c3 from t1`, `[[INT64(300) INT64(100) INT64(300)] [INT64(301) INT64(101) INT64(301)]]`) - clusterInstance.TopoProcess.TearDown(clusterInstance.Cell, clusterInstance.OriginalVTDATAROOT, clusterInstance.CurrentVTDATAROOT, true, *clusterInstance.TopoFlavorString()) - time.Sleep(3 * time.Second) - assertMatches(t, conn, `select c1,c2,c3 from t1`, `[[INT64(300) INT64(100) INT64(300)] [INT64(301) INT64(101) INT64(301)]]`) + + defer execute(t, conn, `delete from t1`) + + ch := make(chan interface{}) + + go func() { + clusterInstance.TopoProcess.TearDown(clusterInstance.Cell, clusterInstance.OriginalVTDATAROOT, clusterInstance.CurrentVTDATAROOT, true, *clusterInstance.TopoFlavorString()) + + // Some sleep to server few queries when topo is down. + time.Sleep(400 * time.Millisecond) + + clusterInstance.TopoProcess.Setup(*clusterInstance.TopoFlavorString(), clusterInstance) + + // topo is up now. + ch <- 1 + }() + + timeOut := time.After(15 * time.Second) + + for { + select { + case <-ch: + return + case <-timeOut: + require.Fail(t, "timed out - topo process did not come up") + case <-time.After(100 * time.Millisecond): + assertMatches(t, conn, `select c1,c2,c3 from t1`, `[[INT64(300) INT64(100) INT64(300)] [INT64(301) INT64(101) INT64(301)]]`) + } + } } -func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { +func execute(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { t.Helper() qr, err := conn.ExecuteFetch(query, 1000, true) require.NoError(t, err) @@ -139,7 +163,7 @@ func execMulti(t *testing.T, conn *mysql.Conn, query string) []*sqltypes.Result func assertMatches(t *testing.T, conn *mysql.Conn, query, expected string) { t.Helper() - qr := exec(t, conn, query) + qr := execute(t, conn, query) got := fmt.Sprintf("%v", qr.Rows) diff := cmp.Diff(expected, got) if diff != "" { diff --git a/go/test/endtoend/vreplication/cluster.go b/go/test/endtoend/vreplication/cluster.go index 5b96a6255f4..a8ec0c5c81f 100644 --- a/go/test/endtoend/vreplication/cluster.go +++ b/go/test/endtoend/vreplication/cluster.go @@ -24,6 +24,7 @@ var ( vtdataroot string mainClusterConfig *ClusterConfig externalClusterConfig *ClusterConfig + extraVtctldArgs = []string{"-remote_operation_timeout", "600s", "-topo_etcd_lease_ttl", "120"} ) // ClusterConfig defines the parameters like ports, tmpDir, tablet types which uniquely define a vitess cluster @@ -164,7 +165,7 @@ func NewVitessCluster(t *testing.T, name string, cellNames []string, clusterConf vc.Vtctld = vtctld require.NotNil(t, vc.Vtctld) // use first cell as `-cell` - vc.Vtctld.Setup(cellNames[0]) + vc.Vtctld.Setup(cellNames[0], extraVtctldArgs...) vc.Vtctl = cluster.VtctlProcessInstance(vc.ClusterConfig.topoPort, vc.ClusterConfig.hostname) require.NotNil(t, vc.Vtctl) @@ -400,6 +401,8 @@ func (vc *VitessCluster) teardown(t testing.TB) { for _, vtgate := range cell.Vtgates { if err := vtgate.TearDown(); err != nil { log.Errorf("Error in vtgate teardown - %s", err.Error()) + } else { + log.Infof("vtgate teardown successful") } } } @@ -436,11 +439,15 @@ func (vc *VitessCluster) teardown(t testing.TB) { wg.Wait() if err := vc.Vtctld.TearDown(); err != nil { log.Infof("Error stopping Vtctld: %s", err.Error()) + } else { + log.Info("Successfully stopped vtctld") } for _, cell := range vc.Cells { if err := vc.Topo.TearDown(cell.Name, originalVtdataroot, vtdataroot, false, "etcd2"); err != nil { log.Infof("Error in etcd teardown - %s", err.Error()) + } else { + log.Infof("Successfully tore down topo %s", vc.Topo.Name) } } } @@ -461,6 +468,8 @@ func (vc *VitessCluster) TearDown(t testing.TB) { case <-time.After(1 * time.Minute): log.Infof("TearDown() timed out") } + // some processes seem to hang around for a bit + time.Sleep(5 * time.Second) } func (vc *VitessCluster) getVttabletsInKeyspace(t *testing.T, cell *Cell, ksName string, tabletType string) map[string]*cluster.VttabletProcess { @@ -476,3 +485,24 @@ func (vc *VitessCluster) getVttabletsInKeyspace(t *testing.T, cell *Cell, ksName } return tablets } + +func (vc *VitessCluster) startQuery(t *testing.T, query string) (func(t *testing.T), func(t *testing.T)) { + conn := getConnection(t, vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateMySQLPort) + _, err := conn.ExecuteFetch("begin", 1000, false) + require.NoError(t, err) + _, err = conn.ExecuteFetch(query, 1000, false) + require.NoError(t, err) + + commit := func(t *testing.T) { + _, err = conn.ExecuteFetch("commit", 1000, false) + log.Infof("startQuery:commit:err: %+v", err) + conn.Close() + log.Infof("startQuery:after closing connection") + } + rollback := func(t *testing.T) { + defer conn.Close() + _, err = conn.ExecuteFetch("rollback", 1000, false) + log.Infof("startQuery:rollback:err: %+v", err) + } + return commit, rollback +} diff --git a/go/test/endtoend/vreplication/config.go b/go/test/endtoend/vreplication/config.go index 8ffe0724ae8..74e67622e28 100644 --- a/go/test/endtoend/vreplication/config.go +++ b/go/test/endtoend/vreplication/config.go @@ -3,7 +3,7 @@ package vreplication var ( initialProductSchema = ` create table product(pid int, description varbinary(128), primary key(pid)); -create table customer(cid int, name varbinary(128), meta json default null, typ enum('individual','soho','enterprise'), sport set('football','cricket','baseball'),ts timestamp not null default current_timestamp, primary key(cid)) CHARSET=utf8mb4; +create table customer(cid int, name varbinary(128), meta json default null, typ enum('individual','soho','enterprise'), sport set('football','cricket','baseball'),ts timestamp not null default current_timestamp, bits bit(2) default b'11', primary key(cid)) CHARSET=utf8mb4; create table customer_seq(id int, next_id bigint, cache bigint, primary key(id)) comment 'vitess_sequence'; create table merchant(mname varchar(128), category varchar(128), primary key(mname)) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; create table orders(oid int, cid int, pid int, mname varchar(128), price int, qty int, total int as (qty * price), total2 int as (qty * price) stored, primary key(oid)); diff --git a/go/test/endtoend/vreplication/helper.go b/go/test/endtoend/vreplication/helper.go index 01a80b27982..bee3c214015 100644 --- a/go/test/endtoend/vreplication/helper.go +++ b/go/test/endtoend/vreplication/helper.go @@ -52,7 +52,9 @@ func execVtgateQuery(t *testing.T, conn *mysql.Conn, database string, query stri if strings.TrimSpace(query) == "" { return nil } - execQuery(t, conn, "use `"+database+"`;") + if database != "" { + execQuery(t, conn, "use `"+database+"`;") + } execQuery(t, conn, "begin") qr := execQuery(t, conn, query) execQuery(t, conn, "commit") @@ -167,10 +169,13 @@ func getQueryCount(url string, query string) int { func validateDryRunResults(t *testing.T, output string, want []string) { t.Helper() require.NotEmpty(t, output) - gotDryRun := strings.Split(output, "\n") require.True(t, len(gotDryRun) > 3) - gotDryRun = gotDryRun[3 : len(gotDryRun)-1] + startRow := 3 + if strings.Contains(gotDryRun[0], "deprecated") { + startRow = 4 + } + gotDryRun = gotDryRun[startRow : len(gotDryRun)-1] if len(want) != len(gotDryRun) { t.Fatalf("want and got: lengths don't match, \nwant\n%s\n\ngot\n%s", strings.Join(want, "\n"), strings.Join(gotDryRun, "\n")) } diff --git a/go/test/endtoend/vreplication/resharding_workflows_v2_test.go b/go/test/endtoend/vreplication/resharding_workflows_v2_test.go index 34f10e392a2..d69a0f5a56e 100644 --- a/go/test/endtoend/vreplication/resharding_workflows_v2_test.go +++ b/go/test/endtoend/vreplication/resharding_workflows_v2_test.go @@ -94,7 +94,7 @@ func tstWorkflowExec(t *testing.T, cells, workflow, sourceKs, targetKs, tables, } else { args = append(args, "Reshard") } - args = append(args, "-v2") + switch action { case workflowActionCreate: if currentWorkflowType == wrangler.MoveTablesWorkflow { diff --git a/go/test/endtoend/vreplication/vreplication_test.go b/go/test/endtoend/vreplication/vreplication_test.go index 25e19be33fc..2b57020d88c 100644 --- a/go/test/endtoend/vreplication/vreplication_test.go +++ b/go/test/endtoend/vreplication/vreplication_test.go @@ -49,6 +49,11 @@ var ( targetThrottlerAppName = "vreplication" ) +// for some tests we keep an open transaction during a SwitchWrites and commit it afterwards, to reproduce https://github.com/vitessio/vitess/issues/9400 +// we also then delete the extra row (if) added so that the row counts for the future count comparisons stay the same +const openTxQuery = "insert into customer(cid, name, typ, sport, meta) values(4, 'openTxQuery',1,'football,baseball','{}');" +const deleteOpenTxQuery = "delete from customer where name = 'openTxQuery'" + func init() { defaultRdonly = 0 defaultReplicas = 1 @@ -108,7 +113,8 @@ func TestBasicVreplicationWorkflow(t *testing.T) { insertInitialData(t) materializeRollup(t) - shardCustomer(t, true, []*Cell{defaultCell}, defaultCellName) + shardCustomer(t, true, []*Cell{defaultCell}, defaultCellName, false) + // the tenant table was to test a specific case with binary sharding keys. Drop it now so that we don't // have to update the rest of the tests execVtgateQuery(t, vtgateConn, "customer", "drop table tenant") @@ -138,7 +144,7 @@ func TestMultiCellVreplicationWorkflow(t *testing.T) { cells := []string{"zone1", "zone2"} allCellNames = "zone1,zone2" - vc = NewVitessCluster(t, "TestBasicVreplicationWorkflow", cells, mainClusterConfig) + vc = NewVitessCluster(t, "TestMultiCellVreplicationWorkflow", cells, mainClusterConfig) require.NotNil(t, vc) defaultCellName := "zone1" defaultCell = vc.Cells[defaultCellName] @@ -158,7 +164,7 @@ func TestMultiCellVreplicationWorkflow(t *testing.T) { defer vtgateConn.Close() verifyClusterHealth(t, vc) insertInitialData(t) - shardCustomer(t, true, []*Cell{cell1, cell2}, cell2.Name) + shardCustomer(t, true, []*Cell{cell1, cell2}, cell2.Name, true) } func TestCellAliasVreplicationWorkflow(t *testing.T) { @@ -167,7 +173,7 @@ func TestCellAliasVreplicationWorkflow(t *testing.T) { defer func() { mainClusterConfig.vreplicationCompressGTID = false }() - vc = NewVitessCluster(t, "TestBasicVreplicationWorkflow", cells, mainClusterConfig) + vc = NewVitessCluster(t, "TestCellAliasVreplicationWorkflow", cells, mainClusterConfig) require.NotNil(t, vc) allCellNames = "zone1,zone2" defaultCellName := "zone1" @@ -192,7 +198,7 @@ func TestCellAliasVreplicationWorkflow(t *testing.T) { defer vtgateConn.Close() verifyClusterHealth(t, vc) insertInitialData(t) - shardCustomer(t, true, []*Cell{cell1, cell2}, "alias") + shardCustomer(t, true, []*Cell{cell1, cell2}, "alias", false) } func insertInitialData(t *testing.T) { @@ -239,7 +245,7 @@ func insertMoreProductsForTargetThrottler(t *testing.T) { execVtgateQuery(t, vtgateConn, "product", sql) } -func shardCustomer(t *testing.T, testReverse bool, cells []*Cell, sourceCellOrAlias string) { +func shardCustomer(t *testing.T, testReverse bool, cells []*Cell, sourceCellOrAlias string, withOpenTx bool) { t.Run("shardCustomer", func(t *testing.T) { workflow := "p2c" sourceKs := "product" @@ -255,12 +261,13 @@ func shardCustomer(t *testing.T, testReverse bool, cells []*Cell, sourceCellOrAl t.Fatal(err) } - tables := "customer,tenant" - moveTables(t, sourceCellOrAlias, workflow, sourceKs, targetKs, tables) - // Assume we are operating on first cell defaultCell := cells[0] custKs := vc.Cells[defaultCell.Name].Keyspaces["customer"] + + tables := "customer,tenant" + moveTables(t, sourceCellOrAlias, workflow, sourceKs, targetKs, tables) + customerTab1 := custKs.Shards["-80"].Tablets["zone1-200"].Vttablet customerTab2 := custKs.Shards["80-"].Tablets["zone1-300"].Vttablet @@ -278,8 +285,21 @@ func shardCustomer(t *testing.T, testReverse bool, cells []*Cell, sourceCellOrAl switchReadsDryRun(t, allCellNames, ksWorkflow, dryRunResultsReadCustomerShard) switchReads(t, allCellNames, ksWorkflow) require.True(t, validateThatQueryExecutesOnTablet(t, vtgateConn, productTab, "customer", query, query)) + + var commit func(t *testing.T) + if withOpenTx { + commit, _ = vc.startQuery(t, openTxQuery) + } switchWritesDryRun(t, ksWorkflow, dryRunResultsSwitchWritesCustomerShard) switchWrites(t, ksWorkflow, false) + if withOpenTx && commit != nil { + commit(t) + } + vdiff(t, "product.p2c_reverse", "") + if withOpenTx { + execVtgateQuery(t, vtgateConn, "", deleteOpenTxQuery) + } + ksShards := []string{"product/0", "customer/-80", "customer/80-"} printShardPositions(vc, ksShards) insertQuery2 := "insert into customer(name, cid) values('tempCustomer2', 100)" @@ -477,7 +497,7 @@ func reshard(t *testing.T, ksName string, tableName string, workflow string, sou t.Fatal(err) } } - if err := vc.VtctlClient.ExecuteCommand("Reshard", "-cells="+sourceCellOrAlias, "-tablet_types=replica,master", ksWorkflow, sourceShards, targetShards); err != nil { + if err := vc.VtctlClient.ExecuteCommand("Reshard", "-v1", "-cells="+sourceCellOrAlias, "-tablet_types=replica,master", ksWorkflow, sourceShards, targetShards); err != nil { t.Fatalf("Reshard command failed with %+v\n", err) } tablets := vc.getVttabletsInKeyspace(t, defaultCell, ksName, "master") @@ -819,7 +839,7 @@ func catchup(t *testing.T, vttablet *cluster.VttabletProcess, workflow, info str } func moveTables(t *testing.T, cell, workflow, sourceKs, targetKs, tables string) { - if err := vc.VtctlClient.ExecuteCommand("MoveTables", "-cells="+cell, "-workflow="+workflow, + if err := vc.VtctlClient.ExecuteCommand("MoveTables", "-v1", "-cells="+cell, "-workflow="+workflow, "-tablet_types="+"master,replica,rdonly", sourceKs, targetKs, tables); err != nil { t.Fatalf("MoveTables command failed with %+v\n", err) } diff --git a/go/test/endtoend/vreplication/vschema_load_test.go b/go/test/endtoend/vreplication/vschema_load_test.go new file mode 100644 index 00000000000..cddfe2a4019 --- /dev/null +++ b/go/test/endtoend/vreplication/vschema_load_test.go @@ -0,0 +1,162 @@ +/* +Copyright 2022 The Vitess Authors. + +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 vreplication + +import ( + "context" + "fmt" + "net" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/vt/log" + binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" + vtgatepb "vitess.io/vitess/go/vt/proto/vtgate" + "vitess.io/vitess/go/vt/vtgate/vtgateconn" +) + +// BACKPORT: Required for test to work https://github.com/vitessio/vitess/commit/8037f43d00934e9420e657859021dc0245aa35b8 +const ( + defaultTick = 1 * time.Second + defaultTimeout = 30 * time.Second +) + +// TestVSchemaChangesUnderLoad tests vstreamer under a load of high binlog events and simultaneous multiple vschema changes +// see https://github.com/vitessio/vitess/issues/11169 +func TestVSchemaChangesUnderLoad(t *testing.T) { + + extendedTimeout := defaultTimeout * 4 + + defaultCellName := "zone1" + allCells := []string{"zone1"} + allCellNames = "zone1" + vc = NewVitessCluster(t, "TestVSchemaChanges", allCells, mainClusterConfig) + + require.NotNil(t, vc) + + defer vc.TearDown(t) + + defaultCell = vc.Cells[defaultCellName] + vc.AddKeyspace(t, []*Cell{defaultCell}, "product", "0", initialProductVSchema, initialProductSchema, 1, 0, 100) + vtgate = defaultCell.Vtgates[0] + require.NotNil(t, vtgate) + vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", "product", "0"), 1) + vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", "product", "0"), 1) + vtgateConn = getConnection(t, vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateMySQLPort) + defer vtgateConn.Close() + + // ch is used to signal that there is significant data inserted into the tables and when a lot of vschema changes have been applied + ch := make(chan bool, 1) + + ctx := context.Background() + initialDataInserted := false + startCid := 100 + warmupRowCount := startCid + 2000 + insertData := func() { + timer := time.NewTimer(extendedTimeout) + defer timer.Stop() + log.Infof("Inserting data into customer") + cid := startCid + for { + if !initialDataInserted && cid > warmupRowCount { + log.Infof("Done inserting initial data into customer") + initialDataInserted = true + ch <- true + } + query := fmt.Sprintf("insert into customer(cid, name) values (%d, 'a')", cid) + _, _ = vtgateConn.ExecuteFetch(query, 1, false) + cid++ + query = "update customer set name = concat(name, 'a')" + _, _ = vtgateConn.ExecuteFetch(query, 10000, false) + select { + case <-timer.C: + log.Infof("Done inserting data into customer") + return + default: + } + } + } + go func() { + log.Infof("Starting to vstream from replica") + vgtid := &binlogdatapb.VGtid{ + ShardGtids: []*binlogdatapb.ShardGtid{{ + Keyspace: "product", + Shard: "0", + Gtid: "", + }}} + + filter := &binlogdatapb.Filter{ + Rules: []*binlogdatapb.Rule{{ + Match: "customer", + Filter: "select * from customer", + }}, + } + conn, err := vtgateconn.Dial(ctx, net.JoinHostPort("localhost", strconv.Itoa(vc.ClusterConfig.vtgateGrpcPort))) + require.NoError(t, err) + defer conn.Close() + + flags := &vtgatepb.VStreamFlags{} + + ctx2, cancel := context.WithTimeout(ctx, extendedTimeout/2) + defer cancel() + reader, err := conn.VStream(ctx2, topodatapb.TabletType_REPLICA, vgtid, filter, flags) + require.NoError(t, err) + _, err = reader.Recv() + require.NoError(t, err) + log.Infof("About to sleep in vstreaming to block the vstream Recv() channel") + time.Sleep(extendedTimeout) + log.Infof("Done vstreaming") + }() + + go insertData() + <-ch // wait for enough data to be inserted before ApplyVSchema + const maxApplyVSchemas = 20 + go func() { + numApplyVSchema := 0 + timer := time.NewTimer(extendedTimeout) + defer timer.Stop() + log.Infof("Started ApplyVSchema") + for { + if err := vc.VtctlClient.ExecuteCommand("ApplyVSchema", "--", "--vschema={}", "product"); err != nil { + log.Errorf("ApplyVSchema command failed with %+v\n", err) + return + } + numApplyVSchema++ + if numApplyVSchema > maxApplyVSchemas { + ch <- true + } + select { + case <-timer.C: + log.Infof("Done ApplyVSchema") + ch <- true + return + default: + time.Sleep(defaultTick) + } + } + }() + + <-ch // wait for enough ApplyVSchema calls before doing a PRS + if err := vc.VtctlClient.ExecuteCommand("PlannedReparentShard", "--", "--keyspace_shard", "product/0", + "--new_master", "zone1-101", "--wait_replicas_timeout", defaultTimeout.String()); err != nil { + require.NoError(t, err, "PlannedReparentShard command failed") + } +} diff --git a/go/test/endtoend/vreplication/vstream_test.go b/go/test/endtoend/vreplication/vstream_test.go new file mode 100644 index 00000000000..1a640440e98 --- /dev/null +++ b/go/test/endtoend/vreplication/vstream_test.go @@ -0,0 +1,393 @@ +/* +Copyright 2021 The Vitess Authors. + +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 vreplication + +import ( + "context" + "fmt" + "io" + "strings" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/vt/log" + binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" + vtgatepb "vitess.io/vitess/go/vt/proto/vtgate" + _ "vitess.io/vitess/go/vt/vtctl/grpcvtctlclient" + "vitess.io/vitess/go/vt/vtgate/evalengine" + _ "vitess.io/vitess/go/vt/vtgate/grpcvtgateconn" + + "vitess.io/vitess/go/vt/vtgate/vtgateconn" +) + +// Validates that a reparent while VStream API is streaming doesn't miss any events +// We stream only from the primary and while streaming we reparent to a replica and then back to the original primary +func TestVStreamFailover(t *testing.T) { + defaultCellName := "zone1" + cells := []string{"zone1"} + allCellNames = "zone1" + vc = NewVitessCluster(t, "TestVStreamFailover", cells, mainClusterConfig) + + require.NotNil(t, vc) + defaultReplicas = 2 + defaultRdonly = 0 + defer vc.TearDown(t) + + defaultCell = vc.Cells[defaultCellName] + vc.AddKeyspace(t, []*Cell{defaultCell}, "product", "0", initialProductVSchema, initialProductSchema, defaultReplicas, defaultRdonly, 100) + vtgate = defaultCell.Vtgates[0] + require.NotNil(t, vtgate) + vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.master", "product", "0"), 3) + vtgateConn = getConnection(t, vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateMySQLPort) + defer vtgateConn.Close() + + verifyClusterHealth(t, vc) + insertInitialData(t) + ctx := context.Background() + vstreamConn, err := vtgateconn.Dial(ctx, fmt.Sprintf("%s:%d", vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateGrpcPort)) + if err != nil { + log.Fatal(err) + } + defer vstreamConn.Close() + vgtid := &binlogdatapb.VGtid{ + ShardGtids: []*binlogdatapb.ShardGtid{{ + Keyspace: "product", + Shard: "0", + Gtid: "", + }}} + + filter := &binlogdatapb.Filter{ + Rules: []*binlogdatapb.Rule{{ + Match: "customer", + Filter: "select * from customer", + }}, + } + flags := &vtgatepb.VStreamFlags{HeartbeatInterval: 3600} + done := false + + // don't insert while PRS is going on + var insertMu sync.Mutex + stopInserting := false + id := 0 + + // first goroutine that keeps inserting rows into table being streamed until some time elapses after second PRS + go func() { + for { + if stopInserting { + return + } + insertMu.Lock() + id++ + execVtgateQuery(t, vtgateConn, "product", fmt.Sprintf("insert into customer (cid, name) values (%d, 'customer%d')", id+100, id)) + insertMu.Unlock() + } + }() + + // stream events from the VStream API + reader, err := vstreamConn.VStream(ctx, topodatapb.TabletType_MASTER, vgtid, filter, flags) + require.NoError(t, err) + var numRowEvents int64 + // second goroutine that continuously receives events via VStream API and should be resilient to the two PRS events + go func() { + for { + evs, err := reader.Recv() + + switch err { + case nil: + for _, ev := range evs { + if ev.Type == binlogdatapb.VEventType_ROW { + numRowEvents++ + } + } + case io.EOF: + log.Infof("Stream Ended") + default: + log.Infof("%s:: remote error: %v", time.Now(), err) + } + + if done { + return + } + } + }() + + // run two PRS after one second each, wait for events to be received and exit test + ticker := time.NewTicker(1 * time.Second) + tickCount := 0 + // this for loop implements a mini state machine that does the two PRSs, waits a bit after the second PRS, + // stops the insertions, waits for a bit again for the vstream to catchup and signals the test to stop + for { + <-ticker.C + tickCount++ + switch tickCount { + case 1: + insertMu.Lock() + output, err := vc.VtctlClient.ExecuteCommandWithOutput("PlannedReparentShard", "-keyspace_shard=product/0", "-new_master=zone1-101") + insertMu.Unlock() + log.Infof("output of first PRS is %s", output) + require.NoError(t, err) + case 2: + insertMu.Lock() + output, err := vc.VtctlClient.ExecuteCommandWithOutput("PlannedReparentShard", "-keyspace_shard=product/0", "-new_master=zone1-100") + insertMu.Unlock() + log.Infof("output of second PRS is %s", output) + require.NoError(t, err) + time.Sleep(100 * time.Millisecond) + stopInserting = true + time.Sleep(2 * time.Second) + done = true + } + + if done { + break + } + } + qr := execVtgateQuery(t, vtgateConn, "product", "select count(*) from customer") + require.NotNil(t, qr) + // total number of row events found by the VStream API should match the rows inserted + insertedRows, err := evalengine.ToInt64(qr.Rows[0][0]) + require.NoError(t, err) + require.Equal(t, insertedRows, numRowEvents) +} + +const schemaUnsharded = ` +create table customer_seq(id int, next_id bigint, cache bigint, primary key(id)) comment 'vitess_sequence'; +` +const vschemaUnsharded = ` +{ + "tables": { + "customer_seq": { + "type": "sequence" + } + } +} +` +const schemaSharded = ` +create table customer(cid int, name varbinary(128), primary key(cid)) CHARSET=utf8mb4; +` +const vschemaSharded = ` +{ + "sharded": true, + "vindexes": { + "reverse_bits": { + "type": "reverse_bits" + } + }, + "tables": { + "customer": { + "column_vindexes": [ + { + "column": "cid", + "name": "reverse_bits" + } + ], + "auto_increment": { + "column": "cid", + "sequence": "customer_seq" + } + } + } +} +` + +func insertRow(keyspace, table string, id int) { + vtgateConn.ExecuteFetch(fmt.Sprintf("use %s;", keyspace), 1000, false) + vtgateConn.ExecuteFetch("begin", 1000, false) + vtgateConn.ExecuteFetch(fmt.Sprintf("insert into %s (cid, name) values (%d, '%s%d')", table, id+100, table, id), 1000, false) + vtgateConn.ExecuteFetch("commit", 1000, false) +} + +type numEvents struct { + numRowEvents, numJournalEvents int64 + // BACKPORT: Feature is not needed https://github.com/vitessio/vitess/pull/8598 + // numLessThan80Events, numGreaterThan80Events int64 + // numLessThan40Events, numGreaterThan40Events int64 +} + +// tests the StopOnReshard flag +func testVStreamStopOnReshardFlag(t *testing.T, stopOnReshard bool, baseTabletID int) *numEvents { + defaultCellName := "zone1" + allCells := []string{"zone1"} + allCellNames = "zone1" + vc = NewVitessCluster(t, "TestVStreamStopOnReshard", allCells, mainClusterConfig) + + require.NotNil(t, vc) + defaultReplicas = 0 // because of CI resource constraints we can only run this test with primary tablets + defer func() { defaultReplicas = 1 }() + + defer vc.TearDown(t) + + defaultCell = vc.Cells[defaultCellName] + vc.AddKeyspace(t, []*Cell{defaultCell}, "unsharded", "0", vschemaUnsharded, schemaUnsharded, defaultReplicas, defaultRdonly, baseTabletID+100) + vtgate = defaultCell.Vtgates[0] + require.NotNil(t, vtgate) + vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.primary", "unsharded", "0"), 1) + + vtgateConn = getConnection(t, vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateMySQLPort) + defer vtgateConn.Close() + verifyClusterHealth(t, vc) + + // some initial data + for i := 0; i < 10; i++ { + insertRow("sharded", "customer", i) + } + + vc.AddKeyspace(t, []*Cell{defaultCell}, "sharded", "-80,80-", vschemaSharded, schemaSharded, defaultReplicas, defaultRdonly, baseTabletID+200) + + ctx := context.Background() + vstreamConn, err := vtgateconn.Dial(ctx, fmt.Sprintf("%s:%d", vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateGrpcPort)) + if err != nil { + log.Fatal(err) + } + defer vstreamConn.Close() + vgtid := &binlogdatapb.VGtid{ + ShardGtids: []*binlogdatapb.ShardGtid{{ + Keyspace: "sharded", + Gtid: "current", + }}} + + filter := &binlogdatapb.Filter{ + Rules: []*binlogdatapb.Rule{{ + Match: "customer", + Filter: "select * from customer", + }}, + } + flags := &vtgatepb.VStreamFlags{HeartbeatInterval: 3600, StopOnReshard: stopOnReshard} + done := false + + id := 1000 + // first goroutine that keeps inserting rows into table being streamed until a minute after reshard + // * if StopOnReshard is false we should keep getting events on the new shards + // * if StopOnReshard is true we should get a journal event and no events on the new shards + go func() { + for { + if done { + return + } + id++ + time.Sleep(1 * time.Second) + insertRow("sharded", "customer", id) + } + }() + // stream events from the VStream API + var ne numEvents + go func() { + var reader vtgateconn.VStreamReader + reader, err = vstreamConn.VStream(ctx, topodatapb.TabletType_MASTER, vgtid, filter, flags) + require.NoError(t, err) + connect := false + numErrors := 0 + for { + if connect { // if vtgate returns a transient error try reconnecting from the last seen vgtid + reader, err = vstreamConn.VStream(ctx, topodatapb.TabletType_MASTER, vgtid, filter, flags) + require.NoError(t, err) + connect = false + } + evs, err := reader.Recv() + + switch err { + case nil: + for _, ev := range evs { + switch ev.Type { + case binlogdatapb.VEventType_VGTID: + vgtid = ev.Vgtid + case binlogdatapb.VEventType_ROW: + // BACKPORT: https://github.com/vitessio/vitess/pull/8598 + // shard := ev.RowEvent.Shard + // switch shard { + // case "-80": + // ne.numLessThan80Events++ + // case "80-": + // ne.numGreaterThan80Events++ + // case "-40": + // ne.numLessThan40Events++ + // case "40-": + // ne.numGreaterThan40Events++ + // } + ne.numRowEvents++ + case binlogdatapb.VEventType_JOURNAL: + ne.numJournalEvents++ + } + } + case io.EOF: + log.Infof("Stream Ended") + done = true + default: + log.Infof("%s:: remote error: %v", time.Now(), err) + numErrors++ + if numErrors > 10 { // if vtgate is continuously unavailable error the test + return + } + if strings.Contains(strings.ToLower(err.Error()), "unavailable") { + // this should not happen, but maybe the buffering logic might return a transient + // error during resharding. So adding this logic to reduce future flakiness + time.Sleep(100 * time.Millisecond) + connect = true + } else { + // failure, stop test + done = true + } + } + if done { + return + } + } + }() + + ticker := time.NewTicker(1 * time.Second) + tickCount := 0 + for { + <-ticker.C + tickCount++ + switch tickCount { + case 1: + reshard(t, "sharded", "customer", "vstreamStopOnReshard", "-80,80-", "-40,40-", baseTabletID+400, nil, nil, nil, defaultCellName) + case 60: + done = true + } + if done { + break + } + } + return &ne +} + +func TestVStreamStopOnReshardTrue(t *testing.T) { + ne := testVStreamStopOnReshardFlag(t, true, 1000) + require.Greater(t, ne.numJournalEvents, int64(0)) + require.NotZero(t, ne.numRowEvents) + // BACKPORT: Feature not needed https://github.com/vitessio/vitess/pull/8598 + // require.NotZero(t, ne.numLessThan80Events) + // require.NotZero(t, ne.numGreaterThan80Events) + // require.Zero(t, ne.numLessThan40Events) + // require.Zero(t, ne.numGreaterThan40Events) +} + +func TestVStreamStopOnReshardFalse(t *testing.T) { + ne := testVStreamStopOnReshardFlag(t, false, 2000) + require.Equal(t, int64(0), ne.numJournalEvents) + require.NotZero(t, ne.numRowEvents) + // BACKPORT: Feature not needed https://github.com/vitessio/vitess/pull/8598 + // require.NotZero(t, ne.numLessThan80Events) + // require.NotZero(t, ne.numGreaterThan80Events) + // require.NotZero(t, ne.numLessThan40Events) + // require.NotZero(t, ne.numGreaterThan40Events) +} diff --git a/go/test/endtoend/vtgate/main_test.go b/go/test/endtoend/vtgate/main_test.go index a8b8baea1d8..672a6dcfb3d 100644 --- a/go/test/endtoend/vtgate/main_test.go +++ b/go/test/endtoend/vtgate/main_test.go @@ -434,6 +434,7 @@ func TestMain(m *testing.M) { return 1 } + clusterInstance.VtGateExtraArgs = append(clusterInstance.VtGateExtraArgs, "-enable_system_settings=true") // Start vtgate err = clusterInstance.StartVtgate() if err != nil { diff --git a/go/test/endtoend/vtgate/misc_test.go b/go/test/endtoend/vtgate/misc_test.go index afce3631a5f..4e813c0a715 100644 --- a/go/test/endtoend/vtgate/misc_test.go +++ b/go/test/endtoend/vtgate/misc_test.go @@ -659,6 +659,71 @@ func TestDeleteAlias(t *testing.T) { exec(t, conn, "delete t.* from t1 t where t.id1 = 1") } +func TestFunctionInDefault(t *testing.T) { + defer cluster.PanicHandler(t) + ctx := context.Background() + conn, err := mysql.Connect(ctx, &vtParams) + require.NoError(t, err) + defer conn.Close() + + // set the sql mode ALLOW_INVALID_DATES + exec(t, conn, `SET sql_mode = 'ALLOW_INVALID_DATES'`) + + _, err = conn.ExecuteFetch(`create table function_default (x varchar(25) DEFAULT (TRIM(" check ")))`, 1000, true) + // this query fails because mysql57 does not support functions in default clause + require.Error(t, err) + + // verify that currenet_timestamp and it's aliases work as default values + exec(t, conn, `create table function_default ( +ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, +dt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, +ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP, +dt2 DATETIME DEFAULT CURRENT_TIMESTAMP, +ts3 TIMESTAMP DEFAULT 0, +dt3 DATETIME DEFAULT 0, +ts4 TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP, +dt4 DATETIME DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP, +ts5 TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, +ts6 TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP, +dt5 DATETIME ON UPDATE CURRENT_TIMESTAMP, +dt6 DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP, +ts7 TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), +ts8 TIMESTAMP DEFAULT NOW(), +ts9 TIMESTAMP DEFAULT LOCALTIMESTAMP, +ts10 TIMESTAMP DEFAULT LOCALTIME, +ts11 TIMESTAMP DEFAULT LOCALTIMESTAMP(), +ts12 TIMESTAMP DEFAULT LOCALTIME() +)`) + exec(t, conn, "drop table function_default") + + _, err = conn.ExecuteFetch(`create table function_default (ts TIMESTAMP DEFAULT UTC_TIMESTAMP)`, 1000, true) + // this query fails because utc_timestamp is not supported in default clause + require.Error(t, err) + + exec(t, conn, `create table function_default (x varchar(25) DEFAULT "check")`) + exec(t, conn, "drop table function_default") +} + +func TestRenameFieldsOnOLAP(t *testing.T) { + defer cluster.PanicHandler(t) + ctx := context.Background() + conn, err := mysql.Connect(ctx, &vtParams) + require.NoError(t, err) + defer conn.Close() + + _ = exec(t, conn, "set workload = olap") + defer func() { + exec(t, conn, "set workload = oltp") + }() + + qr := exec(t, conn, "show tables") + require.Equal(t, 1, len(qr.Fields)) + assert.Equal(t, `Tables_in_ks`, fmt.Sprintf("%v", qr.Fields[0].Name)) + _ = exec(t, conn, "use mysql") + qr = exec(t, conn, "select @@workload") + assert.Equal(t, `[[VARBINARY("OLAP")]]`, fmt.Sprintf("%v", qr.Rows)) +} + func assertMatches(t *testing.T, conn *mysql.Conn, query, expected string) { t.Helper() qr := exec(t, conn, query) diff --git a/go/test/endtoend/vtgate/mysql80/main_test.go b/go/test/endtoend/vtgate/mysql80/main_test.go new file mode 100644 index 00000000000..e3dfa1319c5 --- /dev/null +++ b/go/test/endtoend/vtgate/mysql80/main_test.go @@ -0,0 +1,71 @@ +/* +Copyright 2021 The Vitess Authors. + +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 vtgate + +import ( + "flag" + "os" + "testing" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/test/endtoend/cluster" +) + +var ( + clusterInstance *cluster.LocalProcessCluster + vtParams mysql.ConnParams + KeyspaceName = "ks" + Cell = "test" +) + +func TestMain(m *testing.M) { + defer cluster.PanicHandler(nil) + flag.Parse() + + exitCode := func() int { + clusterInstance = cluster.NewCluster(Cell, "localhost") + defer clusterInstance.Teardown() + + // Start topo server + err := clusterInstance.StartTopo() + if err != nil { + return 1 + } + + // Start keyspace + keyspace := &cluster.Keyspace{ + Name: KeyspaceName, + } + err = clusterInstance.StartUnshardedKeyspace(*keyspace, 0, false) + if err != nil { + return 1 + } + + clusterInstance.VtGateExtraArgs = append(clusterInstance.VtGateExtraArgs, "-enable_system_settings=true") + // Start vtgate + err = clusterInstance.StartVtgate() + if err != nil { + return 1 + } + vtParams = mysql.ConnParams{ + Host: clusterInstance.Hostname, + Port: clusterInstance.VtgateMySQLPort, + } + return m.Run() + }() + os.Exit(exitCode) +} diff --git a/go/test/endtoend/vtgate/mysql80/misc_test.go b/go/test/endtoend/vtgate/mysql80/misc_test.go new file mode 100644 index 00000000000..0f614535dc1 --- /dev/null +++ b/go/test/endtoend/vtgate/mysql80/misc_test.go @@ -0,0 +1,79 @@ +/* +Copyright 2021 The Vitess Authors. + +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 vtgate + +import ( + "context" + "testing" + + "vitess.io/vitess/go/test/endtoend/cluster" + + "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/sqltypes" +) + +func TestFunctionInDefault(t *testing.T) { + defer cluster.PanicHandler(t) + ctx := context.Background() + conn, err := mysql.Connect(ctx, &vtParams) + require.NoError(t, err) + defer conn.Close() + + // set the sql mode ALLOW_INVALID_DATES + exec(t, conn, `SET sql_mode = 'ALLOW_INVALID_DATES'`) + + exec(t, conn, `create table function_default (x varchar(25) DEFAULT (TRIM(" check ")))`) + exec(t, conn, "drop table function_default") + + exec(t, conn, `create table function_default ( +ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, +dt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, +ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP, +dt2 DATETIME DEFAULT CURRENT_TIMESTAMP, +ts3 TIMESTAMP DEFAULT 0, +dt3 DATETIME DEFAULT 0, +ts4 TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP, +dt4 DATETIME DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP, +ts5 TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, +ts6 TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP, +dt5 DATETIME ON UPDATE CURRENT_TIMESTAMP, +dt6 DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP, +ts7 TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), +ts8 TIMESTAMP DEFAULT NOW(), +ts9 TIMESTAMP DEFAULT LOCALTIMESTAMP, +ts10 TIMESTAMP DEFAULT LOCALTIME, +ts11 TIMESTAMP DEFAULT LOCALTIMESTAMP(), +ts12 TIMESTAMP DEFAULT LOCALTIME() +)`) + exec(t, conn, "drop table function_default") + + // this query works because utc_timestamp will get parenthesised before reaching MySQL. However, this syntax is not supported in MySQL 8.0 + exec(t, conn, `create table function_default (ts TIMESTAMP DEFAULT UTC_TIMESTAMP)`) + exec(t, conn, "drop table function_default") + + exec(t, conn, `create table function_default (x varchar(25) DEFAULT "check")`) + exec(t, conn, "drop table function_default") +} + +func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { + t.Helper() + qr, err := conn.ExecuteFetch(query, 1000, true) + require.NoError(t, err, "for query: "+query) + return qr +} diff --git a/go/test/endtoend/vtgate/queries/normalize/main_test.go b/go/test/endtoend/vtgate/queries/normalize/main_test.go new file mode 100644 index 00000000000..7d7e6cd8011 --- /dev/null +++ b/go/test/endtoend/vtgate/queries/normalize/main_test.go @@ -0,0 +1,92 @@ +/* +Copyright 2021 The Vitess Authors. + +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 normalize + +import ( + "flag" + "os" + "testing" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/test/endtoend/cluster" +) + +var ( + clusterInstance *cluster.LocalProcessCluster + vtParams mysql.ConnParams + KeyspaceName = "ks_normalize" + Cell = "test_normalize" + SchemaSQL = ` +create table t1( + id bigint unsigned not null, + charcol char(10), + vcharcol varchar(50), + bincol binary(50), + varbincol varbinary(50), + floatcol float, + deccol decimal(5,2), + bitcol bit, + datecol date, + enumcol enum('small', 'medium', 'large'), + setcol set('a', 'b', 'c'), + jsoncol json, + geocol geometry, + primary key(id) +) Engine=InnoDB; +` +) + +func TestMain(m *testing.M) { + defer cluster.PanicHandler(nil) + flag.Parse() + + exitCode := func() int { + clusterInstance = cluster.NewCluster(Cell, "localhost") + defer clusterInstance.Teardown() + + // Start topo server + err := clusterInstance.StartTopo() + if err != nil { + return 1 + } + + // Start keyspace + keyspace := &cluster.Keyspace{ + Name: KeyspaceName, + SchemaSQL: SchemaSQL, + } + clusterInstance.VtGateExtraArgs = []string{} + clusterInstance.VtTabletExtraArgs = []string{} + err = clusterInstance.StartKeyspace(*keyspace, []string{"-"}, 1, false) + if err != nil { + return 1 + } + + // Start vtgate + err = clusterInstance.StartVtgate() + if err != nil { + return 1 + } + + vtParams = mysql.ConnParams{ + Host: clusterInstance.Hostname, + Port: clusterInstance.VtgateMySQLPort, + } + return m.Run() + }() + os.Exit(exitCode) +} diff --git a/go/test/endtoend/vtgate/queries/normalize/normalize_test.go b/go/test/endtoend/vtgate/queries/normalize/normalize_test.go new file mode 100644 index 00000000000..bf56beb1e63 --- /dev/null +++ b/go/test/endtoend/vtgate/queries/normalize/normalize_test.go @@ -0,0 +1,82 @@ +/* +Copyright 2021 The Vitess Authors. + +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 normalize + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/test/endtoend/vtgate/utils" +) + +func TestNormalizeAllFields(t *testing.T) { + conn, err := mysql.Connect(context.Background(), &vtParams) + require.NoError(t, err) + defer conn.Close() + + insertQuery := string(`insert into t1 values (1, "chars", "variable chars", x'73757265', 0x676F, 0.33, 9.99, 1, "1976-06-08", "small", "b", "{\"key\":\"value\"}", point(1,5))`) + normalizedInsertQuery := string(`insert into t1 values (:vtg1, :vtg2, :vtg3, :vtg4, :vtg5, :vtg6, :vtg7, :vtg8, :vtg9, :vtg10, :vtg11, :vtg12, point(:vtg13, :vtg14))`) + selectQuery := "select * from t1" + utils.Exec(t, conn, insertQuery) + qr := utils.Exec(t, conn, selectQuery) + assert.Equal(t, 1, len(qr.Rows), "wrong number of table rows, expected 1 but had %d. Results: %v", len(qr.Rows), qr.Rows) + + // Now need to figure out the best way to check the normalized query in the planner cache... + results, err := getPlanCache(fmt.Sprintf("%s:%d", clusterInstance.Hostname, clusterInstance.VtgateProcess.Port)) + require.Nil(t, err) + found := false + for _, record := range results { + key := record["Key"].(string) + if key == normalizedInsertQuery { + found = true + break + } + } + assert.True(t, found, "correctly normalized record not found in planner cache") +} + +func getPlanCache(vtgateHostPort string) ([]map[string]interface{}, error) { + var results []map[string]interface{} + client := http.Client{ + Timeout: 10 * time.Second, + } + resp, err := client.Get(fmt.Sprintf("http://%s/debug/query_plans", vtgateHostPort)) + if err != nil { + return results, err + } + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + return results, err + } + + err = json.Unmarshal(body, &results) + if err != nil { + return results, err + } + + return results, nil +} diff --git a/go/test/endtoend/vtgate/utils/utils.go b/go/test/endtoend/vtgate/utils/utils.go new file mode 100644 index 00000000000..2b0ff0cee62 --- /dev/null +++ b/go/test/endtoend/vtgate/utils/utils.go @@ -0,0 +1,100 @@ +/* +Copyright 2021 The Vitess Authors. + +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. + +BACKPORT: Merge pull request #9145 from planetscale/NormalizeHexValuesInQueries +BACKPORT: https://github.com/vitessio/vitess/pull/9145/commits/322ac090ab12676d79cc855cc7f381a62e2d414c +*/ + +package utils + +import ( + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/test/utils" +) + +func AssertMatches(t *testing.T, conn *mysql.Conn, query, expected string) { + t.Helper() + qr := Exec(t, conn, query) + got := fmt.Sprintf("%v", qr.Rows) + diff := cmp.Diff(expected, got) + if diff != "" { + t.Errorf("Query: %s (-want +got):\n%s", query, diff) + } +} + +func AssertContainsError(t *testing.T, conn *mysql.Conn, query, expected string) { + t.Helper() + _, err := ExecAllowError(t, conn, query) + require.Error(t, err) + require.Contains(t, err.Error(), expected) +} + +func AssertMatchesNoOrder(t *testing.T, conn *mysql.Conn, query, expected string) { + t.Helper() + qr := Exec(t, conn, query) + actual := fmt.Sprintf("%v", qr.Rows) + assert.Equal(t, utils.SortString(expected), utils.SortString(actual), "for query: [%s] expected \n%s \nbut actual \n%s", query, expected, actual) +} + +func AssertIsEmpty(t *testing.T, conn *mysql.Conn, query string) { + t.Helper() + qr := Exec(t, conn, query) + assert.Empty(t, qr.Rows, "for query: "+query) +} + +func AssertFoundRowsValue(t *testing.T, conn *mysql.Conn, query, workload string, count int) { + Exec(t, conn, query) + qr := Exec(t, conn, "select found_rows()") + got := fmt.Sprintf("%v", qr.Rows) + want := fmt.Sprintf(`[[UINT64(%d)]]`, count) + assert.Equalf(t, want, got, "Workload: %s\nQuery:%s\n", workload, query) +} + +func AssertSingleRowIsReturned(t *testing.T, conn *mysql.Conn, predicate string, expectedKs string) { + t.Run(predicate, func(t *testing.T) { + qr, err := conn.ExecuteFetch("SELECT distinct table_schema FROM information_schema.tables WHERE "+predicate, 1000, true) + require.NoError(t, err) + assert.Equal(t, 1, len(qr.Rows), "did not get enough rows back") + assert.Equal(t, expectedKs, qr.Rows[0][0].ToString()) + }) +} + +func AssertResultIsEmpty(t *testing.T, conn *mysql.Conn, pre string) { + t.Run(pre, func(t *testing.T) { + qr, err := conn.ExecuteFetch("SELECT distinct table_schema FROM information_schema.tables WHERE "+pre, 1000, true) + require.NoError(t, err) + assert.Empty(t, qr.Rows) + }) +} + +func Exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { + t.Helper() + qr, err := conn.ExecuteFetch(query, 1000, true) + require.NoError(t, err, "for query: "+query) + return qr +} + +func ExecAllowError(t *testing.T, conn *mysql.Conn, query string) (*sqltypes.Result, error) { + t.Helper() + return conn.ExecuteFetch(query, 1000, true) +} diff --git a/go/vt/binlog/binlog_streamer.go b/go/vt/binlog/binlog_streamer.go index 986b1bfdf3e..5d5ca6658e9 100644 --- a/go/vt/binlog/binlog_streamer.go +++ b/go/vt/binlog/binlog_streamer.go @@ -754,7 +754,7 @@ func writeValuesAsSQL(sql *sqlparser.TrackedBuffer, tce *tableCacheEntry, rs *my } // We have real data. - value, l, err := mysql.CellValue(data, pos, tce.tm.Types[c], tce.tm.Metadata[c], tce.ti.Fields[c].Type) + value, l, err := mysql.CellValue(data, pos, tce.tm.Types[c], tce.tm.Metadata[c], &querypb.Field{Type: tce.ti.Fields[c].Type}) if err != nil { return keyspaceIDCell, nil, err } @@ -815,7 +815,7 @@ func writeIdentifiersAsSQL(sql *sqlparser.TrackedBuffer, tce *tableCacheEntry, r sql.WriteByte('=') // We have real data. - value, l, err := mysql.CellValue(data, pos, tce.tm.Types[c], tce.tm.Metadata[c], tce.ti.Fields[c].Type) + value, l, err := mysql.CellValue(data, pos, tce.tm.Types[c], tce.tm.Metadata[c], &querypb.Field{Type: tce.ti.Fields[c].Type}) if err != nil { return keyspaceIDCell, nil, err } diff --git a/go/vt/binlog/binlogplayer/binlog_player.go b/go/vt/binlog/binlogplayer/binlog_player.go index fb5c9272edd..bde74f0690f 100644 --- a/go/vt/binlog/binlogplayer/binlog_player.go +++ b/go/vt/binlog/binlogplayer/binlog_player.go @@ -695,10 +695,7 @@ func DeleteVReplication(uid uint32) string { // MessageTruncate truncates the message string to a safe length. func MessageTruncate(msg string) string { // message length is 1000 bytes. - if len(msg) > 950 { - return msg[:950] + "..." - } - return msg + return LimitString(msg, 950) } func encodeString(in string) string { diff --git a/go/vt/binlog/binlogplayer/dbclient.go b/go/vt/binlog/binlogplayer/dbclient.go index 7dfeb36f2a4..5ad73b686a6 100644 --- a/go/vt/binlog/binlogplayer/dbclient.go +++ b/go/vt/binlog/binlogplayer/dbclient.go @@ -74,7 +74,7 @@ func (dc *dbClientImpl) Connect() error { func (dc *dbClientImpl) Begin() error { _, err := dc.dbConn.ExecuteFetch("begin", 1, false) if err != nil { - log.Errorf("BEGIN failed w/ error %v", err) + LogError("BEGIN failed w/ error", err) dc.handleError(err) } return err @@ -83,7 +83,7 @@ func (dc *dbClientImpl) Begin() error { func (dc *dbClientImpl) Commit() error { _, err := dc.dbConn.ExecuteFetch("commit", 1, false) if err != nil { - log.Errorf("COMMIT failed w/ error %v", err) + LogError("COMMIT failed w/ error", err) dc.dbConn.Close() } return err @@ -92,7 +92,7 @@ func (dc *dbClientImpl) Commit() error { func (dc *dbClientImpl) Rollback() error { _, err := dc.dbConn.ExecuteFetch("rollback", 1, false) if err != nil { - log.Errorf("ROLLBACK failed w/ error %v", err) + LogError("ROLLBACK failed w/ error", err) dc.dbConn.Close() } return err @@ -102,10 +102,22 @@ func (dc *dbClientImpl) Close() { dc.dbConn.Close() } +// LogError logs a message after truncating it to avoid spamming logs +func LogError(msg string, err error) { + log.Errorf("%s: %s", msg, MessageTruncate(err.Error())) +} + +// LimitString truncates string to specified size +func LimitString(s string, limit int) string { + if len(s) > limit { + return s[:limit] + } + return s +} + func (dc *dbClientImpl) ExecuteFetch(query string, maxrows int) (*sqltypes.Result, error) { mqr, err := dc.dbConn.ExecuteFetch(query, maxrows, true) if err != nil { - log.Errorf("ExecuteFetch failed w/ error %v", err) dc.handleError(err) return nil, err } diff --git a/go/vt/binlog/binlogplayer/fake_dbclient.go b/go/vt/binlog/binlogplayer/fake_dbclient.go index 3b794dafd72..186722cf12f 100644 --- a/go/vt/binlog/binlogplayer/fake_dbclient.go +++ b/go/vt/binlog/binlogplayer/fake_dbclient.go @@ -68,10 +68,10 @@ func (dc *fakeDBClient) ExecuteFetch(query string, maxrows int) (qr *sqltypes.Re if strings.Contains(query, "where") { return sqltypes.MakeTestResult( sqltypes.MakeTestFields( - "id|state|source", - "int64|varchar|varchar", + "id|state|source|message", + "int64|varchar|varchar|varchar", ), - `1|Running|keyspace:"ks" shard:"0" key_range: `, + `1|Running|keyspace:"ks" shard:"0" key_range: |`, ), nil } return &sqltypes.Result{}, nil diff --git a/go/vt/discovery/tablet_picker.go b/go/vt/discovery/tablet_picker.go index af813ae13e9..dea4d7d7def 100644 --- a/go/vt/discovery/tablet_picker.go +++ b/go/vt/discovery/tablet_picker.go @@ -23,6 +23,8 @@ import ( "sync" "time" + "vitess.io/vitess/go/stats" + "vitess.io/vitess/go/vt/topo/topoproto" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" @@ -41,6 +43,7 @@ import ( var ( tabletPickerRetryDelay = 30 * time.Second muTabletPickerRetryDelay sync.Mutex + globalTPStats *tabletPickerStats ) // GetTabletPickerRetryDelay synchronizes changes to tabletPickerRetryDelay. Used in tests only at the moment @@ -108,11 +111,11 @@ func (tp *TabletPicker) PickForStreaming(ctx context.Context) (*topodatapb.Table default: } candidates := tp.GetMatchingTablets(ctx) - if len(candidates) == 0 { // if no candidates were found, sleep and try again - log.Infof("No tablet found for streaming, shard %s.%s, cells %v, tabletTypes %v, sleeping for %d seconds", - tp.keyspace, tp.shard, tp.cells, tp.tabletTypes, int(GetTabletPickerRetryDelay()/1e9)) + tp.incNoTabletFoundStat() + log.Infof("No tablet found for streaming, shard %s.%s, cells %v, tabletTypes %v, sleeping for %.3f seconds", + tp.keyspace, tp.shard, tp.cells, tp.tabletTypes, float64(GetTabletPickerRetryDelay().Milliseconds())/1000.0) timer := time.NewTimer(GetTabletPickerRetryDelay()) select { case <-ctx.Done(): @@ -133,6 +136,7 @@ func (tp *TabletPicker) PickForStreaming(ctx context.Context) (*topodatapb.Table log.Warningf("unable to connect to tablet for alias %v", ti.Alias) candidates = append(candidates[:idx], candidates[idx+1:]...) if len(candidates) == 0 { + tp.incNoTabletFoundStat() break } continue @@ -156,6 +160,7 @@ func (tp *TabletPicker) GetMatchingTablets(ctx context.Context) []*topo.TabletIn defer cancel() si, err := tp.ts.GetShard(shortCtx, tp.keyspace, tp.shard) if err != nil { + log.Errorf("error getting shard %s/%s: %s", tp.keyspace, tp.shard, err.Error()) return nil } aliases = append(aliases, si.MasterAlias) @@ -226,4 +231,25 @@ func (tp *TabletPicker) GetMatchingTablets(ctx context.Context) []*topo.TabletIn func init() { // TODO(sougou): consolidate this call to be once per process. rand.Seed(time.Now().UnixNano()) + globalTPStats = newTabletPickerStats() +} + +type tabletPickerStats struct { + mu sync.Mutex + noTabletFoundError *stats.CountersWithMultiLabels +} + +func newTabletPickerStats() *tabletPickerStats { + tpStats := &tabletPickerStats{} + tpStats.noTabletFoundError = stats.NewCountersWithMultiLabels("TabletPickerNoTabletFoundErrorCount", "", []string{"cells", "keyspace", "shard", "types"}) + return tpStats +} + +func (tp *TabletPicker) incNoTabletFoundStat() { + globalTPStats.mu.Lock() + defer globalTPStats.mu.Unlock() + cells := strings.Join(tp.cells, "_") + tabletTypes := strings.Join(topoproto.MakeStringTypeList(tp.tabletTypes), "_") + labels := []string{cells, tp.keyspace, tp.shard, tabletTypes} + globalTPStats.noTabletFoundError.Add(labels, 1) } diff --git a/go/vt/discovery/tablet_picker_test.go b/go/vt/discovery/tablet_picker_test.go index 94bfe4d56e1..64e8cea0f44 100644 --- a/go/vt/discovery/tablet_picker_test.go +++ b/go/vt/discovery/tablet_picker_test.go @@ -329,6 +329,7 @@ func TestPickError(t *testing.T) { defer cancel() _, err = tp.PickForStreaming(ctx) require.EqualError(t, err, "context has expired") + require.Greater(t, globalTPStats.noTabletFoundError.Counts()["cell.ks.0.replica"], int64(0)) } type pickerTestEnv struct { diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index aea3a374859..6b837e909e6 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -1140,3 +1140,8 @@ func buildLdPaths() ([]string, error) { return ldPaths, nil } + +// GetVersionString is part of the MysqlDeamon interface. +func (mysqld *Mysqld) GetVersionString() string { + return fmt.Sprintf("%d.%d.%d", mysqld.capabilities.version.Major, mysqld.capabilities.version.Minor, mysqld.capabilities.version.Patch) +} diff --git a/go/vt/proto/query/query.pb.go b/go/vt/proto/query/query.pb.go index 5fe31689846..2fee5da065c 100644 --- a/go/vt/proto/query/query.pb.go +++ b/go/vt/proto/query/query.pb.go @@ -306,6 +306,12 @@ const ( // This type is for internal use only. // Properties: 31, None. Type_EXPRESSION Type = 31 + // HEXNUM specifies a HEXNUM type (unquoted varbinary). + // Properties: 32, IsText. + Type_HEXNUM Type = 4128 + // HEXVAL specifies a HEXVAL type (unquoted varbinary). + // Properties: 33, IsText. + Type_HEXVAL Type = 4129 ) // Enum value maps for Type. @@ -343,6 +349,8 @@ var ( 2077: "GEOMETRY", 2078: "JSON", 31: "EXPRESSION", + 4128: "HEXNUM", + 4129: "HEXVAL", } Type_value = map[string]int32{ "NULL_TYPE": 0, @@ -377,6 +385,8 @@ var ( "GEOMETRY": 2077, "JSON": 2078, "EXPRESSION": 31, + "HEXNUM": 4128, + "HEXVAL": 4129, } ) @@ -5749,7 +5759,7 @@ var file_query_proto_rawDesc = []byte{ 0x44, 0x10, 0x80, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x53, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, 0x80, 0x08, 0x12, 0x0d, 0x0a, 0x08, 0x49, 0x53, 0x51, 0x55, 0x4f, 0x54, 0x45, 0x44, 0x10, 0x80, 0x10, 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x53, 0x54, 0x45, 0x58, 0x54, 0x10, 0x80, 0x20, 0x12, 0x0d, - 0x0a, 0x08, 0x49, 0x53, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x80, 0x40, 0x2a, 0x99, 0x03, + 0x0a, 0x08, 0x49, 0x53, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x80, 0x40, 0x2a, 0xb3, 0x03, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x55, 0x4c, 0x4c, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x04, 0x49, 0x4e, 0x54, 0x38, 0x10, 0x81, 0x02, 0x12, 0x0a, 0x0a, 0x05, 0x55, 0x49, 0x4e, 0x54, 0x38, 0x10, 0x82, 0x06, 0x12, 0x0a, 0x0a, 0x05, @@ -5775,15 +5785,17 @@ var file_query_proto_rawDesc = []byte{ 0x54, 0x10, 0x9b, 0x10, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x55, 0x50, 0x4c, 0x45, 0x10, 0x1c, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x45, 0x4f, 0x4d, 0x45, 0x54, 0x52, 0x59, 0x10, 0x9d, 0x10, 0x12, 0x09, 0x0a, 0x04, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x9e, 0x10, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x58, 0x50, - 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x1f, 0x2a, 0x46, 0x0a, 0x10, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, - 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, - 0x45, 0x50, 0x41, 0x52, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4d, 0x4d, 0x49, - 0x54, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x4f, 0x4c, 0x4c, 0x42, 0x41, 0x43, 0x4b, 0x10, - 0x03, 0x42, 0x35, 0x0a, 0x0f, 0x69, 0x6f, 0x2e, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x22, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6f, 0x2f, - 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x74, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x1f, 0x12, 0x0b, 0x0a, 0x06, 0x48, 0x45, 0x58, + 0x4e, 0x55, 0x4d, 0x10, 0xa0, 0x20, 0x12, 0x0b, 0x0a, 0x06, 0x48, 0x45, 0x58, 0x56, 0x41, 0x4c, + 0x10, 0xa1, 0x20, 0x2a, 0x46, 0x0a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, + 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, 0x45, 0x50, 0x41, 0x52, 0x45, 0x10, + 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x02, 0x12, 0x0c, 0x0a, + 0x08, 0x52, 0x4f, 0x4c, 0x4c, 0x42, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x42, 0x35, 0x0a, 0x0f, 0x69, + 0x6f, 0x2e, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x22, + 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, + 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/go/vt/proto/vtgate/vtgate.pb.go b/go/vt/proto/vtgate/vtgate.pb.go index de9839b842a..90ced00d24f 100644 --- a/go/vt/proto/vtgate/vtgate.pb.go +++ b/go/vt/proto/vtgate/vtgate.pb.go @@ -1062,6 +1062,8 @@ type VStreamFlags struct { MinimizeSkew bool `protobuf:"varint,1,opt,name=minimize_skew,json=minimizeSkew,proto3" json:"minimize_skew,omitempty"` // how often heartbeats must be sent when idle (seconds) HeartbeatInterval uint32 `protobuf:"varint,2,opt,name=heartbeat_interval,json=heartbeatInterval,proto3" json:"heartbeat_interval,omitempty"` + // stop streams on a reshard (journal event) + StopOnReshard bool `protobuf:"varint,3,opt,name=stop_on_reshard,json=stopOnReshard,proto3" json:"stop_on_reshard,omitempty"` } func (x *VStreamFlags) Reset() { @@ -1110,6 +1112,13 @@ func (x *VStreamFlags) GetHeartbeatInterval() uint32 { return 0 } +func (x *VStreamFlags) GetStopOnReshard() bool { + if x != nil { + return x.StopOnReshard + } + return false +} + // VStreamRequest is the payload for VStream. type VStreamRequest struct { state protoimpl.MessageState @@ -1761,74 +1770,77 @@ var file_vtgate_proto_rawDesc = []byte{ 0x49, 0x44, 0x52, 0x08, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x74, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x74, 0x69, 0x64, 0x22, 0x1c, 0x0a, 0x1a, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x62, - 0x0a, 0x0c, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x23, - 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x73, 0x6b, 0x65, 0x77, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x53, - 0x6b, 0x65, 0x77, 0x12, 0x2d, 0x0a, 0x12, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, - 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x11, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, - 0x61, 0x6c, 0x22, 0xf6, 0x01, 0x0a, 0x0e, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x08, 0x63, 0x61, 0x6c, 0x6c, 0x65, - 0x72, 0x49, 0x64, 0x12, 0x35, 0x0a, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, - 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, - 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x67, - 0x74, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x69, 0x6e, 0x6c, - 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x47, 0x74, 0x69, 0x64, 0x52, 0x05, 0x76, 0x67, - 0x74, 0x69, 0x64, 0x12, 0x2a, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, - 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, - 0x2a, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, - 0x2e, 0x76, 0x74, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x46, - 0x6c, 0x61, 0x67, 0x73, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x22, 0x3d, 0x0a, 0x0f, 0x56, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, - 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, - 0x2e, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x92, 0x01, 0x0a, 0x0e, 0x50, - 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, - 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, - 0x44, 0x52, 0x08, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x07, 0x73, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, - 0x74, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x42, 0x6f, - 0x75, 0x6e, 0x64, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, - 0x89, 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x29, 0x0a, 0x07, 0x73, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, - 0x67, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x46, 0x69, - 0x65, 0x6c, 0x64, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0x6e, 0x0a, 0x13, 0x43, - 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, - 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x08, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, - 0x12, 0x29, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3d, 0x0a, 0x14, 0x43, - 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2a, 0x44, 0x0a, 0x0f, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0f, 0x0a, - 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0a, - 0x0a, 0x06, 0x53, 0x49, 0x4e, 0x47, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x55, - 0x4c, 0x54, 0x49, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x57, 0x4f, 0x50, 0x43, 0x10, 0x03, - 0x2a, 0x3c, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, - 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x50, - 0x52, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x4f, 0x53, 0x54, 0x10, 0x02, 0x12, 0x0e, - 0x0a, 0x0a, 0x41, 0x55, 0x54, 0x4f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x03, 0x42, 0x36, - 0x0a, 0x0f, 0x69, 0x6f, 0x2e, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x5a, 0x23, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x76, 0x69, 0x74, - 0x65, 0x73, 0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x76, 0x74, 0x67, 0x61, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8a, + 0x01, 0x0a, 0x0c, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, + 0x23, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x73, 0x6b, 0x65, 0x77, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x69, 0x7a, 0x65, + 0x53, 0x6b, 0x65, 0x77, 0x12, 0x2d, 0x0a, 0x12, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, + 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x11, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x76, 0x61, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x6f, 0x6e, 0x5f, 0x72, + 0x65, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x74, + 0x6f, 0x70, 0x4f, 0x6e, 0x52, 0x65, 0x73, 0x68, 0x61, 0x72, 0x64, 0x22, 0xf6, 0x01, 0x0a, 0x0e, + 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, + 0x0a, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, + 0x49, 0x44, 0x52, 0x08, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x35, 0x0a, 0x0b, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, + 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x67, 0x74, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, 0x2e, + 0x56, 0x47, 0x74, 0x69, 0x64, 0x52, 0x05, 0x76, 0x67, 0x74, 0x69, 0x64, 0x12, 0x2a, 0x0a, 0x06, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, + 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, + 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x76, 0x74, 0x67, 0x61, 0x74, 0x65, + 0x2e, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x52, 0x05, 0x66, + 0x6c, 0x61, 0x67, 0x73, 0x22, 0x3d, 0x0a, 0x0f, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, + 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x22, 0x92, 0x01, 0x0a, 0x0e, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x09, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x08, 0x63, 0x61, 0x6c, 0x6c, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x27, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x89, 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x65, + 0x70, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x12, 0x29, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, + 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, + 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x06, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x73, 0x22, 0x6e, 0x0a, 0x13, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x09, 0x63, + 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, + 0x08, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x07, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x67, + 0x61, 0x74, 0x65, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3d, 0x0a, 0x14, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x2a, 0x44, 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x49, 0x4e, 0x47, 0x4c, + 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x10, 0x02, 0x12, 0x09, + 0x0a, 0x05, 0x54, 0x57, 0x4f, 0x50, 0x43, 0x10, 0x03, 0x2a, 0x3c, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, + 0x41, 0x4c, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x52, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, + 0x04, 0x50, 0x4f, 0x53, 0x54, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x55, 0x54, 0x4f, 0x43, + 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x03, 0x42, 0x36, 0x0a, 0x0f, 0x69, 0x6f, 0x2e, 0x76, 0x69, + 0x74, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x23, 0x76, 0x69, 0x74, 0x65, + 0x73, 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x6f, 0x2f, + 0x76, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x74, 0x67, 0x61, 0x74, 0x65, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/go/vt/proto/vtgate/vtgate_vtproto.pb.go b/go/vt/proto/vtgate/vtgate_vtproto.pb.go index 4fd0983cf21..b8fd70d9975 100644 --- a/go/vt/proto/vtgate/vtgate_vtproto.pb.go +++ b/go/vt/proto/vtgate/vtgate_vtproto.pb.go @@ -1017,6 +1017,16 @@ func (m *VStreamFlags) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if m.StopOnReshard { + i-- + if m.StopOnReshard { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } if m.HeartbeatInterval != 0 { i = encodeVarint(dAtA, i, uint64(m.HeartbeatInterval)) i-- @@ -1803,6 +1813,9 @@ func (m *VStreamFlags) SizeVT() (n int) { if m.HeartbeatInterval != 0 { n += 1 + sov(uint64(m.HeartbeatInterval)) } + if m.StopOnReshard { + n += 2 + } if m.unknownFields != nil { n += len(m.unknownFields) } @@ -4476,6 +4489,26 @@ func (m *VStreamFlags) UnmarshalVT(dAtA []byte) error { break } } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StopOnReshard", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.StopOnReshard = bool(v != 0) default: iNdEx = preIndex skippy, err := skip(dAtA[iNdEx:]) diff --git a/go/vt/schema/tablegc_test.go b/go/vt/schema/tablegc_test.go index dfa03012c8c..90b31ff90fa 100644 --- a/go/vt/schema/tablegc_test.go +++ b/go/vt/schema/tablegc_test.go @@ -21,6 +21,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestIsGCTableName(t *testing.T) { @@ -152,3 +153,16 @@ func TestParseGCLifecycle(t *testing.T) { }) } } + +func TestGenerateRenameStatementWithUUID(t *testing.T) { + uuid := "997342e3_e91d_11eb_aaae_0a43f95f28a3" + tableName := "mytbl" + countIterations := 5 + toTableNames := map[string]bool{} + for i := 0; i < countIterations; i++ { + _, toTableName, err := GenerateRenameStatementWithUUID(tableName, PurgeTableGCState, OnlineDDLToGCUUID(uuid), time.Now().Add(time.Duration(i)*time.Second).UTC()) + require.NoError(t, err) + toTableNames[toTableName] = true + } + assert.Equal(t, countIterations, len(toTableNames)) +} diff --git a/go/vt/servenv/version.go b/go/vt/servenv/version.go index f6f99ade26e..e1afa17fafd 100644 --- a/go/vt/servenv/version.go +++ b/go/vt/servenv/version.go @@ -1,3 +1,3 @@ package servenv -const versionName = "11.0.0-SNAPSHOT" +const versionName = "11.0.4" diff --git a/go/vt/sqlparser/analyzer.go b/go/vt/sqlparser/analyzer.go index f06dc5485cc..e86006a9893 100644 --- a/go/vt/sqlparser/analyzer.go +++ b/go/vt/sqlparser/analyzer.go @@ -62,9 +62,10 @@ const ( StmtFlush StmtCallProc StmtRevert + StmtShowMigrationLogs ) -//ASTToStatementType returns a StatementType from an AST stmt +// ASTToStatementType returns a StatementType from an AST stmt func ASTToStatementType(stmt Statement) StatementType { switch stmt.(type) { case *Select, *Union: @@ -83,6 +84,8 @@ func ASTToStatementType(stmt Statement) StatementType { return StmtDDL case *RevertMigration: return StmtRevert + case *ShowMigrationLogs: + return StmtShowMigrationLogs case *Use: return StmtUse case *OtherRead, *OtherAdmin, *Load: @@ -118,7 +121,7 @@ func ASTToStatementType(stmt Statement) StatementType { } } -//CanNormalize takes Statement and returns if the statement can be normalized. +// CanNormalize takes Statement and returns if the statement can be normalized. func CanNormalize(stmt Statement) bool { switch stmt.(type) { case *Select, *Union, *Insert, *Update, *Delete, *Set, *CallProc, *Stream: // TODO: we could merge this logic into ASTrewriter @@ -137,7 +140,7 @@ func CachePlan(stmt Statement) bool { return false } -//MustRewriteAST takes Statement and returns true if RewriteAST must run on it for correct execution irrespective of user flags. +// MustRewriteAST takes Statement and returns true if RewriteAST must run on it for correct execution irrespective of user flags. func MustRewriteAST(stmt Statement) bool { switch node := stmt.(type) { case *Set: @@ -298,7 +301,7 @@ func IsDML(sql string) bool { return false } -//IsDMLStatement returns true if the query is an INSERT, UPDATE or DELETE statement. +// IsDMLStatement returns true if the query is an INSERT, UPDATE or DELETE statement. func IsDMLStatement(stmt Statement) bool { switch stmt.(type) { case *Insert, *Update, *Delete: @@ -487,7 +490,7 @@ func NewPlanValue(node Expr) (sqltypes.PlanValue, error) { return sqltypes.PlanValue{}, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "expression is too complex '%v'", String(node)) } -//IsLockingFunc returns true for all functions that are used to work with mysql advisory locks +// IsLockingFunc returns true for all functions that are used to work with mysql advisory locks func IsLockingFunc(node Expr) bool { switch p := node.(type) { case *FuncExpr: diff --git a/go/vt/sqlparser/ast.go b/go/vt/sqlparser/ast.go index ee4682a04e7..fd01a4d3c40 100644 --- a/go/vt/sqlparser/ast.go +++ b/go/vt/sqlparser/ast.go @@ -414,6 +414,12 @@ type ( AutoIncSpec *AutoIncSpec } + // ShowMigrationLogs represents a SHOW VITESS_MIGRATION '' LOGS statement + ShowMigrationLogs struct { + UUID string + Comments Comments + } + // RevertMigration represents a REVERT VITESS_MIGRATION statement RevertMigration struct { UUID string @@ -622,6 +628,7 @@ func (*AlterTable) iStatement() {} func (*AlterVschema) iStatement() {} func (*AlterMigration) iStatement() {} func (*RevertMigration) iStatement() {} +func (*ShowMigrationLogs) iStatement() {} func (*DropTable) iStatement() {} func (*DropView) iStatement() {} func (*TruncateTable) iStatement() {} diff --git a/go/vt/sqlparser/ast_clone.go b/go/vt/sqlparser/ast_clone.go index 901029c6aad..95a76116015 100644 --- a/go/vt/sqlparser/ast_clone.go +++ b/go/vt/sqlparser/ast_clone.go @@ -255,6 +255,8 @@ func CloneSQLNode(in SQLNode) SQLNode { return CloneRefOfShowFilter(in) case *ShowLegacy: return CloneRefOfShowLegacy(in) + case *ShowMigrationLogs: + return CloneRefOfShowMigrationLogs(in) case *StarExpr: return CloneRefOfStarExpr(in) case *Stream: @@ -1470,6 +1472,16 @@ func CloneRefOfShowLegacy(n *ShowLegacy) *ShowLegacy { return &out } +// CloneRefOfShowMigrationLogs creates a deep clone of the input. +func CloneRefOfShowMigrationLogs(n *ShowMigrationLogs) *ShowMigrationLogs { + if n == nil { + return nil + } + out := *n + out.Comments = CloneComments(n.Comments) + return &out +} + // CloneRefOfStarExpr creates a deep clone of the input. func CloneRefOfStarExpr(n *StarExpr) *StarExpr { if n == nil { @@ -2182,6 +2194,8 @@ func CloneStatement(in Statement) Statement { return CloneRefOfSetTransaction(in) case *Show: return CloneRefOfShow(in) + case *ShowMigrationLogs: + return CloneRefOfShowMigrationLogs(in) case *Stream: return CloneRefOfStream(in) case *TruncateTable: diff --git a/go/vt/sqlparser/ast_equals.go b/go/vt/sqlparser/ast_equals.go index 7f3ccf22cba..3912d0a284f 100644 --- a/go/vt/sqlparser/ast_equals.go +++ b/go/vt/sqlparser/ast_equals.go @@ -722,6 +722,12 @@ func EqualsSQLNode(inA, inB SQLNode) bool { return false } return EqualsRefOfShowLegacy(a, b) + case *ShowMigrationLogs: + b, ok := inB.(*ShowMigrationLogs) + if !ok { + return false + } + return EqualsRefOfShowMigrationLogs(a, b) case *StarExpr: b, ok := inB.(*StarExpr) if !ok { @@ -2310,6 +2316,18 @@ func EqualsRefOfShowLegacy(a, b *ShowLegacy) bool { EqualsExpr(a.ShowCollationFilterOpt, b.ShowCollationFilterOpt) } +// EqualsRefOfShowMigrationLogs does deep equals between the two objects. +func EqualsRefOfShowMigrationLogs(a, b *ShowMigrationLogs) bool { + if a == b { + return true + } + if a == nil || b == nil { + return false + } + return a.UUID == b.UUID && + EqualsComments(a.Comments, b.Comments) +} + // EqualsRefOfStarExpr does deep equals between the two objects. func EqualsRefOfStarExpr(a, b *StarExpr) bool { if a == b { @@ -3598,6 +3616,12 @@ func EqualsStatement(inA, inB Statement) bool { return false } return EqualsRefOfShow(a, b) + case *ShowMigrationLogs: + b, ok := inB.(*ShowMigrationLogs) + if !ok { + return false + } + return EqualsRefOfShowMigrationLogs(a, b) case *Stream: b, ok := inB.(*Stream) if !ok { diff --git a/go/vt/sqlparser/ast_format.go b/go/vt/sqlparser/ast_format.go index 43e1f7f716f..c1eb5c14da0 100644 --- a/go/vt/sqlparser/ast_format.go +++ b/go/vt/sqlparser/ast_format.go @@ -249,6 +249,11 @@ func (node *RevertMigration) Format(buf *TrackedBuffer) { buf.astPrintf(node, "revert %vvitess_migration '%s'", node.Comments, node.UUID) } +// Format formats the node. +func (node *ShowMigrationLogs) Format(buf *TrackedBuffer) { + buf.astPrintf(node, "show vitess_migration '%s' logs", node.UUID) +} + // Format formats the node. func (node *OptLike) Format(buf *TrackedBuffer) { buf.astPrintf(node, "like %v", node.LikeTable) @@ -471,7 +476,15 @@ func (ct *ColumnType) Format(buf *TrackedBuffer) { } } if ct.Options.Default != nil { - buf.astPrintf(ct, " %s %v", keywordStrings[DEFAULT], ct.Options.Default) + buf.astPrintf(ct, " %s", keywordStrings[DEFAULT]) + _, isLiteral := ct.Options.Default.(*Literal) + _, isBool := ct.Options.Default.(BoolVal) + _, isNullVal := ct.Options.Default.(*NullVal) + if isLiteral || isNullVal || isBool || isExprAliasForCurrentTimeStamp(ct.Options.Default) { + buf.astPrintf(ct, " %v", ct.Options.Default) + } else { + buf.astPrintf(ct, " (%v)", ct.Options.Default) + } } if ct.Options.OnUpdate != nil { buf.astPrintf(ct, " %s %s %v", keywordStrings[ON], keywordStrings[UPDATE], ct.Options.OnUpdate) diff --git a/go/vt/sqlparser/ast_format_fast.go b/go/vt/sqlparser/ast_format_fast.go index 4dd76509ab7..490947725ec 100644 --- a/go/vt/sqlparser/ast_format_fast.go +++ b/go/vt/sqlparser/ast_format_fast.go @@ -381,6 +381,13 @@ func (node *RevertMigration) formatFast(buf *TrackedBuffer) { buf.WriteByte('\'') } +// formatFast formats the node. +func (node *ShowMigrationLogs) formatFast(buf *TrackedBuffer) { + buf.WriteString("show vitess_migration '") + buf.WriteString(node.UUID) + buf.WriteString("' logs") +} + // formatFast formats the node. func (node *OptLike) formatFast(buf *TrackedBuffer) { buf.WriteString("like ") @@ -672,8 +679,17 @@ func (ct *ColumnType) formatFast(buf *TrackedBuffer) { if ct.Options.Default != nil { buf.WriteByte(' ') buf.WriteString(keywordStrings[DEFAULT]) - buf.WriteByte(' ') - ct.Options.Default.formatFast(buf) + _, isLiteral := ct.Options.Default.(*Literal) + _, isBool := ct.Options.Default.(BoolVal) + _, isNullVal := ct.Options.Default.(*NullVal) + if isLiteral || isNullVal || isBool || isExprAliasForCurrentTimeStamp(ct.Options.Default) { + buf.WriteByte(' ') + ct.Options.Default.formatFast(buf) + } else { + buf.WriteString(" (") + ct.Options.Default.formatFast(buf) + buf.WriteByte(')') + } } if ct.Options.OnUpdate != nil { buf.WriteByte(' ') diff --git a/go/vt/sqlparser/ast_funcs.go b/go/vt/sqlparser/ast_funcs.go index 5029e6d5691..f75878a2667 100644 --- a/go/vt/sqlparser/ast_funcs.go +++ b/go/vt/sqlparser/ast_funcs.go @@ -17,8 +17,10 @@ limitations under the License. package sqlparser import ( + "bytes" "encoding/hex" "encoding/json" + "regexp" "strings" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" @@ -469,6 +471,32 @@ func (node *Literal) HexDecode() ([]byte, error) { return hex.DecodeString(node.Val) } +// encodeHexValToMySQLQueryFormat encodes the hexval back into the query format +// for passing on to MySQL as a bind var +func (node *Literal) encodeHexValToMySQLQueryFormat() ([]byte, error) { + nb := node.Bytes() + if node.Type != HexVal { + return nb, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Literal value is not a HexVal") + } + + // Let's make this idempotent in case it's called more than once + match, err := regexp.Match("^x'.*'$", nb) + if err != nil { + return nb, err + } + if match { + return nb, nil + } + + var bb bytes.Buffer + bb.WriteByte('x') + bb.WriteByte('\'') + bb.WriteString(string(nb)) + bb.WriteByte('\'') + nb = bb.Bytes() + return nb, nil +} + // Equal returns true if the column names match. func (node *ColName) Equal(c *ColName) bool { // Failsafe: ColName should not be empty. @@ -1307,6 +1335,17 @@ func (node *ColName) CompliantName() string { return node.Name.CompliantName() } +// isExprAliasForCurrentTimeStamp returns true if the Expr provided is an alias for CURRENT_TIMESTAMP +func isExprAliasForCurrentTimeStamp(expr Expr) bool { + switch node := expr.(type) { + case *FuncExpr: + return node.Name.EqualString("current_timestamp") || node.Name.EqualString("now") || node.Name.EqualString("localtimestamp") || node.Name.EqualString("localtime") + case *CurTimeFuncExpr: + return node.Name.EqualString("current_timestamp") || node.Name.EqualString("now") || node.Name.EqualString("localtimestamp") || node.Name.EqualString("localtime") + } + return false +} + // AtCount represents the '@' count in ColIdent type AtCount int diff --git a/go/vt/sqlparser/ast_rewrite.go b/go/vt/sqlparser/ast_rewrite.go index c54f1feff36..a0d395aec22 100644 --- a/go/vt/sqlparser/ast_rewrite.go +++ b/go/vt/sqlparser/ast_rewrite.go @@ -254,6 +254,8 @@ func (a *application) rewriteSQLNode(parent SQLNode, node SQLNode, replacer repl return a.rewriteRefOfShowFilter(parent, node, replacer) case *ShowLegacy: return a.rewriteRefOfShowLegacy(parent, node, replacer) + case *ShowMigrationLogs: + return a.rewriteRefOfShowMigrationLogs(parent, node, replacer) case *StarExpr: return a.rewriteRefOfStarExpr(parent, node, replacer) case *Stream: @@ -3725,6 +3727,33 @@ func (a *application) rewriteRefOfShowLegacy(parent SQLNode, node *ShowLegacy, r } return true } +func (a *application) rewriteRefOfShowMigrationLogs(parent SQLNode, node *ShowMigrationLogs, replacer replacerFunc) bool { + if node == nil { + return true + } + if a.pre != nil { + a.cur.replacer = replacer + a.cur.parent = parent + a.cur.node = node + if !a.pre(&a.cur) { + return true + } + } + if !a.rewriteComments(node, node.Comments, func(newNode, parent SQLNode) { + parent.(*ShowMigrationLogs).Comments = newNode.(Comments) + }) { + return false + } + if a.post != nil { + a.cur.replacer = replacer + a.cur.parent = parent + a.cur.node = node + if !a.post(&a.cur) { + return false + } + } + return true +} func (a *application) rewriteRefOfStarExpr(parent SQLNode, node *StarExpr, replacer replacerFunc) bool { if node == nil { return true @@ -5086,6 +5115,8 @@ func (a *application) rewriteStatement(parent SQLNode, node Statement, replacer return a.rewriteRefOfSetTransaction(parent, node, replacer) case *Show: return a.rewriteRefOfShow(parent, node, replacer) + case *ShowMigrationLogs: + return a.rewriteRefOfShowMigrationLogs(parent, node, replacer) case *Stream: return a.rewriteRefOfStream(parent, node, replacer) case *TruncateTable: diff --git a/go/vt/sqlparser/ast_rewriting.go b/go/vt/sqlparser/ast_rewriting.go index 978e14a5d64..978aa83715c 100644 --- a/go/vt/sqlparser/ast_rewriting.go +++ b/go/vt/sqlparser/ast_rewriting.go @@ -18,6 +18,7 @@ package sqlparser import ( "strconv" + "vitess.io/vitess/go/vt/vtgate/boost" querypb "vitess.io/vitess/go/vt/proto/query" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" @@ -31,7 +32,8 @@ import ( // RewriteASTResult contains the rewritten ast and meta information about it type RewriteASTResult struct { *BindVarNeeds - AST Statement // The rewritten AST + AST Statement // The rewritten AST + Columns boost.Columns } // ReservedVars keeps track of the bind variable names that have already been used @@ -145,17 +147,21 @@ func NewReservedVars(prefix string, known BindVars) *ReservedVars { // PrepareAST will normalize the query func PrepareAST(in Statement, reservedVars *ReservedVars, bindVars map[string]*querypb.BindVariable, parameterize bool, keyspace string) (*RewriteASTResult, error) { + var boostColumns boost.Columns + var err error + if parameterize { - err := Normalize(in, reservedVars, bindVars) + boostColumns, err = Normalize(in, reservedVars, bindVars) if err != nil { return nil, err } } - return RewriteAST(in, keyspace) + + return RewriteAST(in, keyspace, boostColumns) } // RewriteAST rewrites the whole AST, replacing function calls and adding column aliases to queries -func RewriteAST(in Statement, keyspace string) (*RewriteASTResult, error) { +func RewriteAST(in Statement, keyspace string, columns map[string]string) (*RewriteASTResult, error) { er := newExpressionRewriter(keyspace) er.shouldRewriteDatabaseFunc = shouldRewriteDatabaseFunc(in) setRewriter := &setNormalizer{} @@ -172,6 +178,7 @@ func RewriteAST(in Statement, keyspace string) (*RewriteASTResult, error) { r := &RewriteASTResult{ AST: out, BindVarNeeds: er.bindVars, + Columns: columns, } return r, nil } diff --git a/go/vt/sqlparser/ast_visit.go b/go/vt/sqlparser/ast_visit.go index 9acffb6323c..6f6ca59b94a 100644 --- a/go/vt/sqlparser/ast_visit.go +++ b/go/vt/sqlparser/ast_visit.go @@ -254,6 +254,8 @@ func VisitSQLNode(in SQLNode, f Visit) error { return VisitRefOfShowFilter(in, f) case *ShowLegacy: return VisitRefOfShowLegacy(in, f) + case *ShowMigrationLogs: + return VisitRefOfShowMigrationLogs(in, f) case *StarExpr: return VisitRefOfStarExpr(in, f) case *Stream: @@ -1869,6 +1871,18 @@ func VisitRefOfShowLegacy(in *ShowLegacy, f Visit) error { } return nil } +func VisitRefOfShowMigrationLogs(in *ShowMigrationLogs, f Visit) error { + if in == nil { + return nil + } + if cont, err := f(in); err != nil || !cont { + return err + } + if err := VisitComments(in.Comments, f); err != nil { + return err + } + return nil +} func VisitRefOfStarExpr(in *StarExpr, f Visit) error { if in == nil { return nil @@ -2686,6 +2700,8 @@ func VisitStatement(in Statement, f Visit) error { return VisitRefOfSetTransaction(in, f) case *Show: return VisitRefOfShow(in, f) + case *ShowMigrationLogs: + return VisitRefOfShowMigrationLogs(in, f) case *Stream: return VisitRefOfStream(in, f) case *TruncateTable: diff --git a/go/vt/sqlparser/cached_size.go b/go/vt/sqlparser/cached_size.go index 1aa0a172e9e..0720b7564ec 100644 --- a/go/vt/sqlparser/cached_size.go +++ b/go/vt/sqlparser/cached_size.go @@ -1901,6 +1901,25 @@ func (cached *ShowLegacy) CachedSize(alloc bool) int64 { } return size } +func (cached *ShowMigrationLogs) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(40) + } + // field UUID string + size += int64(len(cached.UUID)) + // field Comments vitess.io/vitess/go/vt/sqlparser.Comments + { + size += int64(cap(cached.Comments)) * int64(16) + for _, elem := range cached.Comments { + size += int64(len(elem)) + } + } + return size +} func (cached *ShowTablesOpt) CachedSize(alloc bool) int64 { if cached == nil { return int64(0) diff --git a/go/vt/sqlparser/normalizer.go b/go/vt/sqlparser/normalizer.go index 177d9a5ba27..bfc8af05a6a 100644 --- a/go/vt/sqlparser/normalizer.go +++ b/go/vt/sqlparser/normalizer.go @@ -18,8 +18,8 @@ package sqlparser import ( "vitess.io/vitess/go/sqltypes" - querypb "vitess.io/vitess/go/vt/proto/query" + "vitess.io/vitess/go/vt/vtgate/boost" ) // BindVars is a set of reserved bind variables from a SQL statement @@ -32,17 +32,20 @@ type BindVars map[string]struct{} // Within Select constructs, bind vars are deduped. This allows // us to identify vindex equality. Otherwise, every value is // treated as distinct. -func Normalize(stmt Statement, reserved *ReservedVars, bindVars map[string]*querypb.BindVariable) error { + +func Normalize(stmt Statement, reserved *ReservedVars, bindVars map[string]*querypb.BindVariable) (boost.Columns, error) { nz := newNormalizer(reserved, bindVars) _ = Rewrite(stmt, nz.WalkStatement, nil) - return nz.err + return nz.columns, nz.err } type normalizer struct { - bindVars map[string]*querypb.BindVariable - reserved *ReservedVars - vals map[string]string - err error + bindVars map[string]*querypb.BindVariable + reserved *ReservedVars + vals map[string]string + columns boost.Columns + currentColumn string + err error } func newNormalizer(reserved *ReservedVars, bindVars map[string]*querypb.BindVariable) *normalizer { @@ -50,6 +53,7 @@ func newNormalizer(reserved *ReservedVars, bindVars map[string]*querypb.BindVari bindVars: bindVars, reserved: reserved, vals: make(map[string]string), + columns: make(map[string]string), } } @@ -86,7 +90,10 @@ func (nz *normalizer) WalkSelect(cursor *Cursor) bool { nz.convertLiteralDedup(node, cursor) case *ComparisonExpr: nz.convertComparison(node) - case *ColName, TableName: + case *ColName: + nz.currentColumn = node.Name.String() + return false + case *TableName: // Common node types that never contain Literals or ListArgs but create a lot of object // allocations. return false @@ -134,6 +141,11 @@ func (nz *normalizer) convertLiteralDedup(node *Literal, cursor *Cursor) { nz.bindVars[bvname] = bval } + // Store the column to bind var mapping. + if nz.currentColumn != "" && !ok { + nz.columns[nz.currentColumn] = bvname + } + // Modify the AST node to a bindvar. cursor.Replace(NewArgument(bvname)) } @@ -148,6 +160,11 @@ func (nz *normalizer) convertLiteral(node *Literal, cursor *Cursor) { bvname := nz.reserved.nextUnusedVar() nz.bindVars[bvname] = bval + // Store the column to bind var mapping. + if nz.currentColumn != "" { + nz.columns[nz.currentColumn] = bvname + } + cursor.Replace(NewArgument(bvname)) } @@ -196,6 +213,17 @@ func (nz *normalizer) sqlToBindvar(node SQLNode) *querypb.BindVariable { v, err = sqltypes.NewValue(sqltypes.Int64, node.Bytes()) case FloatVal: v, err = sqltypes.NewValue(sqltypes.Float64, node.Bytes()) + case HexNum: + v, err = sqltypes.NewValue(sqltypes.HexNum, node.Bytes()) + case HexVal: + // We parse the `x'7b7d'` string literal into a hex encoded string of `7b7d` in the parser + // We need to re-encode it back to the original MySQL query format before passing it on as a bindvar value to MySQL + var vbytes []byte + vbytes, err = node.encodeHexValToMySQLQueryFormat() + if err != nil { + return nil + } + v, err = sqltypes.NewValue(sqltypes.HexVal, vbytes) default: return nil } diff --git a/go/vt/sqlparser/normalizer_test.go b/go/vt/sqlparser/normalizer_test.go index 5a389f34b17..eb6d932c2d5 100644 --- a/go/vt/sqlparser/normalizer_test.go +++ b/go/vt/sqlparser/normalizer_test.go @@ -131,15 +131,33 @@ func TestNormalize(t *testing.T) { "bv2": sqltypes.TestBindVariable([]interface{}{1, 4, 5}), }, }, { - // Hex value does not convert + // Hex number values should work for selects in: "select * from t where v1 = 0x1234", - outstmt: "select * from t where v1 = 0x1234", - outbv: map[string]*querypb.BindVariable{}, + outstmt: "select * from t where v1 = :bv1", + outbv: map[string]*querypb.BindVariable{ + "bv1": sqltypes.HexNumBindVariable([]byte("0x1234")), + }, }, { - // Hex value does not convert for DMLs - in: "update a set v1 = 0x1234", - outstmt: "update a set v1 = 0x1234", - outbv: map[string]*querypb.BindVariable{}, + // Hex encoded string values should work for selects + in: "select * from t where v1 = x'7b7d'", + outstmt: "select * from t where v1 = :bv1", + outbv: map[string]*querypb.BindVariable{ + "bv1": sqltypes.HexValBindVariable([]byte("x'7b7d'")), + }, + }, { + // Ensure that hex notation bind vars work with collation based conversions + in: "select convert(x'7b7d' using utf8mb4) from dual", + outstmt: "select convert(:bv1 using utf8mb4) from dual", + outbv: map[string]*querypb.BindVariable{ + "bv1": sqltypes.HexValBindVariable([]byte("x'7b7d'")), + }, + }, { + // Hex number values should work for DMLs + in: "update a set v1 = 0x12", + outstmt: "update a set v1 = :bv1", + outbv: map[string]*querypb.BindVariable{ + "bv1": sqltypes.HexNumBindVariable([]byte("0x12")), + }, }, { // Bin value does not convert in: "select * from t where v1 = b'11'", diff --git a/go/vt/sqlparser/parse_test.go b/go/vt/sqlparser/parse_test.go index 3e6d3f353eb..2e94de5ed7f 100644 --- a/go/vt/sqlparser/parse_test.go +++ b/go/vt/sqlparser/parse_test.go @@ -1169,6 +1169,18 @@ var ( input: "create table `a`", output: "create table a", partialDDL: true, + }, { + input: "create table function_default (x varchar(25) default (trim(' check ')))", + output: "create table function_default (\n\tx varchar(25) default (trim(' check '))\n)", + }, { + input: "create table function_default (x varchar(25) default (((trim(' check ')))))", + output: "create table function_default (\n\tx varchar(25) default (trim(' check '))\n)", + }, { + input: "create table function_default3 (x bool DEFAULT (true AND false));", + output: "create table function_default3 (\n\tx bool default (true and false)\n)", + }, { + input: "create table function_default (x bool DEFAULT true);", + output: "create table function_default (\n\tx bool default true\n)", }, { input: "create table a (\n\t`a` int\n)", output: "create table a (\n\ta int\n)", @@ -1623,6 +1635,8 @@ var ( input: `show vitess_migrations from ks like '%pattern'`, }, { input: "show vitess_migrations like '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90'", + }, { + input: "show vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' logs", }, { input: "revert vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90'", }, { @@ -2907,11 +2921,11 @@ func TestCreateTable(t *testing.T) { time5 timestamp(4) default utc_timestamp(4) on update utc_timestamp(4) )`, output: `create table t ( - time1 timestamp default utc_timestamp(), - time2 timestamp default utc_timestamp(), - time3 timestamp default utc_timestamp() on update utc_timestamp(), - time4 timestamp default utc_timestamp() on update utc_timestamp(), - time5 timestamp(4) default utc_timestamp(4) on update utc_timestamp(4) + time1 timestamp default (utc_timestamp()), + time2 timestamp default (utc_timestamp()), + time3 timestamp default (utc_timestamp()) on update utc_timestamp(), + time4 timestamp default (utc_timestamp()) on update utc_timestamp(), + time5 timestamp(4) default (utc_timestamp(4)) on update utc_timestamp(4) )`, }, { // test utc_time with and without () @@ -2923,11 +2937,11 @@ func TestCreateTable(t *testing.T) { time5 timestamp(5) default utc_time(5) on update utc_time(5) )`, output: `create table t ( - time1 timestamp default utc_time(), - time2 timestamp default utc_time(), - time3 timestamp default utc_time() on update utc_time(), - time4 timestamp default utc_time() on update utc_time(), - time5 timestamp(5) default utc_time(5) on update utc_time(5) + time1 timestamp default (utc_time()), + time2 timestamp default (utc_time()), + time3 timestamp default (utc_time()) on update utc_time(), + time4 timestamp default (utc_time()) on update utc_time(), + time5 timestamp(5) default (utc_time(5)) on update utc_time(5) )`, }, { // test utc_date with and without () @@ -2938,10 +2952,10 @@ func TestCreateTable(t *testing.T) { time4 timestamp default utc_date() on update utc_date() )`, output: `create table t ( - time1 timestamp default utc_date(), - time2 timestamp default utc_date(), - time3 timestamp default utc_date() on update utc_date(), - time4 timestamp default utc_date() on update utc_date() + time1 timestamp default (utc_date()), + time2 timestamp default (utc_date()), + time3 timestamp default (utc_date()) on update utc_date(), + time4 timestamp default (utc_date()) on update utc_date() )`, }, { // test localtime with and without () @@ -2984,10 +2998,10 @@ func TestCreateTable(t *testing.T) { time4 timestamp default current_date() on update current_date() )`, output: `create table t ( - time1 timestamp default current_date(), - time2 timestamp default current_date(), - time3 timestamp default current_date() on update current_date(), - time4 timestamp default current_date() on update current_date() + time1 timestamp default (current_date()), + time2 timestamp default (current_date()), + time3 timestamp default (current_date()) on update current_date(), + time4 timestamp default (current_date()) on update current_date() )`, }, { // test current_time with and without () @@ -2999,11 +3013,11 @@ func TestCreateTable(t *testing.T) { time5 timestamp(2) default current_time(2) on update current_time(2) )`, output: `create table t ( - time1 timestamp default current_time(), - time2 timestamp default current_time(), - time3 timestamp default current_time() on update current_time(), - time4 timestamp default current_time() on update current_time(), - time5 timestamp(2) default current_time(2) on update current_time(2) + time1 timestamp default (current_time()), + time2 timestamp default (current_time()), + time3 timestamp default (current_time()) on update current_time(), + time4 timestamp default (current_time()) on update current_time(), + time5 timestamp(2) default (current_time(2)) on update current_time(2) )`, }, { input: `create table t1 ( diff --git a/go/vt/sqlparser/redact_query.go b/go/vt/sqlparser/redact_query.go index 194ad1ca64d..6362f1cd32e 100644 --- a/go/vt/sqlparser/redact_query.go +++ b/go/vt/sqlparser/redact_query.go @@ -28,7 +28,7 @@ func RedactSQLQuery(sql string) (string, error) { return "", err } - err = Normalize(stmt, NewReservedVars("redacted", reservedVars), bv) + _, err = Normalize(stmt, NewReservedVars("redacted", reservedVars), bv) if err != nil { return "", err } diff --git a/go/vt/sqlparser/sql.go b/go/vt/sqlparser/sql.go index 5ca258daa7f..26d5a7dbd63 100644 --- a/go/vt/sqlparser/sql.go +++ b/go/vt/sqlparser/sql.go @@ -1011,20 +1011,20 @@ var yyExca = [...]int{ 265, 118, -2, 341, -1, 53, - 33, 489, - 172, 489, - 183, 489, - 216, 503, - 217, 503, - -2, 491, + 33, 490, + 172, 490, + 183, 490, + 216, 504, + 217, 504, + -2, 492, -1, 58, - 174, 513, - -2, 511, + 174, 514, + -2, 512, -1, 84, - 57, 581, - -2, 589, + 57, 582, + -2, 590, -1, 97, - 171, 955, + 171, 956, -2, 91, -1, 99, 1, 113, @@ -1039,569 +1039,593 @@ var yyExca = [...]int{ 150, 118, 265, 118, -2, 350, - -1, 569, - 157, 976, - -2, 972, -1, 570, 157, 977, -2, 973, - -1, 589, - 57, 582, - -2, 594, + -1, 571, + 157, 978, + -2, 974, -1, 590, 57, 583, -2, 595, - -1, 611, - 125, 1327, - -2, 84, + -1, 591, + 57, 584, + -2, 596, -1, 612, - 125, 1208, + 125, 1328, + -2, 84, + -1, 613, + 125, 1209, -2, 85, - -1, 618, - 125, 1259, - -2, 949, - -1, 758, - 125, 1142, - -2, 946, - -1, 794, + -1, 619, + 125, 1260, + -2, 950, + -1, 759, + 125, 1143, + -2, 947, + -1, 795, 182, 38, 187, 38, -2, 255, - -1, 871, + -1, 872, 1, 388, 481, 388, -2, 118, - -1, 1112, + -1, 1114, 1, 285, 481, 285, -2, 118, - -1, 1115, + -1, 1117, 23, 137, -2, 139, - -1, 1188, + -1, 1190, 112, 244, 177, 244, -2, 335, - -1, 1197, + -1, 1199, 182, 39, 187, 39, -2, 256, - -1, 1406, - 157, 981, - -2, 975, - -1, 1497, + -1, 1409, + 157, 982, + -2, 976, + -1, 1500, 75, 66, 83, 66, -2, 70, - -1, 1518, + -1, 1521, 1, 286, 481, 286, -2, 118, - -1, 1951, - 5, 842, - 18, 842, - 20, 842, - 31, 842, - 84, 842, - -2, 621, - -1, 2185, - 47, 917, - -2, 911, + -1, 1954, + 5, 843, + 18, 843, + 20, 843, + 31, 843, + 84, 843, + -2, 622, + -1, 2188, + 47, 918, + -2, 912, } const yyPrivate = 57344 -const yyLast = 29660 +const yyLast = 30143 var yyAct = [...]int{ - 569, 2281, 2105, 2010, 2238, 2215, 2225, 2251, 931, 1775, - 2162, 83, 3, 1737, 2186, 2132, 1782, 1931, 1586, 1704, - 2102, 1783, 1013, 1443, 1932, 527, 1060, 1827, 1738, 1928, - 512, 1551, 1807, 1067, 1871, 541, 1831, 1556, 510, 1571, - 137, 824, 1724, 2124, 1392, 1808, 1890, 1169, 1809, 165, - 1400, 1943, 165, 1664, 475, 165, 1584, 1094, 882, 1304, - 491, 1494, 165, 582, 1195, 761, 1515, 81, 123, 1558, - 165, 1617, 616, 1570, 1801, 1104, 1097, 1070, 789, 1476, - 591, 1065, 1087, 1445, 1052, 1426, 576, 1483, 503, 911, - 542, 34, 491, 1090, 1369, 491, 165, 491, 514, 802, - 613, 1202, 1568, 1287, 769, 790, 1301, 949, 768, 765, - 1547, 1459, 795, 1403, 791, 1103, 1499, 1537, 1077, 792, - 1309, 1101, 140, 79, 106, 34, 1088, 867, 1026, 100, - 1164, 101, 8, 7, 33, 929, 6, 78, 107, 1615, - 1187, 498, 1851, 1850, 1029, 1878, 167, 168, 169, 1536, - 1879, 1273, 2134, 1358, 950, 167, 168, 169, 1440, 1441, - 1213, 1357, 1356, 1355, 598, 602, 1354, 826, 102, 829, - 578, 450, 478, 762, 1353, 501, 777, 502, 1346, 2270, - 840, 841, 1702, 844, 845, 846, 847, 108, 950, 850, - 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, - 861, 862, 863, 864, 2182, 499, 1979, 2081, 2158, 617, - 806, 2157, 467, 610, 577, 772, 828, 827, 2297, 960, - 784, 466, 102, 2100, 84, 1654, 2101, 2248, 2296, 783, - 805, 782, 464, 80, 2208, 2289, 837, 554, 2106, 560, - 561, 558, 559, 1603, 557, 556, 555, 1563, 2247, 830, - 831, 832, 1907, 960, 562, 563, 2207, 2043, 842, 1178, - 1703, 86, 87, 88, 89, 90, 91, 1858, 1561, 97, - 461, 1857, 162, 1957, 781, 445, 876, 877, 1768, 473, - 1442, 1767, 1510, 1511, 1769, 1105, 102, 1106, 1500, 1958, - 1959, 870, 1877, 1652, 1509, 575, 35, 161, 889, 72, - 39, 40, 918, 890, 920, 901, 906, 907, 573, 956, - 572, 888, 948, 887, 889, 902, 1791, 895, 478, 890, - 2012, 103, 927, 1530, 1529, 2212, 479, 776, 2034, 778, - 779, 2032, 489, 1345, 145, 493, 487, 1293, 1056, 866, - 917, 919, 1832, 956, 1347, 1348, 1349, 167, 168, 169, - 478, 1585, 2006, 1560, 451, 1429, 453, 468, 1854, 481, - 2007, 480, 457, 1618, 455, 459, 469, 460, 2295, 454, - 1288, 465, 71, 478, 456, 470, 471, 485, 484, 472, - 1623, 463, 482, 781, 865, 781, 478, 773, 142, 843, - 143, 903, 908, 896, 775, 774, 2013, 904, 905, 160, - 924, 872, 909, 910, 1866, 2271, 2171, 975, 974, 984, - 985, 977, 978, 979, 980, 981, 982, 983, 976, 926, - 2154, 986, 1628, 1626, 1627, 785, 2095, 1630, 915, 1631, - 1633, 1632, 916, 1624, 849, 848, 780, 1263, 2014, 585, - 1620, 779, 921, 1622, 813, 165, 869, 165, 811, 1891, - 165, 955, 952, 953, 954, 959, 961, 958, 804, 957, - 1587, 1477, 822, 914, 146, 821, 951, 1787, 922, 820, - 819, 818, 479, 151, 817, 816, 491, 491, 491, 1264, - 1978, 1265, 1294, 1621, 815, 955, 952, 953, 954, 959, - 961, 958, 1893, 957, 491, 491, 810, 786, 1181, 823, - 951, 766, 2292, 766, 479, 764, 483, 942, 798, 1500, - 885, 804, 891, 892, 893, 894, 2285, 803, 923, 1856, - 2287, 766, 807, 797, 476, 899, 1562, 479, 797, 1302, - 839, 868, 808, 928, 1569, 604, 1867, 2206, 1609, 477, - 479, 1298, 814, 936, 2213, 780, 812, 780, 833, 1201, - 809, 1986, 1853, 1916, 1895, 1915, 1899, 1914, 1894, 1653, - 1892, 925, 804, 1176, 1175, 1897, 930, 930, 930, 1174, - 803, 1870, 1843, 165, 1896, 1299, 797, 800, 801, 138, - 766, 1172, 2239, 449, 794, 798, 34, 1898, 1900, 444, - 1058, 1275, 1274, 1276, 1277, 1278, 1705, 1707, 99, 995, - 997, 491, 1683, 793, 165, 886, 165, 165, 996, 491, - 1057, 1873, 933, 934, 1200, 491, 1872, 613, 998, 999, - 804, 803, 878, 1865, 1680, 2172, 1864, 2193, 945, 943, - 1010, 73, 944, 804, 1015, 1016, 1017, 1018, 1019, 1020, - 1021, 1022, 2063, 1025, 1027, 1030, 1030, 1030, 1027, 1030, - 1030, 1027, 1030, 1043, 1044, 1045, 1046, 1047, 1048, 1049, - 1605, 875, 1956, 1729, 898, 1055, 1053, 1086, 804, 34, - 1672, 2283, 1071, 1873, 2284, 900, 2282, 1014, 1872, 803, - 1595, 838, 1505, 1028, 1031, 1033, 1035, 1036, 1038, 1040, - 1041, 1292, 803, 1081, 1011, 880, 1092, 807, 797, 1706, - 1032, 1034, 1069, 1037, 1039, 976, 1042, 808, 986, 1516, - 986, 1764, 912, 1050, 975, 974, 984, 985, 977, 978, - 979, 980, 981, 982, 983, 976, 617, 803, 986, 1455, - 963, 1341, 94, 797, 800, 801, 1310, 766, 966, 1909, - 884, 794, 798, 167, 168, 169, 966, 1394, 998, 999, - 139, 144, 141, 147, 148, 149, 150, 152, 153, 154, - 155, 165, 871, 965, 963, 1165, 156, 157, 158, 159, - 998, 999, 2202, 1665, 1173, 1376, 825, 1289, 1941, 1290, - 966, 1427, 1291, 95, 1619, 1778, 1295, 1107, 586, 1374, - 1375, 1373, 1604, 491, 946, 1197, 1820, 979, 980, 981, - 982, 983, 976, 1206, 1059, 986, 1427, 1210, 1690, 1395, - 491, 491, 2137, 491, 1966, 491, 491, 1602, 491, 491, - 491, 491, 491, 491, 1965, 1591, 1179, 1180, 1212, 1211, - 1779, 1199, 1597, 491, 2264, 913, 1207, 165, 1246, 1600, - 975, 974, 984, 985, 977, 978, 979, 980, 981, 982, - 983, 976, 1781, 165, 986, 1776, 1601, 1186, 1193, 1311, - 883, 1241, 1242, 1074, 491, 813, 165, 1205, 1785, 1786, - 1678, 811, 2080, 1777, 2290, 1961, 2293, 1300, 1677, 2276, - 2079, 165, 1597, 1984, 1249, 1250, 1805, 964, 965, 963, - 1255, 1256, 167, 168, 169, 1911, 1796, 165, 1243, 1171, - 1203, 1203, 2291, 1204, 165, 966, 1599, 2277, 1282, 964, - 965, 963, 1184, 165, 165, 165, 165, 165, 165, 165, - 165, 165, 491, 491, 491, 1196, 1182, 966, 1183, 1657, - 1658, 1659, 507, 1784, 1460, 1461, 1259, 977, 978, 979, - 980, 981, 982, 983, 976, 1787, 2294, 986, 1102, 165, - 71, 1244, 1804, 1306, 1314, 1566, 603, 1457, 1797, 1283, - 600, 1318, 1372, 1320, 1321, 1322, 1323, 1268, 1267, 1281, - 1327, 1215, 1679, 1216, 1918, 1218, 1220, 1312, 1313, 1224, - 1226, 1228, 1230, 1232, 1342, 1303, 1266, 1393, 167, 168, - 169, 1317, 1771, 2280, 102, 1257, 1396, 1251, 1324, 1325, - 1326, 783, 1177, 782, 1248, 1370, 1352, 167, 168, 169, - 491, 1579, 930, 930, 930, 167, 168, 169, 1316, 1577, - 1404, 1456, 1919, 964, 965, 963, 504, 984, 985, 977, - 978, 979, 980, 981, 982, 983, 976, 1397, 1398, 986, - 608, 966, 1247, 1780, 491, 491, 605, 606, 1410, 1280, - 1415, 1418, 964, 965, 963, 165, 1428, 1337, 1338, 1339, - 1222, 1270, 2279, 964, 965, 963, 2278, 2265, 1371, 491, - 966, 1405, 2259, 2257, 2121, 1806, 165, 2077, 1448, 491, - 2009, 966, 2051, 165, 1406, 165, 167, 168, 169, 1964, - 1404, 1920, 1814, 165, 165, 1802, 1648, 1434, 1435, 80, - 491, 1613, 1612, 491, 1495, 964, 965, 963, 613, 586, - 1279, 613, 1449, 1307, 491, 1271, 1258, 1254, 1253, 1252, - 2152, 1450, 1269, 966, 964, 965, 963, 1993, 2245, 1411, - 1412, 1462, 1014, 1417, 1420, 1421, 1407, 1364, 1366, 1367, - 2151, 1474, 966, 2104, 2231, 1993, 2200, 2229, 1993, 2195, - 1834, 1498, 1470, 1519, 1406, 1365, 2233, 2234, 1817, 1433, - 1785, 1786, 1436, 1437, 1524, 2230, 1993, 2194, 1531, 491, - 1532, 1533, 1534, 1535, 1725, 1572, 1573, 1574, 586, 1520, - 1576, 1578, 1940, 1496, 2176, 586, 1543, 1544, 1545, 1546, - 2098, 586, 1523, 491, 35, 1553, 1758, 1472, 1725, 491, - 1206, 1993, 2096, 1206, 1500, 1206, 2058, 1559, 1597, 586, - 2061, 586, 1503, 1596, 1976, 1975, 1507, 617, 1929, 1522, - 617, 1506, 1972, 1973, 2201, 1784, 1811, 1940, 1521, 82, - 2040, 530, 529, 532, 533, 534, 535, 1787, 1972, 1971, - 531, 1598, 536, 491, 1480, 1393, 1468, 586, 1500, 1852, - 1393, 1393, 1168, 1836, 1829, 1830, 1480, 586, 1583, 1501, - 1501, 962, 586, 35, 1590, 35, 570, 1593, 1940, 1594, - 71, 1549, 1550, 1564, 1554, 1567, 1479, 1538, 1539, 1540, - 1575, 1565, 1168, 1167, 1113, 1112, 165, 1732, 1469, 1608, - 962, 806, 1993, 165, 1610, 1611, 1468, 1597, 165, 165, - 1607, 1203, 165, 1592, 165, 1974, 1554, 1589, 1606, 1588, - 165, 805, 1733, 1480, 2139, 166, 1508, 165, 166, 1695, - 1694, 166, 1502, 1502, 1468, 579, 492, 2082, 166, 1480, - 1504, 1500, 1237, 71, 2148, 1597, 166, 1580, 1458, 71, - 2164, 71, 2103, 1616, 165, 491, 975, 974, 984, 985, - 977, 978, 979, 980, 981, 982, 983, 976, 492, 1468, - 986, 492, 166, 492, 1438, 1350, 1297, 1099, 1408, 1409, - 788, 1643, 1644, 787, 2074, 2069, 1646, 2083, 2084, 2085, - 870, 1170, 1238, 1239, 1240, 1647, 975, 974, 984, 985, - 977, 978, 979, 980, 981, 982, 983, 976, 1552, 2008, - 986, 71, 1968, 1837, 1548, 1542, 1636, 1541, 970, 1370, - 973, 1285, 1198, 1194, 1451, 1166, 987, 988, 989, 990, - 991, 992, 993, 96, 971, 972, 969, 975, 974, 984, - 985, 977, 978, 979, 980, 981, 982, 983, 976, 165, - 1810, 986, 2011, 2086, 1944, 1945, 2165, 165, 1000, 1001, - 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1651, 1563, - 2261, 2226, 1991, 1990, 1989, 1947, 1234, 967, 1660, 1929, - 165, 1821, 1371, 1637, 1674, 1343, 1751, 1711, 1489, 1490, - 1950, 165, 165, 165, 165, 165, 1949, 1811, 1734, 1718, - 2087, 2088, 1746, 165, 1673, 1671, 1745, 165, 578, 2273, - 165, 165, 1749, 504, 165, 165, 165, 1750, 1756, 2246, - 1739, 1689, 1024, 1235, 1236, 1669, 1670, 1770, 1730, 1747, - 1921, 1714, 1068, 1701, 1748, 2187, 2189, 2062, 1996, 1723, - 1709, 1727, 1053, 1722, 2190, 1708, 1687, 2275, 1795, 2217, - 1717, 2250, 577, 2252, 1063, 1066, 1726, 2216, 1712, 2220, - 2184, 1728, 1296, 571, 1789, 1527, 1713, 1815, 835, 1773, - 1092, 1759, 834, 1740, 491, 1761, 1743, 1735, 1736, 165, - 2021, 1092, 1092, 1092, 1092, 1092, 165, 1757, 1306, 1752, - 1061, 1762, 491, 1810, 1765, 1876, 935, 1496, 491, 2056, - 1092, 1062, 1206, 1206, 1092, 1845, 1844, 1559, 491, 1774, - 1423, 103, 1813, 1794, 1840, 1798, 1799, 1800, 1741, 1742, - 1849, 1744, 1460, 1461, 1424, 1453, 1833, 1803, 596, 592, - 1987, 165, 165, 165, 165, 165, 1640, 1812, 1485, 1488, - 1489, 1490, 1486, 593, 1487, 1491, 2197, 165, 165, 1818, - 2159, 1788, 1493, 1629, 1847, 1656, 1822, 1823, 1824, 1186, - 2258, 596, 592, 580, 581, 1405, 1838, 1839, 1072, 1073, - 595, 1721, 594, 1846, 583, 2256, 593, 2255, 1406, 1720, - 2221, 2219, 2055, 491, 1992, 1848, 1581, 584, 82, 1393, - 2054, 1887, 1792, 1793, 1924, 1725, 2263, 2262, 579, 1842, - 1684, 589, 590, 595, 1868, 594, 1681, 1082, 1075, 2263, - 2191, 1889, 1963, 1454, 80, 85, 77, 1888, 1, 491, - 2228, 166, 462, 166, 1439, 1880, 166, 1051, 474, 2224, - 165, 1908, 1886, 1901, 1272, 1262, 1902, 2107, 2161, 1999, - 491, 1557, 1874, 796, 128, 1875, 491, 491, 1887, 1517, - 1518, 2241, 492, 492, 492, 93, 1930, 1485, 1488, 1489, - 1490, 1486, 1667, 1487, 1491, 759, 1668, 1944, 1945, 165, - 492, 492, 92, 1739, 799, 897, 1582, 1675, 1676, 1933, - 2099, 1790, 1528, 1682, 1119, 1117, 1685, 1686, 1118, 1116, - 1939, 1121, 1120, 1115, 1692, 1344, 1693, 488, 165, 1696, - 1697, 1698, 1699, 1700, 1927, 1948, 1492, 163, 1108, 1076, - 1952, 836, 1954, 1710, 1955, 452, 1977, 1340, 1614, 458, - 994, 1719, 1766, 1960, 614, 607, 1985, 1935, 2214, 2183, - 1953, 2185, 165, 2133, 1934, 2188, 34, 2181, 2274, 2249, - 491, 2196, 1525, 1452, 1064, 2053, 1923, 1688, 491, 166, - 1023, 1425, 1091, 513, 165, 1308, 1447, 1363, 528, 1092, - 1754, 1755, 1982, 1983, 165, 1981, 525, 1980, 526, 1969, - 1970, 2000, 1463, 1995, 1731, 1998, 968, 492, 165, 1917, - 166, 165, 166, 166, 1997, 492, 1559, 511, 505, 1083, - 2022, 492, 1484, 2003, 2002, 1482, 1481, 1638, 1095, 1946, - 1942, 1089, 1467, 1526, 1855, 1994, 2005, 1938, 947, 588, - 500, 1368, 2017, 2016, 1377, 1378, 1379, 1380, 1381, 1382, - 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 771, - 1422, 2170, 1655, 1359, 1360, 1361, 1362, 2030, 2042, 587, - 61, 38, 495, 2019, 2020, 2269, 938, 597, 32, 2027, - 2028, 31, 2029, 30, 29, 2031, 28, 2033, 23, 22, - 21, 20, 2025, 19, 25, 18, 17, 16, 98, 48, - 2057, 45, 43, 1430, 105, 104, 46, 42, 873, 2066, - 27, 1739, 26, 2065, 15, 14, 13, 2046, 1413, 1414, - 12, 11, 10, 9, 5, 4, 2071, 165, 941, 2073, - 165, 165, 165, 491, 491, 24, 2072, 1012, 2041, 2, - 0, 0, 0, 0, 0, 2047, 2048, 2049, 0, 0, - 0, 0, 2108, 491, 491, 491, 504, 0, 0, 0, - 2093, 0, 0, 0, 0, 1884, 1885, 166, 0, 2114, - 975, 974, 984, 985, 977, 978, 979, 980, 981, 982, - 983, 976, 0, 0, 986, 0, 0, 0, 491, 491, - 491, 165, 2112, 0, 0, 0, 0, 0, 0, 492, - 0, 0, 491, 0, 491, 0, 0, 0, 1514, 2052, - 491, 0, 2140, 0, 2130, 491, 492, 492, 2136, 492, - 2142, 492, 492, 2138, 492, 492, 492, 492, 492, 492, - 0, 1936, 2128, 2129, 1933, 0, 0, 2145, 1933, 492, - 0, 0, 2147, 166, 491, 0, 2120, 491, 0, 0, - 2153, 0, 1951, 0, 0, 2163, 0, 2156, 2155, 166, - 0, 2076, 0, 2078, 0, 0, 0, 1555, 0, 2144, - 492, 2160, 166, 0, 0, 2146, 0, 0, 0, 0, - 0, 0, 0, 2149, 0, 2150, 0, 166, 0, 1934, - 2180, 34, 0, 1934, 0, 0, 0, 2192, 0, 0, - 0, 0, 0, 166, 0, 491, 165, 0, 0, 0, - 166, 2199, 0, 0, 0, 1933, 0, 491, 2113, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 492, 492, - 492, 0, 2203, 0, 491, 0, 0, 2211, 0, 0, - 2218, 2131, 491, 491, 0, 2222, 2227, 0, 0, 2235, - 2163, 2242, 2240, 2232, 0, 166, 0, 0, 0, 0, - 2254, 2253, 1739, 0, 0, 0, 0, 0, 0, 0, - 1934, 2260, 0, 0, 0, 0, 0, 0, 0, 0, - 2266, 0, 2024, 0, 0, 2198, 2026, 0, 0, 2272, - 34, 0, 0, 0, 0, 0, 0, 2035, 2036, 0, - 0, 0, 0, 0, 0, 2286, 0, 0, 0, 0, - 0, 0, 0, 2050, 540, 2288, 492, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, - 2059, 2060, 0, 0, 2064, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1661, 1662, 1663, - 492, 492, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 166, 0, 164, 0, 0, 448, 2039, 0, 486, - 0, 0, 0, 0, 0, 492, 448, 2045, 0, 161, - 0, 0, 166, 0, 448, 492, 0, 0, 0, 166, - 0, 166, 0, 0, 0, 2097, 0, 0, 0, 166, - 166, 601, 601, 103, 0, 125, 492, 0, 0, 492, - 448, 0, 0, 0, 0, 0, 145, 0, 0, 0, - 492, 0, 0, 0, 0, 0, 0, 0, 1691, 0, - 975, 974, 984, 985, 977, 978, 979, 980, 981, 982, - 983, 976, 0, 2125, 986, 0, 0, 135, 0, 0, - 0, 0, 124, 0, 0, 0, 0, 1715, 1716, 1066, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 142, 0, 143, 0, 0, 492, 0, 112, 113, 134, - 133, 160, 0, 975, 974, 984, 985, 977, 978, 979, - 980, 981, 982, 983, 976, 0, 0, 986, 0, 492, - 0, 0, 0, 0, 0, 492, 0, 0, 0, 0, - 0, 2166, 2167, 2168, 2169, 0, 2173, 0, 2174, 2175, - 2177, 0, 0, 0, 2178, 2179, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 129, 110, 136, 117, 109, - 0, 130, 131, 0, 0, 0, 146, 0, 0, 492, - 0, 0, 0, 0, 0, 151, 118, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2205, 0, 0, 0, - 121, 119, 114, 115, 116, 120, 0, 0, 0, 0, - 111, 0, 0, 0, 0, 0, 0, 0, 0, 122, - 0, 161, 166, 0, 0, 0, 0, 0, 0, 166, - 0, 0, 0, 0, 166, 166, 0, 0, 166, 0, - 166, 539, 0, 0, 0, 103, 166, 0, 0, 0, - 0, 0, 0, 166, 0, 0, 0, 0, 145, 0, - 0, 0, 2267, 2268, 0, 0, 0, 0, 1882, 1883, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 166, 492, 0, 1903, 1904, 0, 1905, 1906, 0, 0, - 0, 138, 0, 0, 0, 0, 0, 1912, 1913, 1772, - 0, 490, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 142, 0, 143, 0, 0, 0, 0, 0, - 0, 1910, 0, 160, 0, 0, 0, 2038, 0, 0, - 0, 0, 0, 615, 0, 0, 763, 0, 770, 0, - 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1925, 0, 126, 0, - 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1136, 0, 0, 166, 0, 0, 0, 0, - 0, 1962, 0, 166, 0, 0, 0, 0, 146, 448, - 0, 448, 0, 0, 448, 0, 0, 151, 0, 0, - 0, 0, 0, 0, 0, 0, 166, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 166, 166, 166, - 166, 166, 0, 0, 0, 0, 0, 0, 0, 166, - 0, 0, 0, 166, 0, 0, 166, 166, 0, 0, - 166, 166, 166, 975, 974, 984, 985, 977, 978, 979, - 980, 981, 982, 983, 976, 0, 0, 986, 0, 0, - 0, 0, 139, 144, 141, 147, 148, 149, 150, 152, - 153, 154, 155, 0, 0, 0, 0, 0, 156, 157, - 158, 159, 0, 0, 2023, 0, 0, 0, 0, 0, - 0, 0, 0, 1124, 0, 0, 0, 0, 0, 0, - 492, 0, 0, 138, 0, 166, 0, 0, 0, 0, - 0, 0, 166, 0, 0, 0, 0, 448, 492, 0, - 0, 0, 0, 0, 492, 0, 0, 0, 0, 0, - 0, 0, 0, 601, 492, 0, 1137, 0, 0, 0, - 0, 0, 2044, 0, 0, 0, 0, 0, 448, 0, - 448, 1098, 0, 0, 0, 0, 0, 166, 166, 166, - 166, 166, 0, 0, 0, 504, 0, 0, 0, 0, - 0, 2075, 2067, 166, 166, 2068, 0, 0, 2070, 0, - 0, 0, 0, 0, 0, 0, 0, 1150, 1153, 1154, - 1155, 1156, 1157, 1158, 0, 1159, 1160, 1161, 1162, 1163, - 1138, 1139, 1140, 1141, 1122, 1123, 1151, 0, 1125, 492, - 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, 1135, - 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2115, 2116, 2117, 2118, 2119, 492, 0, 0, 2122, 2123, - 0, 0, 0, 0, 0, 0, 166, 0, 0, 1054, - 0, 0, 0, 0, 0, 0, 492, 0, 0, 0, - 0, 0, 492, 492, 139, 144, 141, 147, 148, 149, - 150, 152, 153, 154, 155, 2135, 504, 0, 0, 0, - 156, 157, 158, 159, 1152, 166, 2037, 0, 0, 0, + 570, 2108, 2284, 2013, 2241, 2228, 2218, 2189, 2254, 1778, + 933, 83, 3, 2165, 2135, 1740, 1589, 1785, 2105, 1707, + 1934, 1786, 528, 1446, 1015, 1069, 1062, 1830, 1741, 1931, + 1554, 1935, 1810, 511, 1518, 542, 1874, 883, 1834, 1574, + 1559, 513, 1727, 1811, 1539, 1893, 825, 1812, 137, 165, + 583, 2127, 165, 762, 476, 165, 1497, 1946, 1096, 81, + 492, 1667, 165, 1587, 1620, 912, 617, 1197, 123, 1403, + 165, 1561, 1306, 1804, 1395, 790, 1106, 1573, 1099, 592, + 1090, 1479, 1067, 1448, 1092, 1054, 1072, 1215, 601, 1486, + 504, 33, 492, 1429, 577, 492, 165, 492, 515, 1372, + 951, 1303, 614, 1089, 769, 793, 1571, 1462, 766, 1406, + 1204, 796, 791, 1289, 770, 792, 1105, 1311, 1103, 1502, + 79, 1540, 1079, 140, 1028, 8, 1550, 100, 803, 101, + 1166, 1031, 7, 868, 6, 931, 1854, 1853, 106, 1171, + 1189, 78, 1618, 107, 1275, 499, 1881, 1882, 167, 168, + 169, 1443, 1444, 2137, 505, 1361, 1360, 1359, 1358, 1357, + 1356, 1345, 502, 1349, 503, 778, 2273, 1705, 2185, 102, + 763, 578, 827, 599, 603, 450, 2084, 830, 773, 1982, + 84, 2161, 2160, 829, 828, 841, 842, 108, 845, 846, + 847, 848, 2300, 2251, 851, 852, 853, 854, 855, 856, + 857, 858, 859, 860, 861, 862, 863, 864, 865, 500, + 611, 2103, 2292, 618, 2104, 2299, 806, 86, 87, 88, + 89, 90, 91, 102, 785, 97, 80, 784, 162, 783, + 952, 445, 2211, 1566, 1657, 831, 832, 833, 2109, 807, + 555, 2250, 561, 562, 559, 560, 952, 558, 557, 556, + 1606, 576, 161, 1910, 1564, 2210, 1180, 563, 564, 2046, + 1961, 1962, 843, 1829, 35, 838, 1861, 72, 39, 40, + 1860, 1513, 1514, 1445, 1706, 1107, 103, 1108, 125, 161, + 782, 1960, 877, 878, 1880, 871, 1655, 102, 1771, 145, + 1512, 1770, 929, 902, 1772, 962, 919, 1503, 921, 890, + 907, 908, 574, 103, 891, 573, 777, 903, 779, 1794, + 890, 962, 889, 479, 888, 891, 145, 896, 1533, 1532, + 135, 2215, 2015, 2037, 2035, 124, 479, 490, 867, 1350, + 1351, 1352, 1348, 488, 918, 920, 780, 1295, 494, 1563, + 71, 1058, 1588, 142, 1835, 143, 1857, 1894, 479, 1626, + 1191, 1192, 134, 133, 160, 1432, 1621, 1775, 167, 168, + 169, 1631, 1629, 1630, 782, 844, 774, 2009, 911, 2298, + 142, 1290, 143, 776, 775, 2010, 925, 782, 866, 1265, + 873, 160, 1869, 904, 479, 958, 909, 786, 950, 928, + 1896, 1625, 2274, 897, 2017, 1633, 910, 1634, 2016, 1635, + 1623, 958, 1627, 905, 906, 1636, 850, 2157, 129, 1193, + 136, 849, 1190, 2098, 130, 131, 814, 1781, 812, 146, + 780, 1266, 916, 1267, 1590, 1183, 917, 1480, 151, 823, + 822, 1624, 821, 820, 819, 818, 922, 817, 816, 586, + 870, 811, 781, 787, 824, 165, 146, 165, 1503, 1790, + 165, 2295, 1898, 1981, 1902, 151, 1897, 915, 1895, 2290, + 767, 767, 1782, 1900, 1873, 799, 798, 480, 923, 767, + 2288, 1304, 1899, 765, 1572, 605, 900, 492, 492, 492, + 480, 1870, 1296, 1989, 1784, 1901, 1903, 1779, 1203, 886, + 1612, 892, 893, 894, 895, 492, 492, 1300, 805, 938, + 1788, 1789, 480, 834, 1856, 1780, 1919, 1918, 944, 1708, + 1710, 924, 1565, 930, 815, 1917, 813, 1178, 1859, 805, + 1177, 1176, 1846, 1301, 1174, 869, 781, 957, 954, 955, + 956, 961, 963, 960, 138, 959, 2209, 926, 480, 781, + 2216, 449, 953, 957, 954, 955, 956, 961, 963, 960, + 1876, 959, 99, 1202, 444, 1875, 1868, 804, 953, 1867, + 2196, 138, 808, 798, 1608, 1787, 1876, 2066, 1656, 1000, + 1001, 1875, 809, 1686, 165, 2242, 840, 1790, 804, 1294, + 1959, 1732, 1683, 1675, 1277, 1276, 1278, 1279, 1280, 132, + 810, 1060, 1598, 1508, 1519, 1083, 969, 805, 1013, 73, + 988, 126, 492, 1059, 127, 165, 887, 165, 165, 998, + 492, 879, 1709, 935, 936, 899, 492, 881, 978, 1767, + 614, 988, 947, 913, 876, 2286, 901, 1458, 2287, 945, + 2285, 946, 505, 1312, 1343, 1016, 167, 168, 169, 885, + 1397, 1026, 2174, 977, 976, 986, 987, 979, 980, 981, + 982, 983, 984, 985, 978, 968, 804, 988, 1055, 967, + 965, 808, 798, 1088, 2205, 1291, 805, 1292, 826, 1912, + 1293, 809, 1073, 1065, 1068, 1783, 968, 966, 967, 965, + 1030, 1033, 1035, 1037, 1038, 1040, 1042, 1043, 1034, 1036, + 1944, 1039, 1041, 1622, 1044, 968, 1607, 1297, 805, 1071, + 1109, 94, 1398, 948, 1430, 139, 144, 141, 147, 148, + 149, 150, 152, 153, 154, 155, 872, 1823, 1052, 1000, + 1001, 156, 157, 158, 159, 804, 2140, 839, 1000, 1001, + 1969, 618, 139, 144, 141, 147, 148, 149, 150, 152, + 153, 154, 155, 167, 168, 169, 914, 1799, 156, 157, + 158, 159, 95, 1430, 1379, 1693, 1313, 804, 1968, 884, + 1594, 1061, 165, 798, 801, 802, 1167, 767, 1377, 1378, + 1376, 795, 799, 1463, 1464, 1175, 805, 977, 976, 986, + 987, 979, 980, 981, 982, 983, 984, 985, 978, 1214, + 794, 988, 1213, 1201, 492, 1605, 1199, 981, 982, 983, + 984, 985, 978, 1600, 1208, 988, 1600, 1603, 1212, 1800, + 965, 492, 492, 814, 492, 812, 492, 492, 2293, 492, + 492, 492, 492, 492, 492, 2279, 968, 1604, 2267, 1681, + 1602, 1964, 1181, 1182, 492, 804, 1668, 1680, 165, 1248, + 71, 798, 801, 802, 1076, 767, 2294, 1195, 1209, 795, + 799, 1284, 1375, 2280, 165, 1660, 1661, 1662, 1188, 2083, + 1104, 2175, 966, 967, 965, 492, 2296, 165, 966, 967, + 965, 1207, 2234, 1243, 1244, 2232, 604, 2082, 1302, 1987, + 968, 1808, 165, 1807, 2236, 2237, 968, 1245, 1788, 1789, + 1251, 1252, 1682, 2233, 1569, 1285, 1257, 1258, 165, 1217, + 1282, 1218, 1272, 1220, 1222, 165, 1173, 1226, 1228, 1230, + 1232, 1234, 1283, 1206, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 492, 492, 492, 1198, 1186, 1270, 1185, + 1205, 1205, 1184, 1269, 1316, 1268, 2297, 1261, 167, 168, + 169, 1320, 1774, 1322, 1323, 1324, 1325, 1259, 1308, 1921, + 1329, 165, 609, 1787, 1314, 1315, 1246, 1253, 1250, 1179, + 1809, 1281, 1249, 1271, 1344, 1790, 606, 607, 1319, 1224, + 966, 967, 965, 2283, 1310, 1326, 1327, 1328, 1914, 1460, + 2282, 1305, 2281, 966, 967, 965, 2268, 2262, 968, 1396, + 966, 967, 965, 1367, 1369, 1370, 102, 1922, 1399, 2260, + 784, 968, 783, 2124, 167, 168, 169, 1373, 968, 1355, + 2080, 1368, 492, 167, 168, 169, 1318, 1582, 167, 168, + 169, 2054, 1580, 1967, 1407, 1923, 979, 980, 981, 982, + 983, 984, 985, 978, 1400, 1401, 988, 1817, 1805, 1651, + 1616, 1615, 1413, 1459, 1452, 1309, 492, 492, 1273, 587, + 1260, 1256, 1255, 1362, 1363, 1364, 1365, 165, 1339, 1340, + 1341, 1254, 927, 1418, 1421, 2012, 1996, 2248, 80, 1431, + 1374, 492, 1996, 2203, 966, 967, 965, 2155, 165, 2154, + 1409, 492, 1451, 1996, 2198, 165, 1408, 165, 1996, 2197, + 2107, 1016, 968, 1837, 1407, 165, 165, 2179, 587, 2101, + 587, 82, 492, 1996, 2099, 492, 1498, 1820, 1416, 1417, + 1453, 1728, 614, 1600, 587, 614, 492, 1527, 1437, 1438, + 1465, 2064, 587, 1979, 1978, 1975, 1976, 1414, 1415, 1975, + 1974, 1420, 1423, 1424, 1728, 1410, 986, 987, 979, 980, + 981, 982, 983, 984, 985, 978, 505, 587, 988, 1943, + 1409, 1471, 587, 1473, 1501, 1601, 1477, 1436, 1503, 1855, + 1439, 1440, 2085, 1522, 1170, 1839, 1832, 1833, 1471, 1523, + 2061, 492, 1483, 587, 1541, 1542, 1543, 1575, 1576, 1577, + 587, 1483, 1579, 1581, 964, 587, 1761, 1504, 1504, 1170, + 1169, 1526, 1115, 1114, 1503, 492, 1556, 1932, 1517, 2204, + 35, 492, 1208, 1475, 1943, 1208, 1943, 1208, 1482, 1562, + 964, 1600, 2086, 2087, 2088, 1599, 71, 1506, 35, 1510, + 1509, 35, 1472, 618, 1735, 1996, 618, 1977, 1525, 1483, + 1511, 1524, 977, 976, 986, 987, 979, 980, 981, 982, + 983, 984, 985, 978, 1698, 492, 988, 1396, 1586, 1736, + 1505, 1505, 1396, 1396, 1697, 580, 1471, 1558, 1507, 1503, + 1600, 1483, 1534, 1583, 1535, 1536, 1537, 1538, 571, 1593, + 2142, 1461, 1596, 1441, 1597, 1557, 71, 1814, 1353, 1568, + 1546, 1547, 1548, 1549, 1239, 1567, 1578, 1570, 165, 1552, + 1553, 1299, 1101, 1471, 71, 165, 789, 71, 1609, 806, + 165, 165, 788, 2167, 165, 1592, 165, 1557, 2106, 1610, + 1591, 2077, 165, 2072, 1595, 1172, 1555, 166, 2011, 165, + 166, 1611, 807, 166, 1971, 1840, 1613, 1614, 493, 1551, + 166, 71, 1205, 1545, 1240, 1241, 1242, 871, 166, 1544, + 531, 530, 533, 534, 535, 536, 1619, 165, 492, 532, + 1287, 537, 1646, 1647, 1200, 1196, 1168, 1649, 96, 2264, + 493, 2014, 1813, 493, 166, 493, 1650, 972, 2151, 975, + 1411, 1412, 1947, 1948, 2168, 989, 990, 991, 992, 993, + 994, 995, 1566, 973, 974, 971, 977, 976, 986, 987, + 979, 980, 981, 982, 983, 984, 985, 978, 2089, 2229, + 988, 1236, 1994, 1639, 1488, 1491, 1492, 1493, 1489, 1814, + 1490, 1494, 1373, 1993, 1947, 1948, 1454, 1992, 1950, 1932, + 977, 976, 986, 987, 979, 980, 981, 982, 983, 984, + 985, 978, 1824, 1640, 988, 1346, 2276, 1488, 1491, 1492, + 1493, 1489, 165, 1490, 1494, 2090, 2091, 1752, 1237, 1238, + 165, 1750, 1753, 1953, 1654, 1952, 1751, 597, 593, 1754, + 1749, 1492, 1493, 1748, 1677, 2249, 1924, 1717, 1070, 2190, + 2192, 2065, 594, 165, 1999, 1374, 1663, 1726, 2193, 2278, + 1714, 1725, 2220, 2253, 165, 165, 165, 165, 165, 2255, + 2219, 1737, 1721, 2223, 2187, 1298, 165, 1074, 1075, 596, + 165, 595, 578, 165, 165, 1676, 572, 165, 165, 165, + 1715, 1759, 1792, 1530, 1672, 1673, 1818, 1426, 1716, 1694, + 1773, 1733, 1692, 836, 1742, 835, 1055, 1704, 1063, 1730, + 2024, 1427, 1813, 1712, 1879, 1690, 937, 1456, 1848, 1064, + 1847, 1798, 103, 2059, 1720, 1463, 1464, 1990, 1718, 1719, + 1068, 1643, 2200, 1731, 2162, 1791, 1496, 1632, 1729, 1762, + 581, 582, 1659, 1764, 584, 1744, 1745, 492, 1747, 2261, + 1776, 2259, 165, 2258, 1797, 1308, 1801, 1802, 1803, 165, + 1795, 1796, 1760, 2224, 1755, 492, 1765, 1743, 1768, 1724, + 1746, 492, 2222, 2058, 82, 1208, 1208, 1723, 1995, 1777, + 1562, 492, 1584, 597, 593, 585, 2057, 1927, 1728, 1843, + 1816, 2266, 2265, 1852, 1687, 1684, 1084, 1077, 594, 1806, + 2266, 2194, 1966, 1457, 165, 165, 165, 165, 165, 580, + 1836, 80, 1815, 85, 77, 1821, 1, 2231, 462, 1442, + 165, 165, 1053, 590, 591, 596, 1851, 595, 475, 1850, + 2227, 1274, 1188, 1825, 1826, 1827, 1264, 2110, 2164, 2002, + 1560, 797, 1841, 1842, 128, 1409, 1520, 1521, 2244, 93, + 760, 1408, 92, 1849, 800, 898, 492, 1585, 2102, 1793, + 1531, 1121, 1396, 1119, 1120, 1118, 1890, 976, 986, 987, + 979, 980, 981, 982, 983, 984, 985, 978, 1871, 1123, + 988, 1122, 1891, 1117, 1892, 1347, 489, 1495, 163, 1110, + 1078, 1877, 492, 166, 1878, 166, 1911, 837, 166, 452, + 1980, 1342, 1617, 165, 458, 996, 1883, 1722, 1905, 1769, + 615, 608, 1938, 492, 2217, 2186, 2188, 2136, 2191, 492, + 492, 2184, 2277, 1890, 1889, 493, 493, 493, 2252, 2199, + 1528, 1933, 1455, 1066, 2056, 1670, 1904, 1926, 1691, 1671, + 1025, 1428, 165, 493, 493, 1093, 514, 1450, 1366, 529, + 1678, 1679, 1936, 526, 527, 1466, 1685, 1742, 1734, 1688, + 1689, 970, 1913, 1942, 1930, 512, 506, 1695, 1085, 1696, + 1487, 165, 1699, 1700, 1701, 1702, 1703, 1485, 1484, 1920, + 1641, 1097, 1949, 1955, 1951, 1957, 1713, 1958, 1945, 1091, + 1470, 1529, 1858, 2008, 949, 589, 501, 1928, 1956, 1988, + 772, 1425, 2173, 1658, 1963, 165, 2045, 1941, 2043, 588, + 1972, 1973, 61, 492, 38, 496, 2049, 2272, 940, 598, + 32, 492, 166, 31, 30, 29, 28, 165, 23, 22, + 21, 20, 19, 1757, 1758, 25, 1984, 165, 18, 1983, + 1985, 1986, 2003, 17, 2048, 16, 98, 48, 2001, 45, + 493, 165, 43, 166, 165, 166, 166, 1998, 493, 1562, + 2000, 105, 2005, 2025, 493, 104, 1997, 46, 2006, 977, + 976, 986, 987, 979, 980, 981, 982, 983, 984, 985, + 978, 42, 874, 988, 27, 2020, 26, 15, 2019, 14, + 13, 12, 11, 10, 9, 2022, 2023, 977, 976, 986, + 987, 979, 980, 981, 982, 983, 984, 985, 978, 2033, + 5, 988, 4, 943, 24, 1014, 2, 0, 0, 0, + 0, 0, 2028, 0, 977, 976, 986, 987, 979, 980, + 981, 982, 983, 984, 985, 978, 0, 0, 988, 0, + 0, 0, 0, 2060, 0, 0, 0, 2055, 2068, 0, + 0, 0, 2069, 0, 0, 0, 0, 0, 0, 0, + 0, 2074, 0, 0, 0, 1742, 0, 0, 0, 2076, + 165, 0, 0, 165, 165, 165, 492, 492, 0, 2075, + 0, 0, 0, 2047, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2111, 492, 492, 492, 2079, + 0, 2081, 0, 2096, 0, 0, 505, 0, 1887, 1888, + 166, 0, 2117, 2070, 2030, 2031, 2071, 2032, 0, 2073, + 2034, 0, 2036, 0, 0, 0, 0, 0, 0, 0, + 0, 492, 492, 492, 165, 2115, 0, 0, 0, 0, + 0, 0, 493, 0, 0, 492, 0, 492, 0, 0, + 0, 0, 0, 492, 0, 2143, 2116, 2133, 492, 493, + 493, 0, 493, 2139, 493, 493, 2145, 493, 493, 493, + 493, 493, 493, 2141, 1939, 0, 2123, 1936, 0, 2134, + 2148, 1936, 493, 2131, 2132, 2150, 166, 492, 0, 0, + 492, 2156, 0, 0, 2152, 1954, 2153, 0, 2159, 2147, + 2166, 2158, 166, 0, 0, 2149, 0, 0, 0, 0, + 0, 0, 0, 493, 2163, 166, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2138, 505, 0, 0, + 166, 0, 541, 2183, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2195, 0, 0, 166, 0, 492, 165, + 0, 0, 0, 166, 2202, 0, 0, 0, 1936, 0, + 492, 0, 166, 166, 166, 166, 166, 166, 166, 166, + 166, 493, 493, 493, 0, 2206, 2221, 492, 0, 2214, + 0, 164, 0, 0, 448, 492, 492, 487, 0, 2230, + 2225, 2042, 2238, 0, 448, 2166, 2245, 2235, 2243, 166, + 0, 540, 448, 0, 2257, 2256, 0, 0, 0, 0, + 0, 0, 0, 2263, 0, 0, 1742, 0, 0, 602, + 602, 0, 0, 2269, 0, 2027, 0, 0, 448, 2029, + 0, 0, 2275, 0, 0, 0, 0, 0, 0, 0, + 2038, 2039, 0, 0, 0, 0, 0, 0, 0, 2289, + 0, 0, 0, 0, 0, 0, 2053, 2291, 0, 0, + 493, 491, 0, 0, 0, 0, 167, 168, 169, 0, + 0, 0, 0, 2062, 2063, 508, 0, 2067, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 479, 616, 493, 493, 764, 0, 771, 0, + 0, 0, 0, 0, 2041, 166, 0, 977, 976, 986, + 987, 979, 980, 981, 982, 983, 984, 985, 978, 493, + 0, 988, 0, 0, 0, 0, 166, 0, 0, 493, + 0, 0, 467, 166, 0, 166, 0, 0, 2100, 0, + 0, 466, 0, 166, 166, 0, 0, 0, 0, 0, + 493, 0, 464, 493, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 493, 0, 0, 0, 0, 0, + 0, 0, 35, 36, 37, 72, 39, 40, 0, 0, + 0, 0, 0, 0, 0, 0, 2128, 0, 0, 0, + 461, 0, 76, 0, 2040, 0, 41, 67, 68, 474, + 65, 69, 0, 0, 0, 0, 0, 0, 0, 66, + 0, 0, 0, 0, 472, 0, 0, 0, 0, 493, + 977, 976, 986, 987, 979, 980, 981, 982, 983, 984, + 985, 978, 0, 0, 988, 0, 0, 0, 54, 0, + 0, 0, 0, 493, 0, 0, 480, 0, 71, 493, + 0, 0, 0, 0, 2169, 2170, 2171, 2172, 0, 2176, + 0, 2177, 2178, 2180, 0, 0, 0, 2181, 2182, 0, + 0, 0, 0, 0, 451, 0, 453, 468, 0, 482, + 0, 481, 457, 0, 455, 459, 469, 460, 0, 454, + 0, 465, 0, 493, 456, 470, 471, 486, 485, 473, + 0, 463, 483, 0, 0, 0, 0, 0, 0, 2208, + 977, 976, 986, 987, 979, 980, 981, 982, 983, 984, + 985, 978, 0, 0, 988, 0, 44, 47, 50, 49, + 52, 0, 64, 0, 0, 70, 166, 0, 0, 0, + 0, 0, 0, 166, 0, 0, 0, 0, 166, 166, + 0, 0, 166, 0, 166, 0, 0, 53, 75, 74, + 166, 0, 62, 63, 51, 0, 0, 166, 0, 0, + 0, 0, 0, 0, 0, 2270, 2271, 448, 0, 448, + 0, 0, 448, 0, 0, 0, 0, 0, 0, 0, + 1884, 0, 0, 0, 0, 166, 493, 0, 0, 0, + 0, 0, 0, 55, 56, 0, 57, 58, 59, 60, + 977, 976, 986, 987, 979, 980, 981, 982, 983, 984, + 985, 978, 0, 0, 988, 0, 484, 1669, 977, 976, + 986, 987, 979, 980, 981, 982, 983, 984, 985, 978, + 0, 0, 988, 0, 477, 0, 0, 977, 976, 986, + 987, 979, 980, 981, 982, 983, 984, 985, 978, 478, + 0, 988, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 616, 616, + 616, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 166, 0, 0, 0, 0, 0, 939, 941, 166, 0, + 0, 0, 0, 0, 0, 0, 448, 73, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 166, 602, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 166, 166, 166, 166, 166, 448, 0, 448, + 1100, 0, 0, 0, 166, 0, 0, 0, 166, 0, + 0, 166, 166, 0, 0, 166, 166, 166, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, + 1010, 1011, 0, 1081, 0, 0, 0, 0, 0, 0, + 0, 616, 0, 0, 0, 493, 0, 1111, 0, 0, + 166, 0, 0, 0, 0, 0, 0, 166, 0, 0, + 0, 0, 0, 493, 0, 0, 0, 0, 0, 493, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 493, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 166, 166, 166, 166, 166, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 166, 166, + 0, 0, 0, 0, 448, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 493, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1211, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 493, 0, 0, 0, 1211, 1211, 0, 0, 0, 0, + 448, 166, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 493, 0, 0, 0, 0, 1262, 493, 493, 0, + 0, 0, 0, 0, 0, 764, 0, 0, 0, 448, + 0, 0, 0, 0, 0, 0, 0, 0, 1210, 0, + 166, 0, 1216, 1216, 1307, 1216, 0, 1216, 1216, 0, + 1225, 1216, 1216, 1216, 1216, 1216, 0, 0, 0, 0, + 448, 0, 0, 1210, 1210, 764, 0, 448, 161, 166, + 0, 0, 0, 0, 0, 0, 1330, 1331, 448, 448, + 448, 448, 448, 448, 448, 0, 0, 0, 0, 0, + 0, 0, 103, 0, 0, 0, 1286, 0, 0, 0, + 0, 0, 0, 166, 0, 145, 0, 0, 0, 0, + 0, 493, 0, 448, 0, 0, 0, 0, 0, 493, + 0, 0, 0, 0, 0, 166, 0, 0, 0, 0, + 1056, 0, 0, 0, 0, 166, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, + 0, 0, 166, 0, 616, 616, 616, 0, 0, 142, + 0, 143, 0, 0, 0, 0, 0, 0, 0, 0, + 160, 0, 0, 0, 0, 602, 1307, 0, 0, 0, + 602, 602, 447, 0, 602, 602, 602, 0, 0, 0, + 1211, 0, 495, 0, 0, 0, 0, 0, 0, 0, + 575, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 602, 602, 602, 602, 602, 0, 0, 0, 0, 1262, + 0, 0, 0, 0, 0, 0, 768, 0, 0, 0, + 0, 0, 0, 0, 0, 146, 0, 0, 0, 0, + 448, 0, 0, 1402, 151, 616, 1307, 448, 0, 448, + 0, 0, 0, 0, 0, 0, 0, 448, 448, 1210, + 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, + 0, 166, 166, 166, 493, 493, 1371, 1434, 1435, 1380, + 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, + 1391, 1392, 1393, 1394, 493, 493, 493, 0, 0, 543, + 34, 0, 1467, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1081, 0, 0, 616, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 493, + 493, 493, 166, 616, 34, 0, 616, 0, 1433, 0, + 0, 0, 0, 493, 0, 493, 0, 764, 0, 0, + 138, 493, 0, 0, 0, 0, 493, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 579, + 0, 0, 0, 0, 0, 493, 0, 0, 493, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 771, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 764, 0, 0, 0, + 0, 0, 771, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 493, 166, 0, 0, + 448, 0, 0, 0, 0, 0, 0, 448, 493, 0, + 0, 0, 448, 448, 0, 0, 448, 0, 1644, 0, + 0, 0, 0, 0, 448, 493, 764, 1138, 0, 0, + 0, 448, 0, 493, 493, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 448, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 139, 144, 141, 147, 148, 149, 150, 152, 153, + 154, 155, 0, 0, 0, 0, 0, 156, 157, 158, + 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 602, 602, 0, + 0, 0, 0, 0, 0, 875, 0, 880, 0, 1653, + 882, 0, 0, 0, 0, 0, 0, 0, 602, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1126, 0, + 0, 0, 0, 0, 448, 0, 0, 0, 0, 0, + 0, 0, 1262, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 602, 448, 0, 0, 0, 0, + 0, 1139, 0, 0, 0, 1211, 448, 448, 448, 448, + 448, 0, 0, 0, 0, 0, 0, 0, 1756, 0, + 0, 0, 448, 0, 0, 448, 448, 0, 0, 448, + 1766, 1307, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1664, 1665, 1666, 0, 0, 0, 0, + 0, 0, 1152, 1155, 1156, 1157, 1158, 1159, 1160, 0, + 1161, 1162, 1163, 1164, 1165, 1140, 1141, 1142, 1143, 1124, + 1125, 1153, 0, 1127, 1210, 1128, 1129, 1130, 1131, 1132, + 1133, 1134, 1135, 1136, 1137, 1144, 1145, 1146, 1147, 1148, + 1149, 1150, 1151, 0, 448, 1087, 0, 0, 1098, 0, + 0, 1828, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1211, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1307, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 932, 932, 932, 0, + 0, 0, 0, 0, 0, 0, 448, 448, 448, 448, + 448, 0, 0, 0, 0, 0, 34, 0, 1819, 1154, + 0, 0, 448, 448, 0, 0, 0, 0, 0, 997, + 999, 0, 0, 0, 0, 0, 1831, 0, 0, 0, + 1210, 0, 1838, 0, 0, 0, 0, 0, 0, 0, + 616, 0, 1844, 0, 0, 0, 0, 602, 0, 0, + 1012, 0, 0, 0, 1017, 1018, 1019, 1020, 1021, 1022, + 1023, 1024, 0, 1027, 1029, 1032, 1032, 1032, 1029, 1032, + 1032, 1029, 1032, 1045, 1046, 1047, 1048, 1049, 1050, 1051, + 0, 0, 0, 0, 0, 1057, 0, 0, 0, 34, 0, 0, 0, 0, 0, 448, 0, 0, 0, 0, - 0, 447, 0, 0, 0, 0, 0, 615, 615, 615, - 0, 494, 0, 0, 166, 0, 0, 0, 0, 574, - 0, 0, 0, 0, 0, 937, 939, 975, 974, 984, - 985, 977, 978, 979, 980, 981, 982, 983, 976, 0, - 1209, 986, 0, 0, 0, 767, 0, 0, 166, 0, - 0, 0, 0, 0, 0, 0, 492, 0, 0, 0, - 0, 0, 0, 0, 492, 1209, 1209, 0, 0, 0, - 166, 448, 0, 0, 0, 0, 0, 0, 0, 0, - 166, 0, 0, 0, 0, 0, 0, 1260, 0, 0, - 0, 2236, 0, 0, 166, 0, 0, 166, 0, 1881, - 448, 0, 975, 974, 984, 985, 977, 978, 979, 980, - 981, 982, 983, 976, 0, 1305, 986, 0, 0, 975, - 974, 984, 985, 977, 978, 979, 980, 981, 982, 983, - 976, 448, 1079, 986, 0, 0, 1666, 0, 448, 0, - 615, 0, 0, 0, 0, 0, 1109, 1328, 1329, 448, - 448, 448, 448, 448, 448, 448, 975, 974, 984, 985, - 977, 978, 979, 980, 981, 982, 983, 976, 0, 0, - 986, 974, 984, 985, 977, 978, 979, 980, 981, 982, - 983, 976, 0, 448, 986, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 166, 0, 0, 166, 166, 166, 492, - 492, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 492, - 492, 492, 0, 0, 0, 601, 1305, 0, 0, 0, - 601, 601, 0, 0, 601, 601, 601, 0, 0, 0, - 1209, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 492, 492, 492, 166, 0, 0, - 601, 601, 601, 601, 601, 0, 0, 0, 492, 1260, - 492, 0, 0, 0, 0, 0, 492, 0, 0, 0, - 0, 492, 0, 0, 0, 0, 0, 0, 0, 0, - 448, 0, 0, 0, 0, 0, 1305, 448, 0, 448, - 0, 0, 0, 0, 763, 0, 0, 448, 448, 0, - 492, 0, 0, 492, 0, 0, 0, 1208, 0, 0, - 0, 1214, 1214, 0, 1214, 0, 1214, 1214, 0, 1223, - 1214, 1214, 1214, 1214, 1214, 0, 0, 0, 0, 0, - 0, 0, 1208, 1208, 763, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 492, 166, 0, 874, 1284, 879, 0, 0, 881, - 0, 0, 0, 492, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 492, 0, 0, 0, 0, 0, 0, 0, 492, 492, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 615, 615, 615, 0, 0, 0, 0, + 0, 0, 1116, 0, 0, 0, 0, 0, 1211, 0, + 0, 0, 0, 0, 0, 0, 1094, 616, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 448, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1216, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 448, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 616, 0, 0, 1210, 1247, 0, + 1940, 1216, 0, 0, 1885, 1886, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 448, 0, 1906, + 1907, 0, 1908, 1909, 0, 0, 0, 1288, 1211, 0, + 0, 0, 0, 1915, 1916, 0, 0, 0, 0, 448, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 448, + 0, 0, 0, 0, 0, 0, 0, 0, 1317, 0, + 0, 0, 0, 448, 0, 1321, 448, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1332, 1333, 1334, 1335, + 1336, 1337, 1338, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 764, 0, 0, 1210, 0, 0, + 0, 0, 1831, 0, 0, 0, 0, 0, 0, 0, + 0, 1098, 0, 0, 0, 0, 0, 1965, 0, 0, 0, 0, 0, 0, 0, 0, 161, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1826, 0, 0, + 0, 0, 0, 0, 0, 0, 1211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, 125, 0, 0, 0, 0, 0, 0, 0, - 448, 0, 0, 145, 0, 0, 161, 448, 0, 0, - 0, 0, 448, 448, 0, 0, 448, 1185, 1641, 0, - 0, 1399, 0, 615, 448, 0, 0, 0, 0, 0, - 103, 448, 125, 1085, 135, 0, 1096, 1208, 0, 124, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1431, 1432, 142, 448, 143, - 0, 0, 0, 0, 1189, 1190, 134, 133, 160, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 448, 0, 0, 448, 448, 448, 0, 0, 0, 0, 0, 0, 135, 0, 0, 0, 0, 124, - 1464, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1079, 0, 0, 615, 0, 0, 0, 142, 0, 143, - 0, 0, 0, 0, 1189, 1190, 134, 133, 160, 0, - 0, 615, 0, 0, 615, 0, 601, 601, 0, 0, - 0, 0, 129, 1191, 136, 763, 1188, 0, 130, 131, - 0, 0, 0, 146, 0, 0, 0, 601, 0, 0, - 0, 0, 151, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 448, 0, 0, 0, 0, 0, 0, - 0, 1260, 129, 1191, 136, 0, 1188, 0, 130, 131, + 0, 0, 0, 0, 0, 1210, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 142, 0, 143, + 2026, 0, 0, 0, 112, 113, 134, 133, 160, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1474, 0, + 0, 0, 0, 0, 0, 1478, 1262, 1481, 0, 0, + 0, 0, 932, 932, 932, 0, 1500, 1831, 2097, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2112, 2113, 2114, + 0, 0, 129, 110, 136, 117, 109, 0, 130, 131, 0, 0, 0, 146, 0, 0, 0, 0, 0, 0, - 770, 0, 151, 601, 448, 0, 0, 0, 0, 0, - 1114, 0, 0, 0, 1209, 448, 448, 448, 448, 448, - 0, 0, 0, 0, 763, 0, 0, 1753, 0, 0, - 770, 448, 0, 0, 448, 448, 0, 0, 448, 1763, - 1305, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 151, 118, 0, 0, 0, 2078, 0, 0, + 0, 0, 2129, 2129, 2129, 0, 0, 121, 119, 114, + 115, 116, 120, 0, 0, 0, 2144, 111, 2146, 0, + 0, 0, 0, 0, 1831, 0, 122, 0, 0, 1831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, - 0, 0, 0, 0, 763, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 448, 0, 0, 0, 0, 138, 0, - 1825, 0, 0, 0, 0, 1286, 0, 0, 0, 0, - 1209, 0, 0, 132, 0, 0, 0, 0, 0, 0, - 1305, 0, 0, 0, 0, 126, 0, 0, 127, 0, - 0, 0, 0, 0, 0, 0, 1315, 0, 0, 0, - 0, 0, 0, 1319, 0, 448, 448, 448, 448, 448, - 0, 0, 0, 132, 1330, 1331, 1332, 1333, 1334, 1335, - 1336, 448, 448, 0, 0, 126, 1650, 0, 127, 0, + 0, 448, 0, 0, 0, 0, 0, 0, 1831, 0, + 0, 616, 0, 0, 0, 0, 2118, 2119, 2120, 2121, + 2122, 0, 0, 0, 2125, 2126, 0, 1211, 0, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1096, 0, - 0, 0, 0, 0, 0, 0, 601, 0, 0, 0, + 1187, 0, 0, 0, 0, 0, 0, 0, 138, 0, + 0, 0, 0, 103, 0, 125, 0, 0, 0, 0, + 0, 0, 0, 0, 1499, 0, 145, 0, 0, 1831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2212, 0, 0, 0, 0, 0, 0, 1098, 0, + 0, 0, 0, 0, 0, 1628, 1210, 135, 2226, 0, + 1637, 1638, 124, 132, 1642, 0, 616, 616, 0, 0, + 0, 0, 1645, 0, 0, 126, 0, 0, 127, 1648, + 142, 0, 143, 0, 0, 0, 0, 1191, 1192, 134, + 133, 160, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2239, 0, 0, + 0, 0, 0, 0, 0, 129, 1193, 136, 0, 1190, + 0, 130, 131, 0, 0, 0, 146, 0, 0, 0, + 0, 0, 0, 0, 0, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 144, 141, 147, 148, 149, 150, 152, 153, 154, 155, - 0, 0, 0, 0, 448, 156, 157, 158, 159, 0, - 0, 0, 0, 0, 0, 0, 0, 1209, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, - 144, 141, 147, 148, 149, 150, 152, 153, 154, 155, - 0, 0, 0, 448, 0, 156, 157, 158, 159, 0, + 0, 0, 0, 0, 0, 156, 157, 158, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1208, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 448, 0, 0, 1471, 0, 0, 0, 0, - 0, 0, 1475, 0, 1478, 0, 0, 0, 0, 0, - 0, 0, 0, 1497, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 448, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1209, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 448, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 448, 0, - 0, 0, 0, 0, 0, 1816, 0, 0, 0, 0, - 0, 0, 448, 0, 0, 448, 0, 0, 0, 0, - 0, 0, 0, 1828, 0, 0, 0, 1208, 0, 1835, - 35, 36, 37, 72, 39, 40, 0, 615, 0, 1841, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 76, 0, 0, 0, 41, 67, 68, 0, 65, 69, - 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1209, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 71, 0, 0, 0, - 0, 0, 0, 0, 615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 448, 0, 0, 448, 448, 448, 0, 0, 0, - 0, 0, 0, 0, 0, 1096, 0, 0, 0, 0, - 1214, 0, 1625, 0, 0, 0, 0, 1634, 1635, 0, - 0, 1639, 0, 0, 0, 0, 0, 0, 0, 1642, - 0, 615, 0, 0, 1208, 0, 1645, 1937, 1214, 0, - 0, 0, 0, 0, 44, 47, 50, 49, 52, 0, - 64, 0, 0, 70, 0, 1260, 0, 0, 0, 0, - 0, 0, 0, 1649, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 53, 75, 74, 0, 0, - 62, 63, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1763, 0, 0, 0, 0, 0, + 0, 138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 55, 56, 0, 57, 58, 59, 60, 0, 0, - 0, 763, 0, 0, 1208, 0, 0, 0, 0, 1828, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 448, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 132, 0, 0, 0, + 0, 0, 1822, 0, 0, 0, 0, 1674, 126, 0, + 579, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1711, 0, 0, + 0, 0, 0, 0, 1862, 1863, 1864, 1865, 1866, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1760, 0, 0, 0, 0, 73, 0, 0, 0, 0, + 1098, 1872, 1094, 0, 0, 0, 0, 0, 0, 1738, + 1739, 0, 0, 1094, 1094, 1094, 1094, 1094, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1499, + 0, 0, 1094, 0, 0, 0, 1094, 0, 0, 0, + 0, 0, 139, 144, 141, 147, 148, 149, 150, 152, + 153, 154, 155, 0, 0, 0, 0, 0, 156, 157, + 158, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1208, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1925, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1819, 0, - 0, 0, 0, 0, 1828, 2094, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2109, 2110, 2111, 0, 0, 0, + 0, 1845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1970, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1859, 1860, 1861, 1862, 1863, 0, 0, 0, 0, 2126, - 2126, 2126, 0, 0, 0, 0, 1096, 1869, 0, 0, - 0, 0, 0, 2141, 0, 2143, 0, 0, 0, 0, - 0, 1828, 0, 0, 0, 0, 1828, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1991, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1828, 0, 0, 615, 0, + 0, 0, 0, 0, 0, 0, 0, 2004, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2007, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2018, 0, 0, 2021, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1937, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1828, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1208, 0, 2223, 0, 0, 0, 0, - 0, 0, 0, 615, 615, 0, 0, 1967, 0, 0, + 0, 1094, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1988, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2001, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2004, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2015, 0, 0, - 2018, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2092, 0, 0, 2093, 2094, 2095, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1610,1071 +1634,479 @@ var yyAct = [...]int{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2044, 0, 0, 0, 0, 0, 0, 2050, 2051, 2052, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2089, 0, 0, 2090, - 2091, 2092, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 741, 727, 393, 0, 676, 744, 647, 664, 754, - 667, 670, 710, 626, 689, 317, 661, 0, 651, 622, - 657, 623, 649, 678, 224, 646, 729, 692, 743, 275, - 221, 628, 652, 331, 666, 176, 712, 369, 209, 284, - 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, - 323, 750, 279, 699, 0, 378, 302, 0, 0, 0, - 680, 733, 687, 723, 675, 711, 636, 698, 745, 662, - 707, 746, 265, 207, 175, 314, 379, 239, 0, 0, - 0, 167, 168, 169, 0, 2243, 2244, 0, 0, 0, - 0, 0, 198, 0, 205, 704, 740, 659, 706, 219, - 263, 226, 218, 395, 751, 732, 0, 191, 742, 682, - 709, 757, 621, 701, 0, 624, 627, 753, 736, 655, - 229, 0, 0, 0, 0, 0, 0, 0, 679, 688, - 720, 673, 0, 0, 0, 0, 0, 0, 0, 0, - 653, 0, 697, 0, 0, 0, 632, 625, 0, 0, - 0, 0, 677, 0, 0, 0, 635, 0, 654, 721, - 0, 619, 247, 629, 303, 2204, 725, 735, 674, 427, - 739, 672, 671, 716, 633, 731, 665, 274, 631, 271, - 171, 187, 0, 663, 313, 352, 358, 730, 650, 658, - 210, 656, 356, 327, 412, 194, 237, 349, 332, 354, - 696, 714, 355, 280, 400, 344, 410, 428, 429, 217, - 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, - 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, - 186, 364, 202, 179, 386, 408, 199, 367, 0, 0, - 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, - 222, 243, 212, 316, 403, 404, 211, 442, 190, 423, - 183, 932, 422, 309, 399, 407, 298, 289, 182, 405, - 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, - 304, 306, 0, 177, 0, 380, 416, 443, 195, 196, - 197, 645, 232, 236, 242, 244, 250, 251, 258, 276, - 320, 341, 339, 345, 726, 394, 411, 419, 426, 432, - 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, - 718, 756, 326, 357, 200, 414, 377, 640, 644, 638, - 639, 690, 691, 641, 747, 748, 749, 722, 634, 0, - 642, 643, 0, 728, 737, 738, 695, 170, 184, 277, - 752, 346, 240, 440, 421, 417, 620, 637, 216, 648, - 0, 0, 660, 668, 669, 681, 683, 684, 685, 686, - 694, 702, 703, 705, 713, 715, 717, 719, 724, 734, - 755, 172, 173, 185, 193, 203, 215, 230, 238, 248, - 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, - 294, 310, 311, 312, 315, 318, 319, 322, 324, 325, - 328, 334, 335, 336, 337, 338, 340, 347, 351, 359, - 360, 361, 362, 363, 365, 366, 370, 371, 372, 373, - 381, 385, 401, 402, 413, 425, 430, 249, 409, 431, - 0, 285, 693, 700, 287, 234, 252, 262, 708, 420, - 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, - 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, - 368, 388, 389, 390, 392, 299, 220, 741, 727, 393, - 0, 676, 744, 647, 664, 754, 667, 670, 710, 626, - 689, 317, 661, 0, 651, 622, 657, 623, 649, 678, - 224, 646, 729, 692, 743, 275, 221, 628, 652, 331, - 666, 176, 712, 369, 209, 284, 282, 398, 235, 227, - 223, 208, 259, 290, 329, 387, 323, 750, 279, 699, - 0, 378, 302, 0, 0, 0, 680, 733, 687, 723, - 675, 711, 636, 698, 745, 662, 707, 746, 265, 207, - 175, 314, 379, 239, 0, 0, 0, 167, 168, 169, - 0, 0, 0, 0, 0, 0, 0, 0, 198, 0, - 205, 704, 740, 659, 706, 219, 263, 226, 218, 395, - 751, 732, 0, 191, 742, 682, 709, 757, 621, 701, - 0, 624, 627, 753, 736, 655, 229, 0, 0, 0, - 0, 0, 0, 0, 679, 688, 720, 673, 0, 0, - 0, 0, 0, 0, 1926, 0, 653, 0, 697, 0, - 0, 0, 632, 625, 0, 0, 0, 0, 677, 0, - 0, 0, 635, 0, 654, 721, 0, 619, 247, 629, - 303, 0, 725, 735, 674, 427, 739, 672, 671, 716, - 633, 731, 665, 274, 631, 271, 171, 187, 0, 663, - 313, 352, 358, 730, 650, 658, 210, 656, 356, 327, - 412, 194, 237, 349, 332, 354, 696, 714, 355, 280, - 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, - 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, - 270, 374, 245, 174, 278, 436, 186, 364, 202, 179, - 386, 408, 199, 367, 0, 0, 441, 181, 406, 383, - 297, 267, 268, 180, 0, 348, 222, 243, 212, 316, - 403, 404, 211, 442, 190, 423, 183, 932, 422, 309, - 399, 407, 298, 289, 182, 405, 296, 288, 273, 233, - 254, 342, 283, 343, 255, 305, 304, 306, 0, 177, - 0, 380, 416, 443, 195, 196, 197, 645, 232, 236, - 242, 244, 250, 251, 258, 276, 320, 341, 339, 345, - 726, 394, 411, 419, 426, 432, 433, 437, 434, 435, - 438, 308, 257, 376, 272, 281, 718, 756, 326, 357, - 200, 414, 377, 640, 644, 638, 639, 690, 691, 641, - 747, 748, 749, 722, 634, 0, 642, 643, 0, 728, - 737, 738, 695, 170, 184, 277, 752, 346, 240, 440, - 421, 417, 620, 637, 216, 648, 0, 0, 660, 668, - 669, 681, 683, 684, 685, 686, 694, 702, 703, 705, - 713, 715, 717, 719, 724, 734, 755, 172, 173, 185, - 193, 203, 215, 230, 238, 248, 253, 256, 260, 261, - 264, 269, 286, 291, 292, 293, 294, 310, 311, 312, - 315, 318, 319, 322, 324, 325, 328, 334, 335, 336, - 337, 338, 340, 347, 351, 359, 360, 361, 362, 363, - 365, 366, 370, 371, 372, 373, 381, 385, 401, 402, - 413, 425, 430, 249, 409, 431, 0, 285, 693, 700, - 287, 234, 252, 262, 708, 420, 382, 189, 353, 241, - 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, - 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, - 392, 299, 220, 741, 727, 393, 0, 676, 744, 647, - 664, 754, 667, 670, 710, 626, 689, 317, 661, 0, - 651, 622, 657, 623, 649, 678, 224, 646, 729, 692, - 743, 275, 221, 628, 652, 331, 666, 176, 712, 369, - 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, - 329, 387, 323, 750, 279, 699, 0, 378, 302, 0, - 0, 0, 680, 733, 687, 723, 675, 711, 636, 698, - 745, 662, 707, 746, 265, 207, 175, 314, 379, 239, - 0, 0, 0, 167, 168, 169, 0, 0, 0, 0, - 0, 0, 0, 0, 198, 0, 205, 704, 740, 659, - 706, 219, 263, 226, 218, 395, 751, 732, 0, 191, - 742, 682, 709, 757, 621, 701, 0, 624, 627, 753, - 736, 655, 229, 0, 0, 0, 0, 0, 0, 0, - 679, 688, 720, 673, 0, 0, 0, 0, 0, 0, - 1764, 0, 653, 0, 697, 0, 0, 0, 632, 625, - 0, 0, 0, 0, 677, 0, 0, 0, 635, 0, - 654, 721, 0, 619, 247, 629, 303, 0, 725, 735, - 674, 427, 739, 672, 671, 716, 633, 731, 665, 274, - 631, 271, 171, 187, 0, 663, 313, 352, 358, 730, - 650, 658, 210, 656, 356, 327, 412, 194, 237, 349, - 332, 354, 696, 714, 355, 280, 400, 344, 410, 428, - 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, - 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, - 278, 436, 186, 364, 202, 179, 386, 408, 199, 367, - 0, 0, 441, 181, 406, 383, 297, 267, 268, 180, - 0, 348, 222, 243, 212, 316, 403, 404, 211, 442, - 190, 423, 183, 932, 422, 309, 399, 407, 298, 289, - 182, 405, 296, 288, 273, 233, 254, 342, 283, 343, - 255, 305, 304, 306, 0, 177, 0, 380, 416, 443, - 195, 196, 197, 645, 232, 236, 242, 244, 250, 251, - 258, 276, 320, 341, 339, 345, 726, 394, 411, 419, - 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, - 272, 281, 718, 756, 326, 357, 200, 414, 377, 640, - 644, 638, 639, 690, 691, 641, 747, 748, 749, 722, - 634, 0, 642, 643, 0, 728, 737, 738, 695, 170, - 184, 277, 752, 346, 240, 440, 421, 417, 620, 637, - 216, 648, 0, 0, 660, 668, 669, 681, 683, 684, - 685, 686, 694, 702, 703, 705, 713, 715, 717, 719, - 724, 734, 755, 172, 173, 185, 193, 203, 215, 230, - 238, 248, 253, 256, 260, 261, 264, 269, 286, 291, - 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, - 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, - 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, - 372, 373, 381, 385, 401, 402, 413, 425, 430, 249, - 409, 431, 0, 285, 693, 700, 287, 234, 252, 262, - 708, 420, 382, 189, 353, 241, 178, 206, 192, 213, - 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, - 350, 201, 368, 388, 389, 390, 392, 299, 220, 741, - 727, 393, 0, 676, 744, 647, 664, 754, 667, 670, - 710, 626, 689, 317, 661, 0, 651, 622, 657, 623, - 649, 678, 224, 646, 729, 692, 743, 275, 221, 628, - 652, 331, 666, 176, 712, 369, 209, 284, 282, 398, - 235, 227, 223, 208, 259, 290, 329, 387, 323, 750, - 279, 699, 0, 378, 302, 0, 0, 0, 680, 733, - 687, 723, 675, 711, 636, 698, 745, 662, 707, 746, - 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, - 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, - 198, 0, 205, 704, 740, 659, 706, 219, 263, 226, - 218, 395, 751, 732, 0, 191, 742, 682, 709, 757, - 621, 701, 0, 624, 627, 753, 736, 655, 229, 0, - 0, 0, 0, 0, 0, 0, 679, 688, 720, 673, - 0, 0, 0, 0, 0, 0, 1473, 0, 653, 0, - 697, 0, 0, 0, 632, 625, 0, 0, 0, 0, - 677, 0, 0, 0, 635, 0, 654, 721, 0, 619, - 247, 629, 303, 0, 725, 735, 674, 427, 739, 672, - 671, 716, 633, 731, 665, 274, 631, 271, 171, 187, - 0, 663, 313, 352, 358, 730, 650, 658, 210, 656, - 356, 327, 412, 194, 237, 349, 332, 354, 696, 714, - 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, - 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, - 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, - 202, 179, 386, 408, 199, 367, 0, 0, 441, 181, - 406, 383, 297, 267, 268, 180, 0, 348, 222, 243, - 212, 316, 403, 404, 211, 442, 190, 423, 183, 932, - 422, 309, 399, 407, 298, 289, 182, 405, 296, 288, - 273, 233, 254, 342, 283, 343, 255, 305, 304, 306, - 0, 177, 0, 380, 416, 443, 195, 196, 197, 645, - 232, 236, 242, 244, 250, 251, 258, 276, 320, 341, - 339, 345, 726, 394, 411, 419, 426, 432, 433, 437, - 434, 435, 438, 308, 257, 376, 272, 281, 718, 756, - 326, 357, 200, 414, 377, 640, 644, 638, 639, 690, - 691, 641, 747, 748, 749, 722, 634, 0, 642, 643, - 0, 728, 737, 738, 695, 170, 184, 277, 752, 346, - 240, 440, 421, 417, 620, 637, 216, 648, 0, 0, - 660, 668, 669, 681, 683, 684, 685, 686, 694, 702, - 703, 705, 713, 715, 717, 719, 724, 734, 755, 172, - 173, 185, 193, 203, 215, 230, 238, 248, 253, 256, - 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, - 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, - 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, - 362, 363, 365, 366, 370, 371, 372, 373, 381, 385, - 401, 402, 413, 425, 430, 249, 409, 431, 0, 285, - 693, 700, 287, 234, 252, 262, 708, 420, 382, 189, - 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, - 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, - 389, 390, 392, 299, 220, 741, 727, 393, 0, 676, - 744, 647, 664, 754, 667, 670, 710, 626, 689, 317, - 661, 0, 651, 622, 657, 623, 649, 678, 224, 646, - 729, 692, 743, 275, 221, 628, 652, 331, 666, 176, - 712, 369, 209, 284, 282, 398, 235, 227, 223, 208, - 259, 290, 329, 387, 323, 750, 279, 699, 0, 378, - 302, 0, 0, 0, 680, 733, 687, 723, 675, 711, - 636, 698, 745, 662, 707, 746, 265, 207, 175, 314, - 379, 239, 71, 0, 0, 167, 168, 169, 0, 0, - 0, 0, 0, 0, 0, 0, 198, 0, 205, 704, - 740, 659, 706, 219, 263, 226, 218, 395, 751, 732, - 0, 191, 742, 682, 709, 757, 621, 701, 0, 624, - 627, 753, 736, 655, 229, 0, 0, 0, 0, 0, - 0, 0, 679, 688, 720, 673, 0, 0, 0, 0, - 0, 0, 0, 0, 653, 0, 697, 0, 0, 0, - 632, 625, 0, 0, 0, 0, 677, 0, 0, 0, - 635, 0, 654, 721, 0, 619, 247, 629, 303, 0, - 725, 735, 674, 427, 739, 672, 671, 716, 633, 731, - 665, 274, 631, 271, 171, 187, 0, 663, 313, 352, - 358, 730, 650, 658, 210, 656, 356, 327, 412, 194, - 237, 349, 332, 354, 696, 714, 355, 280, 400, 344, - 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, - 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, - 245, 174, 278, 436, 186, 364, 202, 179, 386, 408, - 199, 367, 0, 0, 441, 181, 406, 383, 297, 267, - 268, 180, 0, 348, 222, 243, 212, 316, 403, 404, - 211, 442, 190, 423, 183, 932, 422, 309, 399, 407, - 298, 289, 182, 405, 296, 288, 273, 233, 254, 342, - 283, 343, 255, 305, 304, 306, 0, 177, 0, 380, - 416, 443, 195, 196, 197, 645, 232, 236, 242, 244, - 250, 251, 258, 276, 320, 341, 339, 345, 726, 394, - 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, - 257, 376, 272, 281, 718, 756, 326, 357, 200, 414, - 377, 640, 644, 638, 639, 690, 691, 641, 747, 748, - 749, 722, 634, 0, 642, 643, 0, 728, 737, 738, - 695, 170, 184, 277, 752, 346, 240, 440, 421, 417, - 620, 637, 216, 648, 0, 0, 660, 668, 669, 681, - 683, 684, 685, 686, 694, 702, 703, 705, 713, 715, - 717, 719, 724, 734, 755, 172, 173, 185, 193, 203, - 215, 230, 238, 248, 253, 256, 260, 261, 264, 269, - 286, 291, 292, 293, 294, 310, 311, 312, 315, 318, - 319, 322, 324, 325, 328, 334, 335, 336, 337, 338, - 340, 347, 351, 359, 360, 361, 362, 363, 365, 366, - 370, 371, 372, 373, 381, 385, 401, 402, 413, 425, - 430, 249, 409, 431, 0, 285, 693, 700, 287, 234, - 252, 262, 708, 420, 382, 189, 353, 241, 178, 206, - 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, - 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, - 220, 741, 727, 393, 0, 676, 744, 647, 664, 754, - 667, 670, 710, 626, 689, 317, 661, 0, 651, 622, - 657, 623, 649, 678, 224, 646, 729, 692, 743, 275, - 221, 628, 652, 331, 666, 176, 712, 369, 209, 284, - 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, - 323, 750, 279, 699, 0, 378, 302, 0, 0, 0, - 680, 733, 687, 723, 675, 711, 636, 698, 745, 662, - 707, 746, 265, 207, 175, 314, 379, 239, 0, 0, - 0, 167, 168, 169, 0, 0, 0, 0, 0, 0, - 0, 0, 198, 0, 205, 704, 740, 659, 706, 219, - 263, 226, 218, 395, 751, 732, 0, 191, 742, 682, - 709, 757, 621, 701, 0, 624, 627, 753, 736, 655, - 229, 0, 0, 0, 0, 0, 0, 0, 679, 688, - 720, 673, 0, 0, 0, 0, 0, 0, 0, 0, - 653, 0, 697, 0, 0, 0, 632, 625, 0, 0, - 0, 0, 677, 0, 0, 0, 635, 0, 654, 721, - 0, 619, 247, 629, 303, 0, 725, 735, 674, 427, - 739, 672, 671, 716, 633, 731, 665, 274, 631, 271, - 171, 187, 0, 663, 313, 352, 358, 730, 650, 658, - 210, 656, 356, 327, 412, 194, 237, 349, 332, 354, - 696, 714, 355, 280, 400, 344, 410, 428, 429, 217, - 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, - 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, - 186, 364, 202, 179, 386, 408, 199, 367, 0, 0, - 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, - 222, 243, 212, 316, 403, 404, 211, 442, 190, 423, - 183, 932, 422, 309, 399, 407, 298, 289, 182, 405, - 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, - 304, 306, 0, 177, 0, 380, 416, 443, 195, 196, - 197, 645, 232, 236, 242, 244, 250, 251, 258, 276, - 320, 341, 339, 345, 726, 394, 411, 419, 426, 432, - 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, - 718, 756, 326, 357, 200, 414, 377, 640, 644, 638, - 639, 690, 691, 641, 747, 748, 749, 722, 634, 0, - 642, 643, 0, 728, 737, 738, 695, 170, 184, 277, - 752, 346, 240, 440, 421, 417, 620, 637, 216, 648, - 0, 0, 660, 668, 669, 681, 683, 684, 685, 686, - 694, 702, 703, 705, 713, 715, 717, 719, 724, 734, - 755, 172, 173, 185, 193, 203, 215, 230, 238, 248, - 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, - 294, 310, 311, 312, 315, 318, 319, 322, 324, 325, - 328, 334, 335, 336, 337, 338, 340, 347, 351, 359, - 360, 361, 362, 363, 365, 366, 370, 371, 372, 373, - 381, 385, 401, 402, 413, 425, 430, 249, 409, 431, - 0, 285, 693, 700, 287, 234, 252, 262, 708, 420, - 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, - 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, - 368, 388, 389, 390, 392, 299, 220, 741, 727, 393, - 0, 676, 744, 647, 664, 754, 667, 670, 710, 626, - 689, 317, 661, 0, 651, 622, 657, 623, 649, 678, - 224, 646, 729, 692, 743, 275, 221, 628, 652, 331, - 666, 176, 712, 369, 209, 284, 282, 398, 235, 227, - 223, 208, 259, 290, 329, 387, 323, 750, 279, 699, - 0, 378, 302, 0, 0, 0, 680, 733, 687, 723, - 675, 711, 636, 698, 745, 662, 707, 746, 265, 207, - 175, 314, 379, 239, 0, 0, 0, 167, 168, 169, - 0, 0, 0, 0, 0, 0, 0, 0, 198, 0, - 205, 704, 740, 659, 706, 219, 263, 226, 218, 395, - 751, 732, 0, 758, 742, 682, 709, 757, 621, 701, - 0, 624, 627, 753, 736, 655, 229, 0, 0, 0, - 0, 0, 0, 0, 679, 688, 720, 673, 0, 0, - 0, 0, 0, 0, 0, 0, 653, 0, 697, 0, - 0, 0, 632, 625, 0, 0, 0, 0, 677, 0, - 0, 0, 635, 0, 654, 721, 0, 619, 247, 629, - 303, 0, 725, 735, 674, 427, 739, 672, 671, 716, - 633, 731, 665, 274, 631, 271, 171, 187, 0, 663, - 313, 352, 358, 730, 650, 658, 210, 656, 356, 327, - 412, 194, 237, 349, 332, 354, 696, 714, 355, 280, - 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, - 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, - 270, 374, 245, 174, 278, 436, 186, 364, 202, 179, - 386, 408, 199, 367, 0, 0, 441, 181, 406, 383, - 297, 267, 268, 180, 0, 348, 222, 243, 212, 316, - 403, 404, 211, 442, 190, 423, 183, 630, 422, 309, - 399, 407, 298, 289, 182, 405, 296, 288, 273, 233, - 254, 342, 283, 343, 255, 305, 304, 306, 0, 177, - 0, 380, 416, 443, 195, 196, 197, 645, 232, 236, - 242, 244, 250, 251, 258, 276, 320, 341, 339, 345, - 726, 394, 411, 419, 426, 432, 433, 437, 434, 435, - 438, 618, 612, 611, 272, 281, 718, 756, 326, 357, - 200, 414, 377, 640, 644, 638, 639, 690, 691, 641, - 747, 748, 749, 722, 634, 0, 642, 643, 0, 728, - 737, 738, 695, 170, 184, 277, 752, 346, 240, 440, - 421, 417, 620, 637, 216, 648, 0, 0, 660, 668, - 669, 681, 683, 684, 685, 686, 694, 702, 703, 705, - 713, 715, 717, 719, 724, 734, 755, 172, 173, 185, - 193, 203, 215, 230, 238, 248, 253, 256, 260, 261, - 264, 269, 286, 291, 292, 293, 294, 310, 311, 312, - 315, 318, 319, 322, 324, 325, 328, 334, 335, 336, - 337, 338, 340, 347, 351, 359, 360, 361, 362, 363, - 365, 366, 370, 371, 372, 373, 381, 385, 401, 402, - 413, 425, 430, 249, 409, 431, 0, 285, 693, 700, - 287, 234, 252, 262, 708, 420, 382, 189, 353, 241, - 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, - 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, - 392, 299, 220, 741, 727, 393, 0, 676, 744, 647, - 664, 754, 667, 670, 710, 626, 689, 317, 661, 0, - 651, 622, 657, 623, 649, 678, 224, 646, 729, 692, - 743, 275, 221, 628, 652, 331, 666, 176, 712, 369, - 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, - 329, 387, 323, 750, 279, 699, 0, 378, 302, 0, - 0, 0, 680, 733, 687, 723, 675, 711, 636, 698, - 745, 662, 707, 746, 265, 207, 175, 314, 379, 239, - 0, 0, 0, 167, 168, 169, 0, 0, 0, 0, - 0, 0, 0, 0, 198, 0, 205, 704, 740, 659, - 706, 219, 263, 226, 218, 395, 751, 732, 0, 758, - 742, 682, 709, 757, 621, 701, 0, 624, 627, 753, - 736, 655, 229, 0, 0, 0, 0, 0, 0, 0, - 679, 688, 720, 673, 0, 0, 0, 0, 0, 0, - 0, 0, 653, 0, 697, 0, 0, 0, 632, 625, - 0, 0, 0, 0, 677, 0, 0, 0, 635, 0, - 654, 721, 0, 619, 247, 629, 303, 0, 725, 735, - 674, 427, 739, 672, 671, 716, 633, 731, 665, 274, - 631, 271, 171, 187, 0, 663, 313, 352, 358, 730, - 650, 658, 210, 656, 356, 327, 412, 194, 237, 349, - 332, 354, 696, 714, 355, 280, 400, 344, 410, 428, - 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, - 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, - 278, 436, 186, 364, 202, 179, 386, 1100, 199, 367, - 0, 0, 441, 181, 406, 383, 297, 267, 268, 180, - 0, 348, 222, 243, 212, 316, 403, 404, 211, 442, - 190, 423, 183, 630, 422, 309, 399, 407, 298, 289, - 182, 405, 296, 288, 273, 233, 254, 342, 283, 343, - 255, 305, 304, 306, 0, 177, 0, 380, 416, 443, - 195, 196, 197, 645, 232, 236, 242, 244, 250, 251, - 258, 276, 320, 341, 339, 345, 726, 394, 411, 419, - 426, 432, 433, 437, 434, 435, 438, 618, 612, 611, - 272, 281, 718, 756, 326, 357, 200, 414, 377, 640, - 644, 638, 639, 690, 691, 641, 747, 748, 749, 722, - 634, 0, 642, 643, 0, 728, 737, 738, 695, 170, - 184, 277, 752, 346, 240, 440, 421, 417, 620, 637, - 216, 648, 0, 0, 660, 668, 669, 681, 683, 684, - 685, 686, 694, 702, 703, 705, 713, 715, 717, 719, - 724, 734, 755, 172, 173, 185, 193, 203, 215, 230, - 238, 248, 253, 256, 260, 261, 264, 269, 286, 291, - 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, - 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, - 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, - 372, 373, 381, 385, 401, 402, 413, 425, 430, 249, - 409, 431, 0, 285, 693, 700, 287, 234, 252, 262, - 708, 420, 382, 189, 353, 241, 178, 206, 192, 213, - 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, - 350, 201, 368, 388, 389, 390, 392, 299, 220, 741, - 727, 393, 0, 676, 744, 647, 664, 754, 667, 670, - 710, 626, 689, 317, 661, 0, 651, 622, 657, 623, - 649, 678, 224, 646, 729, 692, 743, 275, 221, 628, - 652, 331, 666, 176, 712, 369, 209, 284, 282, 398, - 235, 227, 223, 208, 259, 290, 329, 387, 323, 750, - 279, 699, 0, 378, 302, 0, 0, 0, 680, 733, - 687, 723, 675, 711, 636, 698, 745, 662, 707, 746, - 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, - 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, - 198, 0, 205, 704, 740, 659, 706, 219, 263, 226, - 218, 395, 751, 732, 0, 758, 742, 682, 709, 757, - 621, 701, 0, 624, 627, 753, 736, 655, 229, 0, - 0, 0, 0, 0, 0, 0, 679, 688, 720, 673, - 0, 0, 0, 0, 0, 0, 0, 0, 653, 0, - 697, 0, 0, 0, 632, 625, 0, 0, 0, 0, - 677, 0, 0, 0, 635, 0, 654, 721, 0, 619, - 247, 629, 303, 0, 725, 735, 674, 427, 739, 672, - 671, 716, 633, 731, 665, 274, 631, 271, 171, 187, - 0, 663, 313, 352, 358, 730, 650, 658, 210, 656, - 356, 327, 412, 194, 237, 349, 332, 354, 696, 714, - 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, - 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, - 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, - 202, 179, 386, 609, 199, 367, 0, 0, 441, 181, - 406, 383, 297, 267, 268, 180, 0, 348, 222, 243, - 212, 316, 403, 404, 211, 442, 190, 423, 183, 630, - 422, 309, 399, 407, 298, 289, 182, 405, 296, 288, - 273, 233, 254, 342, 283, 343, 255, 305, 304, 306, - 0, 177, 0, 380, 416, 443, 195, 196, 197, 645, - 232, 236, 242, 244, 250, 251, 258, 276, 320, 341, - 339, 345, 726, 394, 411, 419, 426, 432, 433, 437, - 434, 435, 438, 618, 612, 611, 272, 281, 718, 756, - 326, 357, 200, 414, 377, 640, 644, 638, 639, 690, - 691, 641, 747, 748, 749, 722, 634, 0, 642, 643, - 0, 728, 737, 738, 695, 170, 184, 277, 752, 346, - 240, 440, 421, 417, 620, 637, 216, 648, 0, 0, - 660, 668, 669, 681, 683, 684, 685, 686, 694, 702, - 703, 705, 713, 715, 717, 719, 724, 734, 755, 172, - 173, 185, 193, 203, 215, 230, 238, 248, 253, 256, - 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, - 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, - 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, - 362, 363, 365, 366, 370, 371, 372, 373, 381, 385, - 401, 402, 413, 425, 430, 249, 409, 431, 0, 285, - 693, 700, 287, 234, 252, 262, 708, 420, 382, 189, - 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, - 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, - 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 317, 0, 0, - 1401, 0, 509, 0, 0, 0, 224, 508, 0, 0, - 0, 275, 221, 0, 1402, 331, 0, 176, 0, 369, - 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, - 329, 387, 323, 552, 279, 0, 0, 378, 302, 0, - 0, 0, 0, 0, 543, 544, 0, 0, 0, 0, - 0, 0, 0, 0, 265, 207, 175, 314, 379, 239, - 71, 0, 0, 167, 168, 169, 530, 529, 532, 533, - 534, 535, 0, 0, 198, 531, 205, 536, 537, 538, - 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, - 0, 0, 0, 0, 0, 506, 523, 0, 551, 0, - 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 520, 521, - 599, 0, 0, 0, 567, 0, 522, 0, 0, 515, - 516, 518, 517, 519, 524, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 247, 0, 303, 0, 566, 0, - 0, 427, 0, 0, 564, 0, 0, 0, 0, 274, - 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, - 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, - 332, 354, 0, 0, 355, 280, 400, 344, 410, 428, - 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, - 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, - 278, 436, 186, 364, 202, 179, 386, 408, 199, 367, - 0, 0, 441, 181, 406, 383, 297, 267, 268, 180, - 0, 348, 222, 243, 212, 316, 403, 404, 211, 442, - 190, 423, 183, 0, 422, 309, 399, 407, 298, 289, - 182, 405, 296, 288, 273, 233, 254, 342, 283, 343, - 255, 305, 304, 306, 0, 177, 0, 380, 416, 443, - 195, 196, 197, 0, 232, 236, 242, 244, 250, 251, - 258, 276, 320, 341, 339, 345, 0, 394, 411, 419, - 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, - 272, 281, 0, 0, 326, 357, 200, 414, 377, 554, - 565, 560, 561, 558, 559, 553, 557, 556, 555, 568, - 545, 546, 547, 548, 550, 0, 562, 563, 549, 170, - 184, 277, 0, 346, 240, 440, 421, 417, 0, 0, - 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 172, 173, 185, 193, 203, 215, 230, - 238, 248, 253, 256, 260, 261, 264, 269, 286, 291, - 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, - 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, - 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, - 372, 373, 381, 385, 401, 402, 413, 425, 430, 249, - 409, 431, 0, 285, 0, 0, 287, 234, 252, 262, - 0, 420, 382, 189, 353, 241, 178, 206, 192, 213, - 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, - 350, 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 317, 0, 0, 0, 0, 509, 0, 0, 0, - 224, 508, 0, 0, 0, 275, 221, 0, 0, 331, - 0, 176, 0, 369, 209, 284, 282, 398, 235, 227, - 223, 208, 259, 290, 329, 387, 323, 552, 279, 0, - 0, 378, 302, 0, 0, 0, 0, 0, 543, 544, - 0, 0, 0, 0, 0, 0, 1512, 0, 265, 207, - 175, 314, 379, 239, 71, 0, 0, 167, 168, 169, - 530, 529, 532, 533, 534, 535, 0, 0, 198, 531, - 205, 536, 537, 538, 1513, 219, 263, 226, 218, 395, - 0, 0, 0, 191, 0, 0, 0, 0, 0, 506, - 523, 0, 551, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 520, 521, 0, 0, 0, 0, 567, 0, - 522, 0, 0, 515, 516, 518, 517, 519, 524, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, - 303, 0, 566, 0, 0, 427, 0, 0, 564, 0, - 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, - 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, - 412, 194, 237, 349, 332, 354, 0, 0, 355, 280, - 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, - 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, - 270, 374, 245, 174, 278, 436, 186, 364, 202, 179, - 386, 408, 199, 367, 0, 0, 441, 181, 406, 383, - 297, 267, 268, 180, 0, 348, 222, 243, 212, 316, - 403, 404, 211, 442, 190, 423, 183, 0, 422, 309, - 399, 407, 298, 289, 182, 405, 296, 288, 273, 233, - 254, 342, 283, 343, 255, 305, 304, 306, 0, 177, - 0, 380, 416, 443, 195, 196, 197, 0, 232, 236, - 242, 244, 250, 251, 258, 276, 320, 341, 339, 345, - 0, 394, 411, 419, 426, 432, 433, 437, 434, 435, - 438, 308, 257, 376, 272, 281, 0, 0, 326, 357, - 200, 414, 377, 554, 565, 560, 561, 558, 559, 553, - 557, 556, 555, 568, 545, 546, 547, 548, 550, 0, - 562, 563, 549, 170, 184, 277, 0, 346, 240, 440, - 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 172, 173, 185, - 193, 203, 215, 230, 238, 248, 253, 256, 260, 261, - 264, 269, 286, 291, 292, 293, 294, 310, 311, 312, - 315, 318, 319, 322, 324, 325, 328, 334, 335, 336, - 337, 338, 340, 347, 351, 359, 360, 361, 362, 363, - 365, 366, 370, 371, 372, 373, 381, 385, 401, 402, - 413, 425, 430, 249, 409, 431, 0, 285, 0, 0, - 287, 234, 252, 262, 0, 420, 382, 189, 353, 241, - 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, - 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, - 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 317, 0, 0, 0, 0, - 509, 0, 0, 0, 224, 508, 0, 0, 0, 275, - 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, - 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, - 323, 552, 279, 0, 0, 378, 302, 0, 0, 0, - 0, 0, 543, 544, 0, 0, 0, 0, 0, 0, - 0, 0, 265, 207, 175, 314, 379, 239, 71, 0, - 586, 167, 168, 169, 530, 529, 532, 533, 534, 535, - 0, 0, 198, 531, 205, 536, 537, 538, 0, 219, - 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, - 0, 0, 0, 506, 523, 0, 551, 0, 0, 0, - 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 520, 521, 0, 0, - 0, 0, 567, 0, 522, 0, 0, 515, 516, 518, - 517, 519, 524, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 247, 0, 303, 0, 566, 0, 0, 427, - 0, 0, 564, 0, 0, 0, 0, 274, 0, 271, - 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, - 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, - 0, 0, 355, 280, 400, 344, 410, 428, 429, 217, - 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, - 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, - 186, 364, 202, 179, 386, 408, 199, 367, 0, 0, - 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, - 222, 243, 212, 316, 403, 404, 211, 442, 190, 423, - 183, 0, 422, 309, 399, 407, 298, 289, 182, 405, - 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, - 304, 306, 0, 177, 0, 380, 416, 443, 195, 196, - 197, 0, 232, 236, 242, 244, 250, 251, 258, 276, - 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, - 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, - 0, 0, 326, 357, 200, 414, 377, 554, 565, 560, - 561, 558, 559, 553, 557, 556, 555, 568, 545, 546, - 547, 548, 550, 0, 562, 563, 549, 170, 184, 277, - 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 172, 173, 185, 193, 203, 215, 230, 238, 248, - 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, - 294, 310, 311, 312, 315, 318, 319, 322, 324, 325, - 328, 334, 335, 336, 337, 338, 340, 347, 351, 359, - 360, 361, 362, 363, 365, 366, 370, 371, 372, 373, - 381, 385, 401, 402, 413, 425, 430, 249, 409, 431, - 0, 285, 0, 0, 287, 234, 252, 262, 0, 420, - 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, - 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, - 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 317, - 0, 0, 0, 0, 509, 0, 0, 0, 224, 508, - 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, - 0, 369, 209, 284, 282, 398, 235, 227, 223, 208, - 259, 290, 329, 387, 323, 552, 279, 0, 0, 378, - 302, 0, 0, 0, 0, 0, 543, 544, 0, 0, - 0, 0, 0, 0, 0, 0, 265, 207, 175, 314, - 379, 239, 71, 0, 0, 167, 168, 169, 530, 529, - 532, 533, 534, 535, 0, 0, 198, 531, 205, 536, - 537, 538, 0, 219, 263, 226, 218, 395, 0, 0, - 0, 191, 0, 0, 0, 0, 0, 506, 523, 0, - 551, 0, 0, 0, 229, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 520, 521, 599, 0, 0, 0, 567, 0, 522, 0, - 0, 515, 516, 518, 517, 519, 524, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 247, 0, 303, 0, - 566, 0, 0, 427, 0, 0, 564, 0, 0, 0, - 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, - 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, - 237, 349, 332, 354, 0, 0, 355, 280, 400, 344, - 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, - 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, - 245, 174, 278, 436, 186, 364, 202, 179, 386, 408, - 199, 367, 0, 0, 441, 181, 406, 383, 297, 267, - 268, 180, 0, 348, 222, 243, 212, 316, 403, 404, - 211, 442, 190, 423, 183, 0, 422, 309, 399, 407, - 298, 289, 182, 405, 296, 288, 273, 233, 254, 342, - 283, 343, 255, 305, 304, 306, 0, 177, 0, 380, - 416, 443, 195, 196, 197, 0, 232, 236, 242, 244, - 250, 251, 258, 276, 320, 341, 339, 345, 0, 394, - 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, - 257, 376, 272, 281, 0, 0, 326, 357, 200, 414, - 377, 554, 565, 560, 561, 558, 559, 553, 557, 556, - 555, 568, 545, 546, 547, 548, 550, 0, 562, 563, - 549, 170, 184, 277, 0, 346, 240, 440, 421, 417, - 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 172, 173, 185, 193, 203, - 215, 230, 238, 248, 253, 256, 260, 261, 264, 269, - 286, 291, 292, 293, 294, 310, 311, 312, 315, 318, - 319, 322, 324, 325, 328, 334, 335, 336, 337, 338, - 340, 347, 351, 359, 360, 361, 362, 363, 365, 366, - 370, 371, 372, 373, 381, 385, 401, 402, 413, 425, - 430, 249, 409, 431, 0, 285, 0, 0, 287, 234, - 252, 262, 0, 420, 382, 189, 353, 241, 178, 206, - 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, - 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, - 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 317, 0, 0, 0, 0, 509, 0, - 0, 0, 224, 508, 0, 0, 0, 275, 221, 0, - 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, - 235, 227, 223, 208, 259, 290, 329, 387, 323, 552, - 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, - 543, 544, 0, 0, 0, 0, 0, 0, 0, 0, - 265, 207, 175, 314, 379, 239, 71, 0, 0, 167, - 168, 169, 530, 1419, 532, 533, 534, 535, 0, 0, - 198, 531, 205, 536, 537, 538, 0, 219, 263, 226, - 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, - 0, 506, 523, 0, 551, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 520, 521, 599, 0, 0, 0, - 567, 0, 522, 0, 0, 515, 516, 518, 517, 519, - 524, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 247, 0, 303, 0, 566, 0, 0, 427, 0, 0, - 564, 0, 0, 0, 0, 274, 0, 271, 171, 187, - 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, - 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, - 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, - 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, - 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, - 202, 179, 386, 408, 199, 367, 0, 0, 441, 181, - 406, 383, 297, 267, 268, 180, 0, 348, 222, 243, - 212, 316, 403, 404, 211, 442, 190, 423, 183, 0, - 422, 309, 399, 407, 298, 289, 182, 405, 296, 288, - 273, 233, 254, 342, 283, 343, 255, 305, 304, 306, - 0, 177, 0, 380, 416, 443, 195, 196, 197, 0, - 232, 236, 242, 244, 250, 251, 258, 276, 320, 341, - 339, 345, 0, 394, 411, 419, 426, 432, 433, 437, - 434, 435, 438, 308, 257, 376, 272, 281, 0, 0, - 326, 357, 200, 414, 377, 554, 565, 560, 561, 558, - 559, 553, 557, 556, 555, 568, 545, 546, 547, 548, - 550, 0, 562, 563, 549, 170, 184, 277, 0, 346, - 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, - 173, 185, 193, 203, 215, 230, 238, 248, 253, 256, - 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, - 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, - 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, - 362, 363, 365, 366, 370, 371, 372, 373, 381, 385, - 401, 402, 413, 425, 430, 249, 409, 431, 0, 285, - 0, 0, 287, 234, 252, 262, 0, 420, 382, 189, - 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, - 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, - 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 317, 0, 0, - 0, 0, 509, 0, 0, 0, 224, 508, 0, 0, - 0, 275, 221, 0, 0, 331, 0, 176, 0, 369, - 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, - 329, 387, 323, 552, 279, 0, 0, 378, 302, 0, - 0, 0, 0, 0, 543, 544, 0, 0, 0, 0, - 0, 0, 0, 0, 265, 207, 175, 314, 379, 239, - 71, 0, 0, 167, 168, 169, 530, 1416, 532, 533, - 534, 535, 0, 0, 198, 531, 205, 536, 537, 538, - 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, - 0, 0, 0, 0, 0, 506, 523, 0, 551, 0, - 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 520, 521, - 599, 0, 0, 0, 567, 0, 522, 0, 0, 515, - 516, 518, 517, 519, 524, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 247, 0, 303, 0, 566, 0, - 0, 427, 0, 0, 564, 0, 0, 0, 0, 274, - 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, - 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, - 332, 354, 0, 0, 355, 280, 400, 344, 410, 428, - 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, - 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, - 278, 436, 186, 364, 202, 179, 386, 408, 199, 367, - 0, 0, 441, 181, 406, 383, 297, 267, 268, 180, - 0, 348, 222, 243, 212, 316, 403, 404, 211, 442, - 190, 423, 183, 0, 422, 309, 399, 407, 298, 289, - 182, 405, 296, 288, 273, 233, 254, 342, 283, 343, - 255, 305, 304, 306, 0, 177, 0, 380, 416, 443, - 195, 196, 197, 0, 232, 236, 242, 244, 250, 251, - 258, 276, 320, 341, 339, 345, 0, 394, 411, 419, - 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, - 272, 281, 0, 0, 326, 357, 200, 414, 377, 554, - 565, 560, 561, 558, 559, 553, 557, 556, 555, 568, - 545, 546, 547, 548, 550, 0, 562, 563, 549, 170, - 184, 277, 0, 346, 240, 440, 421, 417, 0, 0, - 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 172, 173, 185, 193, 203, 215, 230, - 238, 248, 253, 256, 260, 261, 264, 269, 286, 291, - 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, - 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, - 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, - 372, 373, 381, 385, 401, 402, 413, 425, 430, 249, - 409, 431, 0, 285, 0, 0, 287, 234, 252, 262, - 0, 420, 382, 189, 353, 241, 178, 206, 192, 213, - 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, - 350, 201, 368, 388, 389, 390, 392, 299, 220, 579, - 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 317, 0, 0, 0, 0, 509, 0, 0, - 0, 224, 508, 0, 0, 0, 275, 221, 0, 0, - 331, 0, 176, 0, 369, 209, 284, 282, 398, 235, - 227, 223, 208, 259, 290, 329, 387, 323, 552, 279, - 0, 0, 378, 302, 0, 0, 0, 0, 0, 543, - 544, 0, 0, 0, 0, 0, 0, 0, 0, 265, - 207, 175, 314, 379, 239, 71, 0, 0, 167, 168, - 169, 530, 529, 532, 533, 534, 535, 0, 0, 198, - 531, 205, 536, 537, 538, 0, 219, 263, 226, 218, - 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, - 506, 523, 0, 551, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 520, 521, 0, 0, 0, 0, 567, - 0, 522, 0, 0, 515, 516, 518, 517, 519, 524, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, - 0, 303, 0, 566, 0, 0, 427, 0, 0, 564, - 0, 0, 0, 0, 274, 0, 271, 171, 187, 0, - 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, - 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, - 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, - 424, 439, 188, 214, 321, 384, 415, 375, 300, 396, - 397, 270, 374, 245, 174, 278, 436, 186, 364, 202, - 179, 386, 408, 199, 367, 0, 0, 441, 181, 406, - 383, 297, 267, 268, 180, 0, 348, 222, 243, 212, - 316, 403, 404, 211, 442, 190, 423, 183, 0, 422, - 309, 399, 407, 298, 289, 182, 405, 296, 288, 273, - 233, 254, 342, 283, 343, 255, 305, 304, 306, 0, - 177, 0, 380, 416, 443, 195, 196, 197, 0, 232, - 236, 242, 244, 250, 251, 258, 276, 320, 341, 339, - 345, 0, 394, 411, 419, 426, 432, 433, 437, 434, - 435, 438, 308, 257, 376, 272, 281, 0, 0, 326, - 357, 200, 414, 377, 554, 565, 560, 561, 558, 559, - 553, 557, 556, 555, 568, 545, 546, 547, 548, 550, - 0, 562, 563, 549, 170, 184, 277, 0, 346, 240, - 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, - 185, 193, 203, 215, 230, 238, 248, 253, 256, 260, - 261, 264, 269, 286, 291, 292, 293, 294, 310, 311, - 312, 315, 318, 319, 322, 324, 325, 328, 334, 335, - 336, 337, 338, 340, 347, 351, 359, 360, 361, 362, - 363, 365, 366, 370, 371, 372, 373, 381, 385, 401, - 402, 413, 425, 430, 249, 409, 431, 0, 285, 0, - 0, 287, 234, 252, 262, 0, 420, 382, 189, 353, - 241, 178, 206, 192, 213, 228, 231, 266, 295, 301, - 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, - 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, - 0, 509, 0, 0, 0, 224, 508, 0, 0, 0, - 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, - 284, 282, 398, 235, 227, 223, 208, 259, 290, 329, - 387, 323, 552, 279, 0, 0, 378, 302, 0, 0, - 0, 0, 0, 543, 544, 0, 0, 0, 0, 0, - 0, 0, 0, 265, 207, 175, 314, 379, 239, 71, - 0, 0, 167, 168, 169, 530, 529, 532, 533, 534, - 535, 0, 0, 198, 531, 205, 536, 537, 538, 0, - 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, - 0, 0, 0, 0, 506, 523, 0, 551, 0, 0, - 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 520, 521, 0, - 0, 0, 0, 567, 0, 522, 0, 0, 515, 516, - 518, 517, 519, 524, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 247, 0, 303, 0, 566, 0, 0, - 427, 0, 0, 564, 0, 0, 0, 0, 274, 0, - 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, - 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, - 354, 0, 0, 355, 280, 400, 344, 410, 428, 429, - 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, - 415, 375, 300, 396, 397, 270, 374, 245, 174, 278, - 436, 186, 364, 202, 179, 386, 408, 199, 367, 0, - 0, 441, 181, 406, 383, 297, 267, 268, 180, 0, - 348, 222, 243, 212, 316, 403, 404, 211, 442, 190, - 423, 183, 0, 422, 309, 399, 407, 298, 289, 182, - 405, 296, 288, 273, 233, 254, 342, 283, 343, 255, - 305, 304, 306, 0, 177, 0, 380, 416, 443, 195, - 196, 197, 0, 232, 236, 242, 244, 250, 251, 258, - 276, 320, 341, 339, 345, 0, 394, 411, 419, 426, - 432, 433, 437, 434, 435, 438, 308, 257, 376, 272, - 281, 0, 0, 326, 357, 200, 414, 377, 554, 565, - 560, 561, 558, 559, 553, 557, 556, 555, 568, 545, - 546, 547, 548, 550, 0, 562, 563, 549, 170, 184, - 277, 0, 346, 240, 440, 421, 417, 0, 0, 216, + 0, 1937, 0, 34, 0, 1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 172, 173, 185, 193, 203, 215, 230, 238, - 248, 253, 256, 260, 261, 264, 269, 286, 291, 292, - 293, 294, 310, 311, 312, 315, 318, 319, 322, 324, - 325, 328, 334, 335, 336, 337, 338, 340, 347, 351, - 359, 360, 361, 362, 363, 365, 366, 370, 371, 372, - 373, 381, 385, 401, 402, 413, 425, 430, 249, 409, - 431, 0, 285, 0, 0, 287, 234, 252, 262, 0, - 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, - 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, - 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 317, 0, 0, 0, 0, 0, 0, 0, 0, 224, - 0, 0, 0, 0, 275, 221, 0, 0, 331, 0, - 176, 0, 369, 209, 284, 282, 398, 235, 227, 223, - 208, 259, 290, 329, 387, 323, 552, 279, 0, 0, - 378, 302, 0, 0, 0, 0, 0, 543, 544, 0, - 0, 0, 0, 0, 0, 0, 0, 265, 207, 175, - 314, 379, 239, 71, 0, 0, 167, 168, 169, 530, - 529, 532, 533, 534, 535, 0, 0, 198, 531, 205, - 536, 537, 538, 0, 219, 263, 226, 218, 395, 0, - 0, 0, 191, 0, 0, 0, 0, 0, 0, 523, - 0, 551, 0, 0, 0, 229, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 520, 521, 0, 0, 0, 0, 567, 0, 522, - 0, 0, 515, 516, 518, 517, 519, 524, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 247, 0, 303, - 0, 566, 0, 0, 427, 0, 0, 564, 0, 0, - 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, - 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, - 194, 237, 349, 332, 354, 2237, 0, 355, 280, 400, - 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, - 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, - 374, 245, 174, 278, 436, 186, 364, 202, 179, 386, - 408, 199, 367, 0, 0, 441, 181, 406, 383, 297, - 267, 268, 180, 0, 348, 222, 243, 212, 316, 403, - 404, 211, 442, 190, 423, 183, 0, 422, 309, 399, - 407, 298, 289, 182, 405, 296, 288, 273, 233, 254, - 342, 283, 343, 255, 305, 304, 306, 0, 177, 0, - 380, 416, 443, 195, 196, 197, 0, 232, 236, 242, - 244, 250, 251, 258, 276, 320, 341, 339, 345, 0, - 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, - 308, 257, 376, 272, 281, 0, 0, 326, 357, 200, - 414, 377, 554, 565, 560, 561, 558, 559, 553, 557, - 556, 555, 568, 545, 546, 547, 548, 550, 0, 562, - 563, 549, 170, 184, 277, 0, 346, 240, 440, 421, - 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 172, 173, 185, 193, - 203, 215, 230, 238, 248, 253, 256, 260, 261, 264, - 269, 286, 291, 292, 293, 294, 310, 311, 312, 315, - 318, 319, 322, 324, 325, 328, 334, 335, 336, 337, - 338, 340, 347, 351, 359, 360, 361, 362, 363, 365, - 366, 370, 371, 372, 373, 381, 385, 401, 402, 413, - 425, 430, 249, 409, 431, 0, 285, 0, 0, 287, - 234, 252, 262, 0, 420, 382, 189, 353, 241, 178, - 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, - 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, - 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 317, 0, 0, 0, 0, 0, - 0, 0, 0, 224, 0, 0, 0, 0, 275, 221, - 0, 0, 331, 0, 176, 0, 369, 209, 284, 282, - 398, 235, 227, 223, 208, 259, 290, 329, 387, 323, - 552, 279, 0, 0, 378, 302, 0, 0, 0, 0, - 0, 543, 544, 0, 0, 0, 0, 0, 0, 0, - 0, 265, 207, 175, 314, 379, 239, 71, 0, 586, - 167, 168, 169, 530, 529, 532, 533, 534, 535, 0, - 0, 198, 531, 205, 536, 537, 538, 0, 219, 263, - 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, - 0, 0, 0, 523, 0, 551, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 520, 521, 0, 0, 0, - 0, 567, 0, 522, 0, 0, 515, 516, 518, 517, - 519, 524, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 247, 0, 303, 0, 566, 0, 0, 427, 0, - 0, 564, 0, 0, 0, 0, 274, 0, 271, 171, - 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, - 0, 356, 327, 412, 194, 237, 349, 332, 354, 0, - 0, 355, 280, 400, 344, 410, 428, 429, 217, 307, - 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, - 300, 396, 397, 270, 374, 245, 174, 278, 436, 186, - 364, 202, 179, 386, 408, 199, 367, 0, 0, 441, - 181, 406, 383, 297, 267, 268, 180, 0, 348, 222, - 243, 212, 316, 403, 404, 211, 442, 190, 423, 183, - 0, 422, 309, 399, 407, 298, 289, 182, 405, 296, - 288, 273, 233, 254, 342, 283, 343, 255, 305, 304, - 306, 0, 177, 0, 380, 416, 443, 195, 196, 197, - 0, 232, 236, 242, 244, 250, 251, 258, 276, 320, - 341, 339, 345, 0, 394, 411, 419, 426, 432, 433, - 437, 434, 435, 438, 308, 257, 376, 272, 281, 0, - 0, 326, 357, 200, 414, 377, 554, 565, 560, 561, - 558, 559, 553, 557, 556, 555, 568, 545, 546, 547, - 548, 550, 0, 562, 563, 549, 170, 184, 277, 0, - 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 172, 173, 185, 193, 203, 215, 230, 238, 248, 253, - 256, 260, 261, 264, 269, 286, 291, 292, 293, 294, - 310, 311, 312, 315, 318, 319, 322, 324, 325, 328, - 334, 335, 336, 337, 338, 340, 347, 351, 359, 360, - 361, 362, 363, 365, 366, 370, 371, 372, 373, 381, - 385, 401, 402, 413, 425, 430, 249, 409, 431, 0, - 285, 0, 0, 287, 234, 252, 262, 0, 420, 382, - 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, - 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, - 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 317, 0, - 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, - 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, + 0, 0, 1937, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2201, 0, 0, + 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 742, 728, 393, 0, 677, 745, + 648, 665, 755, 668, 671, 711, 627, 690, 317, 662, + 34, 652, 623, 658, 624, 650, 679, 224, 647, 730, + 693, 744, 275, 221, 629, 653, 331, 667, 176, 713, 369, 209, 284, 282, 398, 235, 227, 223, 208, 259, - 290, 329, 387, 323, 552, 279, 0, 0, 378, 302, - 0, 0, 0, 0, 0, 543, 544, 0, 0, 0, - 0, 0, 0, 0, 0, 265, 207, 175, 314, 379, - 239, 71, 0, 0, 167, 168, 169, 530, 529, 532, - 533, 534, 535, 0, 0, 198, 531, 205, 536, 537, - 538, 0, 219, 263, 226, 218, 395, 0, 0, 0, - 191, 0, 0, 0, 0, 0, 0, 523, 0, 551, - 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 520, - 521, 0, 0, 0, 0, 567, 0, 522, 0, 0, - 515, 516, 518, 517, 519, 524, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 247, 0, 303, 0, 566, - 0, 0, 427, 0, 0, 564, 0, 0, 0, 0, - 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, - 0, 0, 0, 210, 0, 356, 327, 412, 194, 237, - 349, 332, 354, 0, 0, 355, 280, 400, 344, 410, + 290, 329, 387, 323, 751, 279, 700, 0, 378, 302, + 0, 0, 0, 681, 734, 688, 724, 676, 712, 637, + 699, 746, 663, 708, 747, 265, 207, 175, 314, 379, + 239, 0, 0, 0, 167, 168, 169, 0, 2246, 2247, + 0, 0, 0, 0, 0, 198, 0, 205, 705, 741, + 660, 707, 219, 263, 226, 218, 395, 752, 733, 0, + 191, 743, 683, 710, 758, 622, 702, 0, 625, 628, + 754, 737, 656, 229, 0, 0, 0, 0, 0, 0, + 0, 680, 689, 721, 674, 0, 0, 0, 0, 0, + 0, 0, 0, 654, 0, 698, 0, 0, 0, 633, + 626, 0, 0, 0, 0, 678, 0, 0, 0, 636, + 0, 655, 722, 0, 620, 247, 630, 303, 0, 726, + 736, 675, 427, 740, 673, 672, 717, 634, 732, 666, + 274, 632, 271, 171, 187, 0, 664, 313, 352, 358, + 731, 651, 659, 210, 657, 356, 327, 412, 194, 237, + 349, 332, 354, 697, 715, 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, 202, 179, 386, 408, 199, 367, 0, 0, 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, 222, 243, 212, 316, 403, 404, 211, - 442, 190, 423, 183, 0, 422, 309, 399, 407, 298, + 442, 190, 423, 183, 934, 422, 309, 399, 407, 298, 289, 182, 405, 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, 304, 306, 0, 177, 0, 380, 416, - 443, 195, 196, 197, 0, 232, 236, 242, 244, 250, - 251, 258, 276, 320, 341, 339, 345, 0, 394, 411, + 443, 195, 196, 197, 646, 232, 236, 242, 244, 250, + 251, 258, 276, 320, 341, 339, 345, 727, 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, 257, - 376, 272, 281, 0, 0, 326, 357, 200, 414, 377, - 554, 565, 560, 561, 558, 559, 553, 557, 556, 555, - 568, 545, 546, 547, 548, 550, 0, 562, 563, 549, - 170, 184, 277, 0, 346, 240, 440, 421, 417, 0, - 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 172, 173, 185, 193, 203, 215, + 376, 272, 281, 719, 757, 326, 357, 200, 414, 377, + 641, 645, 639, 640, 691, 692, 642, 748, 749, 750, + 723, 635, 0, 643, 644, 0, 729, 738, 739, 696, + 170, 184, 277, 753, 346, 240, 440, 421, 417, 621, + 638, 216, 649, 0, 0, 661, 669, 670, 682, 684, + 685, 686, 687, 695, 703, 704, 706, 714, 716, 718, + 720, 725, 735, 756, 172, 173, 185, 193, 203, 215, 230, 238, 248, 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, 372, 373, 381, 385, 401, 402, 413, 425, 430, - 249, 409, 431, 0, 285, 0, 0, 287, 234, 252, - 262, 0, 420, 382, 189, 353, 241, 178, 206, 192, + 249, 409, 431, 0, 285, 694, 701, 287, 234, 252, + 262, 709, 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, 220, - 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 317, 0, 0, 0, 0, 0, 0, 0, - 0, 224, 0, 0, 0, 0, 275, 221, 0, 0, - 331, 0, 176, 0, 369, 209, 284, 282, 398, 235, - 227, 223, 208, 259, 290, 329, 387, 323, 0, 279, - 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 265, - 207, 175, 314, 379, 239, 0, 0, 0, 167, 168, - 169, 0, 0, 0, 0, 0, 0, 0, 0, 198, - 0, 205, 0, 0, 0, 0, 219, 263, 226, 218, - 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 975, - 974, 984, 985, 977, 978, 979, 980, 981, 982, 983, - 976, 0, 0, 986, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, - 0, 303, 0, 0, 0, 0, 427, 0, 0, 0, - 0, 0, 0, 0, 274, 0, 271, 171, 187, 0, - 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, - 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, - 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, - 424, 439, 188, 214, 321, 384, 415, 375, 300, 396, - 397, 270, 374, 245, 174, 278, 436, 186, 364, 202, + 742, 728, 393, 0, 677, 745, 648, 665, 755, 668, + 671, 711, 627, 690, 317, 662, 0, 652, 623, 658, + 624, 650, 679, 224, 647, 730, 693, 744, 275, 221, + 629, 653, 331, 667, 176, 713, 369, 209, 284, 282, + 398, 235, 227, 223, 208, 259, 290, 329, 387, 323, + 751, 279, 700, 0, 378, 302, 0, 0, 0, 681, + 734, 688, 724, 676, 712, 637, 699, 746, 663, 708, + 747, 265, 207, 175, 314, 379, 239, 0, 0, 0, + 167, 168, 169, 0, 0, 0, 0, 0, 0, 0, + 0, 198, 0, 205, 705, 741, 660, 707, 219, 263, + 226, 218, 395, 752, 733, 0, 191, 743, 683, 710, + 758, 622, 702, 0, 625, 628, 754, 737, 656, 229, + 0, 0, 0, 0, 0, 0, 0, 680, 689, 721, + 674, 0, 0, 0, 0, 0, 0, 1929, 0, 654, + 0, 698, 0, 0, 0, 633, 626, 0, 0, 0, + 0, 678, 0, 0, 0, 636, 0, 655, 722, 0, + 620, 247, 630, 303, 0, 726, 736, 675, 427, 740, + 673, 672, 717, 634, 732, 666, 274, 632, 271, 171, + 187, 0, 664, 313, 352, 358, 731, 651, 659, 210, + 657, 356, 327, 412, 194, 237, 349, 332, 354, 697, + 715, 355, 280, 400, 344, 410, 428, 429, 217, 307, + 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, + 300, 396, 397, 270, 374, 245, 174, 278, 436, 186, + 364, 202, 179, 386, 408, 199, 367, 0, 0, 441, + 181, 406, 383, 297, 267, 268, 180, 0, 348, 222, + 243, 212, 316, 403, 404, 211, 442, 190, 423, 183, + 934, 422, 309, 399, 407, 298, 289, 182, 405, 296, + 288, 273, 233, 254, 342, 283, 343, 255, 305, 304, + 306, 0, 177, 0, 380, 416, 443, 195, 196, 197, + 646, 232, 236, 242, 244, 250, 251, 258, 276, 320, + 341, 339, 345, 727, 394, 411, 419, 426, 432, 433, + 437, 434, 435, 438, 308, 257, 376, 272, 281, 719, + 757, 326, 357, 200, 414, 377, 641, 645, 639, 640, + 691, 692, 642, 748, 749, 750, 723, 635, 0, 643, + 644, 0, 729, 738, 739, 696, 170, 184, 277, 753, + 346, 240, 440, 421, 417, 621, 638, 216, 649, 0, + 0, 661, 669, 670, 682, 684, 685, 686, 687, 695, + 703, 704, 706, 714, 716, 718, 720, 725, 735, 756, + 172, 173, 185, 193, 203, 215, 230, 238, 248, 253, + 256, 260, 261, 264, 269, 286, 291, 292, 293, 294, + 310, 311, 312, 315, 318, 319, 322, 324, 325, 328, + 334, 335, 336, 337, 338, 340, 347, 351, 359, 360, + 361, 362, 363, 365, 366, 370, 371, 372, 373, 381, + 385, 401, 402, 413, 425, 430, 249, 409, 431, 0, + 285, 694, 701, 287, 234, 252, 262, 709, 420, 382, + 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, + 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, + 388, 389, 390, 392, 299, 220, 742, 728, 393, 0, + 677, 745, 648, 665, 755, 668, 671, 711, 627, 690, + 317, 662, 0, 652, 623, 658, 624, 650, 679, 224, + 647, 730, 693, 744, 275, 221, 629, 653, 331, 667, + 176, 713, 369, 209, 284, 282, 398, 235, 227, 223, + 208, 259, 290, 329, 387, 323, 751, 279, 700, 0, + 378, 302, 0, 0, 0, 681, 734, 688, 724, 676, + 712, 637, 699, 746, 663, 708, 747, 265, 207, 175, + 314, 379, 239, 0, 0, 0, 167, 168, 169, 0, + 0, 0, 0, 0, 0, 0, 0, 198, 0, 205, + 705, 741, 660, 707, 219, 263, 226, 218, 395, 752, + 733, 0, 191, 743, 683, 710, 758, 622, 702, 0, + 625, 628, 754, 737, 656, 229, 0, 0, 0, 0, + 0, 0, 0, 680, 689, 721, 674, 0, 0, 0, + 0, 0, 0, 1767, 0, 654, 0, 698, 0, 0, + 0, 633, 626, 0, 0, 0, 0, 678, 0, 0, + 0, 636, 0, 655, 722, 0, 620, 247, 630, 303, + 0, 726, 736, 675, 427, 740, 673, 672, 717, 634, + 732, 666, 274, 632, 271, 171, 187, 0, 664, 313, + 352, 358, 731, 651, 659, 210, 657, 356, 327, 412, + 194, 237, 349, 332, 354, 697, 715, 355, 280, 400, + 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, + 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, + 374, 245, 174, 278, 436, 186, 364, 202, 179, 386, + 408, 199, 367, 0, 0, 441, 181, 406, 383, 297, + 267, 268, 180, 0, 348, 222, 243, 212, 316, 403, + 404, 211, 442, 190, 423, 183, 934, 422, 309, 399, + 407, 298, 289, 182, 405, 296, 288, 273, 233, 254, + 342, 283, 343, 255, 305, 304, 306, 0, 177, 0, + 380, 416, 443, 195, 196, 197, 646, 232, 236, 242, + 244, 250, 251, 258, 276, 320, 341, 339, 345, 727, + 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, + 308, 257, 376, 272, 281, 719, 757, 326, 357, 200, + 414, 377, 641, 645, 639, 640, 691, 692, 642, 748, + 749, 750, 723, 635, 0, 643, 644, 0, 729, 738, + 739, 696, 170, 184, 277, 753, 346, 240, 440, 421, + 417, 621, 638, 216, 649, 0, 0, 661, 669, 670, + 682, 684, 685, 686, 687, 695, 703, 704, 706, 714, + 716, 718, 720, 725, 735, 756, 172, 173, 185, 193, + 203, 215, 230, 238, 248, 253, 256, 260, 261, 264, + 269, 286, 291, 292, 293, 294, 310, 311, 312, 315, + 318, 319, 322, 324, 325, 328, 334, 335, 336, 337, + 338, 340, 347, 351, 359, 360, 361, 362, 363, 365, + 366, 370, 371, 372, 373, 381, 385, 401, 402, 413, + 425, 430, 249, 409, 431, 0, 285, 694, 701, 287, + 234, 252, 262, 709, 420, 382, 189, 353, 241, 178, + 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, + 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, + 299, 220, 742, 728, 393, 0, 677, 745, 648, 665, + 755, 668, 671, 711, 627, 690, 317, 662, 0, 652, + 623, 658, 624, 650, 679, 224, 647, 730, 693, 744, + 275, 221, 629, 653, 331, 667, 176, 713, 369, 209, + 284, 282, 398, 235, 227, 223, 208, 259, 290, 329, + 387, 323, 751, 279, 700, 0, 378, 302, 0, 0, + 0, 681, 734, 688, 724, 676, 712, 637, 699, 746, + 663, 708, 747, 265, 207, 175, 314, 379, 239, 0, + 0, 0, 167, 168, 169, 0, 0, 0, 0, 0, + 0, 0, 0, 198, 0, 205, 705, 741, 660, 707, + 219, 263, 226, 218, 395, 752, 733, 0, 191, 743, + 683, 710, 758, 622, 702, 0, 625, 628, 754, 737, + 656, 229, 0, 0, 0, 0, 0, 0, 0, 680, + 689, 721, 674, 0, 0, 0, 0, 0, 0, 1476, + 0, 654, 0, 698, 0, 0, 0, 633, 626, 0, + 0, 0, 0, 678, 0, 0, 0, 636, 0, 655, + 722, 0, 620, 247, 630, 303, 0, 726, 736, 675, + 427, 740, 673, 672, 717, 634, 732, 666, 274, 632, + 271, 171, 187, 0, 664, 313, 352, 358, 731, 651, + 659, 210, 657, 356, 327, 412, 194, 237, 349, 332, + 354, 697, 715, 355, 280, 400, 344, 410, 428, 429, + 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, + 415, 375, 300, 396, 397, 270, 374, 245, 174, 278, + 436, 186, 364, 202, 179, 386, 408, 199, 367, 0, + 0, 441, 181, 406, 383, 297, 267, 268, 180, 0, + 348, 222, 243, 212, 316, 403, 404, 211, 442, 190, + 423, 183, 934, 422, 309, 399, 407, 298, 289, 182, + 405, 296, 288, 273, 233, 254, 342, 283, 343, 255, + 305, 304, 306, 0, 177, 0, 380, 416, 443, 195, + 196, 197, 646, 232, 236, 242, 244, 250, 251, 258, + 276, 320, 341, 339, 345, 727, 394, 411, 419, 426, + 432, 433, 437, 434, 435, 438, 308, 257, 376, 272, + 281, 719, 757, 326, 357, 200, 414, 377, 641, 645, + 639, 640, 691, 692, 642, 748, 749, 750, 723, 635, + 0, 643, 644, 0, 729, 738, 739, 696, 170, 184, + 277, 753, 346, 240, 440, 421, 417, 621, 638, 216, + 649, 0, 0, 661, 669, 670, 682, 684, 685, 686, + 687, 695, 703, 704, 706, 714, 716, 718, 720, 725, + 735, 756, 172, 173, 185, 193, 203, 215, 230, 238, + 248, 253, 256, 260, 261, 264, 269, 286, 291, 292, + 293, 294, 310, 311, 312, 315, 318, 319, 322, 324, + 325, 328, 334, 335, 336, 337, 338, 340, 347, 351, + 359, 360, 361, 362, 363, 365, 366, 370, 371, 372, + 373, 381, 385, 401, 402, 413, 425, 430, 249, 409, + 431, 0, 285, 694, 701, 287, 234, 252, 262, 709, + 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, + 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, + 201, 368, 388, 389, 390, 392, 299, 220, 742, 728, + 393, 0, 677, 745, 648, 665, 755, 668, 671, 711, + 627, 690, 317, 662, 0, 652, 623, 658, 624, 650, + 679, 224, 647, 730, 693, 744, 275, 221, 629, 653, + 331, 667, 176, 713, 369, 209, 284, 282, 398, 235, + 227, 223, 208, 259, 290, 329, 387, 323, 751, 279, + 700, 0, 378, 302, 0, 0, 0, 681, 734, 688, + 724, 676, 712, 637, 699, 746, 663, 708, 747, 265, + 207, 175, 314, 379, 239, 71, 0, 0, 167, 168, + 169, 0, 0, 0, 0, 0, 0, 0, 0, 198, + 0, 205, 705, 741, 660, 707, 219, 263, 226, 218, + 395, 752, 733, 0, 191, 743, 683, 710, 758, 622, + 702, 0, 625, 628, 754, 737, 656, 229, 0, 0, + 0, 0, 0, 0, 0, 680, 689, 721, 674, 0, + 0, 0, 0, 0, 0, 0, 0, 654, 0, 698, + 0, 0, 0, 633, 626, 0, 0, 0, 0, 678, + 0, 0, 0, 636, 0, 655, 722, 0, 620, 247, + 630, 303, 0, 726, 736, 675, 427, 740, 673, 672, + 717, 634, 732, 666, 274, 632, 271, 171, 187, 0, + 664, 313, 352, 358, 731, 651, 659, 210, 657, 356, + 327, 412, 194, 237, 349, 332, 354, 697, 715, 355, + 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, + 424, 439, 188, 214, 321, 384, 415, 375, 300, 396, + 397, 270, 374, 245, 174, 278, 436, 186, 364, 202, 179, 386, 408, 199, 367, 0, 0, 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, 222, 243, 212, - 316, 403, 404, 211, 442, 190, 423, 183, 0, 422, + 316, 403, 404, 211, 442, 190, 423, 183, 934, 422, 309, 399, 407, 298, 289, 182, 405, 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, 304, 306, 0, - 177, 0, 380, 416, 443, 195, 196, 197, 0, 232, + 177, 0, 380, 416, 443, 195, 196, 197, 646, 232, 236, 242, 244, 250, 251, 258, 276, 320, 341, 339, - 345, 0, 394, 411, 419, 426, 432, 433, 437, 434, - 435, 438, 308, 257, 376, 272, 281, 0, 0, 326, - 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 170, 184, 277, 0, 346, 240, - 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, + 345, 727, 394, 411, 419, 426, 432, 433, 437, 434, + 435, 438, 308, 257, 376, 272, 281, 719, 757, 326, + 357, 200, 414, 377, 641, 645, 639, 640, 691, 692, + 642, 748, 749, 750, 723, 635, 0, 643, 644, 0, + 729, 738, 739, 696, 170, 184, 277, 753, 346, 240, + 440, 421, 417, 621, 638, 216, 649, 0, 0, 661, + 669, 670, 682, 684, 685, 686, 687, 695, 703, 704, + 706, 714, 716, 718, 720, 725, 735, 756, 172, 173, 185, 193, 203, 215, 230, 238, 248, 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, 372, 373, 381, 385, 401, - 402, 413, 425, 430, 249, 409, 431, 0, 285, 0, - 0, 287, 234, 252, 262, 0, 420, 382, 189, 353, + 402, 413, 425, 430, 249, 409, 431, 0, 285, 694, + 701, 287, 234, 252, 262, 709, 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, - 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, - 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, - 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, + 390, 392, 299, 220, 742, 728, 393, 0, 677, 745, + 648, 665, 755, 668, 671, 711, 627, 690, 317, 662, + 0, 652, 623, 658, 624, 650, 679, 224, 647, 730, + 693, 744, 275, 221, 629, 653, 331, 667, 176, 713, + 369, 209, 284, 282, 398, 235, 227, 223, 208, 259, + 290, 329, 387, 323, 751, 279, 700, 0, 378, 302, + 0, 0, 0, 681, 734, 688, 724, 676, 712, 637, + 699, 746, 663, 708, 747, 265, 207, 175, 314, 379, + 239, 0, 0, 0, 167, 168, 169, 0, 0, 0, + 0, 0, 0, 0, 0, 198, 0, 205, 705, 741, + 660, 707, 219, 263, 226, 218, 395, 752, 733, 0, + 191, 743, 683, 710, 758, 622, 702, 0, 625, 628, + 754, 737, 656, 229, 0, 0, 0, 0, 0, 0, + 0, 680, 689, 721, 674, 0, 0, 0, 0, 0, + 0, 0, 0, 654, 0, 698, 0, 0, 0, 633, + 626, 0, 0, 0, 0, 678, 0, 0, 0, 636, + 0, 655, 722, 0, 620, 247, 630, 303, 0, 726, + 736, 675, 427, 740, 673, 672, 717, 634, 732, 666, + 274, 632, 271, 171, 187, 0, 664, 313, 352, 358, + 731, 651, 659, 210, 657, 356, 327, 412, 194, 237, + 349, 332, 354, 697, 715, 355, 280, 400, 344, 410, + 428, 429, 217, 307, 418, 391, 424, 439, 188, 214, + 321, 384, 415, 375, 300, 396, 397, 270, 374, 245, + 174, 278, 436, 186, 364, 202, 179, 386, 408, 199, + 367, 0, 0, 441, 181, 406, 383, 297, 267, 268, + 180, 0, 348, 222, 243, 212, 316, 403, 404, 211, + 442, 190, 423, 183, 934, 422, 309, 399, 407, 298, + 289, 182, 405, 296, 288, 273, 233, 254, 342, 283, + 343, 255, 305, 304, 306, 0, 177, 0, 380, 416, + 443, 195, 196, 197, 646, 232, 236, 242, 244, 250, + 251, 258, 276, 320, 341, 339, 345, 727, 394, 411, + 419, 426, 432, 433, 437, 434, 435, 438, 308, 257, + 376, 272, 281, 719, 757, 326, 357, 200, 414, 377, + 641, 645, 639, 640, 691, 692, 642, 748, 749, 750, + 723, 635, 0, 643, 644, 0, 729, 738, 739, 696, + 170, 184, 277, 753, 346, 240, 440, 421, 417, 621, + 638, 216, 649, 0, 0, 661, 669, 670, 682, 684, + 685, 686, 687, 695, 703, 704, 706, 714, 716, 718, + 720, 725, 735, 756, 172, 173, 185, 193, 203, 215, + 230, 238, 248, 253, 256, 260, 261, 264, 269, 286, + 291, 292, 293, 294, 310, 311, 312, 315, 318, 319, + 322, 324, 325, 328, 334, 335, 336, 337, 338, 340, + 347, 351, 359, 360, 361, 362, 363, 365, 366, 370, + 371, 372, 373, 381, 385, 401, 402, 413, 425, 430, + 249, 409, 431, 0, 285, 694, 701, 287, 234, 252, + 262, 709, 420, 382, 189, 353, 241, 178, 206, 192, + 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, + 204, 350, 201, 368, 388, 389, 390, 392, 299, 220, + 742, 728, 393, 0, 677, 745, 648, 665, 755, 668, + 671, 711, 627, 690, 317, 662, 0, 652, 623, 658, + 624, 650, 679, 224, 647, 730, 693, 744, 275, 221, + 629, 653, 331, 667, 176, 713, 369, 209, 284, 282, + 398, 235, 227, 223, 208, 259, 290, 329, 387, 323, + 751, 279, 700, 0, 378, 302, 0, 0, 0, 681, + 734, 688, 724, 676, 712, 637, 699, 746, 663, 708, + 747, 265, 207, 175, 314, 379, 239, 0, 0, 0, + 167, 168, 169, 0, 0, 0, 0, 0, 0, 0, + 0, 198, 0, 205, 705, 741, 660, 707, 219, 263, + 226, 218, 395, 752, 733, 0, 759, 743, 683, 710, + 758, 622, 702, 0, 625, 628, 754, 737, 656, 229, + 0, 0, 0, 0, 0, 0, 0, 680, 689, 721, + 674, 0, 0, 0, 0, 0, 0, 0, 0, 654, + 0, 698, 0, 0, 0, 633, 626, 0, 0, 0, + 0, 678, 0, 0, 0, 636, 0, 655, 722, 0, + 620, 247, 630, 303, 0, 726, 736, 675, 427, 740, + 673, 672, 717, 634, 732, 666, 274, 632, 271, 171, + 187, 0, 664, 313, 352, 358, 731, 651, 659, 210, + 657, 356, 327, 412, 194, 237, 349, 332, 354, 697, + 715, 355, 280, 400, 344, 410, 428, 429, 217, 307, + 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, + 300, 396, 397, 270, 374, 245, 174, 278, 436, 186, + 364, 202, 179, 386, 408, 199, 367, 0, 0, 441, + 181, 406, 383, 297, 267, 268, 180, 0, 348, 222, + 243, 212, 316, 403, 404, 211, 442, 190, 423, 183, + 631, 422, 309, 399, 407, 298, 289, 182, 405, 296, + 288, 273, 233, 254, 342, 283, 343, 255, 305, 304, + 306, 0, 177, 0, 380, 416, 443, 195, 196, 197, + 646, 232, 236, 242, 244, 250, 251, 258, 276, 320, + 341, 339, 345, 727, 394, 411, 419, 426, 432, 433, + 437, 434, 435, 438, 619, 613, 612, 272, 281, 719, + 757, 326, 357, 200, 414, 377, 641, 645, 639, 640, + 691, 692, 642, 748, 749, 750, 723, 635, 0, 643, + 644, 0, 729, 738, 739, 696, 170, 184, 277, 753, + 346, 240, 440, 421, 417, 621, 638, 216, 649, 0, + 0, 661, 669, 670, 682, 684, 685, 686, 687, 695, + 703, 704, 706, 714, 716, 718, 720, 725, 735, 756, + 172, 173, 185, 193, 203, 215, 230, 238, 248, 253, + 256, 260, 261, 264, 269, 286, 291, 292, 293, 294, + 310, 311, 312, 315, 318, 319, 322, 324, 325, 328, + 334, 335, 336, 337, 338, 340, 347, 351, 359, 360, + 361, 362, 363, 365, 366, 370, 371, 372, 373, 381, + 385, 401, 402, 413, 425, 430, 249, 409, 431, 0, + 285, 694, 701, 287, 234, 252, 262, 709, 420, 382, + 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, + 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, + 388, 389, 390, 392, 299, 220, 742, 728, 393, 0, + 677, 745, 648, 665, 755, 668, 671, 711, 627, 690, + 317, 662, 0, 652, 623, 658, 624, 650, 679, 224, + 647, 730, 693, 744, 275, 221, 629, 653, 331, 667, + 176, 713, 369, 209, 284, 282, 398, 235, 227, 223, + 208, 259, 290, 329, 387, 323, 751, 279, 700, 0, + 378, 302, 0, 0, 0, 681, 734, 688, 724, 676, + 712, 637, 699, 746, 663, 708, 747, 265, 207, 175, + 314, 379, 239, 0, 0, 0, 167, 168, 169, 0, + 0, 0, 0, 0, 0, 0, 0, 198, 0, 205, + 705, 741, 660, 707, 219, 263, 226, 218, 395, 752, + 733, 0, 759, 743, 683, 710, 758, 622, 702, 0, + 625, 628, 754, 737, 656, 229, 0, 0, 0, 0, + 0, 0, 0, 680, 689, 721, 674, 0, 0, 0, + 0, 0, 0, 0, 0, 654, 0, 698, 0, 0, + 0, 633, 626, 0, 0, 0, 0, 678, 0, 0, + 0, 636, 0, 655, 722, 0, 620, 247, 630, 303, + 0, 726, 736, 675, 427, 740, 673, 672, 717, 634, + 732, 666, 274, 632, 271, 171, 187, 0, 664, 313, + 352, 358, 731, 651, 659, 210, 657, 356, 327, 412, + 194, 237, 349, 332, 354, 697, 715, 355, 280, 400, + 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, + 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, + 374, 245, 174, 278, 436, 186, 364, 202, 179, 386, + 1102, 199, 367, 0, 0, 441, 181, 406, 383, 297, + 267, 268, 180, 0, 348, 222, 243, 212, 316, 403, + 404, 211, 442, 190, 423, 183, 631, 422, 309, 399, + 407, 298, 289, 182, 405, 296, 288, 273, 233, 254, + 342, 283, 343, 255, 305, 304, 306, 0, 177, 0, + 380, 416, 443, 195, 196, 197, 646, 232, 236, 242, + 244, 250, 251, 258, 276, 320, 341, 339, 345, 727, + 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, + 619, 613, 612, 272, 281, 719, 757, 326, 357, 200, + 414, 377, 641, 645, 639, 640, 691, 692, 642, 748, + 749, 750, 723, 635, 0, 643, 644, 0, 729, 738, + 739, 696, 170, 184, 277, 753, 346, 240, 440, 421, + 417, 621, 638, 216, 649, 0, 0, 661, 669, 670, + 682, 684, 685, 686, 687, 695, 703, 704, 706, 714, + 716, 718, 720, 725, 735, 756, 172, 173, 185, 193, + 203, 215, 230, 238, 248, 253, 256, 260, 261, 264, + 269, 286, 291, 292, 293, 294, 310, 311, 312, 315, + 318, 319, 322, 324, 325, 328, 334, 335, 336, 337, + 338, 340, 347, 351, 359, 360, 361, 362, 363, 365, + 366, 370, 371, 372, 373, 381, 385, 401, 402, 413, + 425, 430, 249, 409, 431, 0, 285, 694, 701, 287, + 234, 252, 262, 709, 420, 382, 189, 353, 241, 178, + 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, + 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, + 299, 220, 742, 728, 393, 0, 677, 745, 648, 665, + 755, 668, 671, 711, 627, 690, 317, 662, 0, 652, + 623, 658, 624, 650, 679, 224, 647, 730, 693, 744, + 275, 221, 629, 653, 331, 667, 176, 713, 369, 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, 329, - 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 265, 207, 175, 314, 379, 239, 0, + 387, 323, 751, 279, 700, 0, 378, 302, 0, 0, + 0, 681, 734, 688, 724, 676, 712, 637, 699, 746, + 663, 708, 747, 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, 168, 169, 0, 0, 0, 0, 0, - 0, 0, 0, 198, 0, 205, 0, 0, 0, 0, - 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, - 804, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 247, 0, 303, 0, 0, 0, 803, - 427, 0, 0, 0, 0, 0, 800, 801, 274, 766, - 271, 171, 187, 794, 798, 313, 352, 358, 0, 0, - 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, - 354, 0, 0, 355, 280, 400, 344, 410, 428, 429, + 0, 0, 0, 198, 0, 205, 705, 741, 660, 707, + 219, 263, 226, 218, 395, 752, 733, 0, 759, 743, + 683, 710, 758, 622, 702, 0, 625, 628, 754, 737, + 656, 229, 0, 0, 0, 0, 0, 0, 0, 680, + 689, 721, 674, 0, 0, 0, 0, 0, 0, 0, + 0, 654, 0, 698, 0, 0, 0, 633, 626, 0, + 0, 0, 0, 678, 0, 0, 0, 636, 0, 655, + 722, 0, 620, 247, 630, 303, 0, 726, 736, 675, + 427, 740, 673, 672, 717, 634, 732, 666, 274, 632, + 271, 171, 187, 0, 664, 313, 352, 358, 731, 651, + 659, 210, 657, 356, 327, 412, 194, 237, 349, 332, + 354, 697, 715, 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, 278, - 436, 186, 364, 202, 179, 386, 408, 199, 367, 0, + 436, 186, 364, 202, 179, 386, 610, 199, 367, 0, 0, 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, 222, 243, 212, 316, 403, 404, 211, 442, 190, - 423, 183, 0, 422, 309, 399, 407, 298, 289, 182, + 423, 183, 631, 422, 309, 399, 407, 298, 289, 182, 405, 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, 304, 306, 0, 177, 0, 380, 416, 443, 195, - 196, 197, 0, 232, 236, 242, 244, 250, 251, 258, - 276, 320, 341, 339, 345, 0, 394, 411, 419, 426, - 432, 433, 437, 434, 435, 438, 308, 257, 376, 272, - 281, 0, 0, 326, 357, 200, 414, 377, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 170, 184, - 277, 0, 346, 240, 440, 421, 417, 0, 0, 216, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 172, 173, 185, 193, 203, 215, 230, 238, + 196, 197, 646, 232, 236, 242, 244, 250, 251, 258, + 276, 320, 341, 339, 345, 727, 394, 411, 419, 426, + 432, 433, 437, 434, 435, 438, 619, 613, 612, 272, + 281, 719, 757, 326, 357, 200, 414, 377, 641, 645, + 639, 640, 691, 692, 642, 748, 749, 750, 723, 635, + 0, 643, 644, 0, 729, 738, 739, 696, 170, 184, + 277, 753, 346, 240, 440, 421, 417, 621, 638, 216, + 649, 0, 0, 661, 669, 670, 682, 684, 685, 686, + 687, 695, 703, 704, 706, 714, 716, 718, 720, 725, + 735, 756, 172, 173, 185, 193, 203, 215, 230, 238, 248, 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, 372, 373, 381, 385, 401, 402, 413, 425, 430, 249, 409, - 431, 0, 285, 0, 0, 287, 234, 252, 262, 0, + 431, 0, 285, 694, 701, 287, 234, 252, 262, 709, 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 317, 0, 0, 0, 1078, 0, 0, 0, 0, 224, - 0, 0, 0, 0, 275, 221, 0, 0, 331, 0, + 317, 0, 0, 1404, 0, 510, 0, 0, 0, 224, + 509, 0, 0, 0, 275, 221, 0, 1405, 331, 0, 176, 0, 369, 209, 284, 282, 398, 235, 227, 223, - 208, 259, 290, 329, 387, 323, 0, 279, 0, 0, - 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, + 208, 259, 290, 329, 387, 323, 553, 279, 0, 0, + 378, 302, 0, 0, 0, 0, 0, 544, 545, 0, 0, 0, 0, 0, 0, 0, 0, 265, 207, 175, - 314, 379, 239, 0, 0, 0, 167, 168, 169, 0, - 1080, 0, 0, 0, 0, 0, 0, 198, 0, 205, - 0, 0, 0, 0, 219, 263, 226, 218, 395, 0, - 0, 0, 191, 0, 0, 964, 965, 963, 0, 0, - 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, - 0, 0, 0, 966, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 314, 379, 239, 71, 0, 0, 167, 168, 169, 531, + 530, 533, 534, 535, 536, 0, 0, 198, 532, 205, + 537, 538, 539, 0, 219, 263, 226, 218, 395, 0, + 0, 0, 191, 0, 0, 0, 0, 0, 507, 524, + 0, 552, 0, 0, 0, 229, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 521, 522, 600, 0, 0, 0, 568, 0, 523, + 0, 0, 516, 517, 519, 518, 520, 525, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, 303, - 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, + 0, 567, 0, 0, 427, 0, 0, 565, 0, 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, 280, 400, @@ -2690,9 +2122,9 @@ var yyAct = [...]int{ 244, 250, 251, 258, 276, 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, 0, 0, 326, 357, 200, - 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 170, 184, 277, 0, 346, 240, 440, 421, + 414, 377, 555, 566, 561, 562, 559, 560, 554, 558, + 557, 556, 569, 546, 547, 548, 549, 551, 0, 563, + 564, 550, 170, 184, 277, 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, 185, 193, @@ -2705,46 +2137,283 @@ var yyAct = [...]int{ 234, 252, 262, 0, 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, - 299, 220, 35, 393, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 317, 0, 0, 0, 0, - 0, 0, 0, 0, 224, 0, 0, 0, 0, 275, - 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, - 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, - 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 265, 207, 175, 314, 379, 239, 71, 0, - 586, 167, 168, 169, 0, 0, 0, 0, 0, 0, - 0, 0, 198, 0, 205, 0, 0, 0, 0, 219, - 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 317, 0, 0, 0, 0, 510, + 0, 0, 0, 224, 509, 0, 0, 0, 275, 221, + 0, 0, 331, 0, 176, 0, 369, 209, 284, 282, + 398, 235, 227, 223, 208, 259, 290, 329, 387, 323, + 553, 279, 0, 0, 378, 302, 0, 0, 0, 0, + 0, 544, 545, 0, 0, 0, 0, 0, 0, 1515, + 0, 265, 207, 175, 314, 379, 239, 71, 0, 0, + 167, 168, 169, 531, 530, 533, 534, 535, 536, 0, + 0, 198, 532, 205, 537, 538, 539, 1516, 219, 263, + 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, + 0, 0, 507, 524, 0, 552, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 521, 522, 0, 0, 0, + 0, 568, 0, 523, 0, 0, 516, 517, 519, 518, + 520, 525, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 247, 0, 303, 0, 567, 0, 0, 427, 0, + 0, 565, 0, 0, 0, 0, 274, 0, 271, 171, + 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, + 0, 356, 327, 412, 194, 237, 349, 332, 354, 0, + 0, 355, 280, 400, 344, 410, 428, 429, 217, 307, + 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, + 300, 396, 397, 270, 374, 245, 174, 278, 436, 186, + 364, 202, 179, 386, 408, 199, 367, 0, 0, 441, + 181, 406, 383, 297, 267, 268, 180, 0, 348, 222, + 243, 212, 316, 403, 404, 211, 442, 190, 423, 183, + 0, 422, 309, 399, 407, 298, 289, 182, 405, 296, + 288, 273, 233, 254, 342, 283, 343, 255, 305, 304, + 306, 0, 177, 0, 380, 416, 443, 195, 196, 197, + 0, 232, 236, 242, 244, 250, 251, 258, 276, 320, + 341, 339, 345, 0, 394, 411, 419, 426, 432, 433, + 437, 434, 435, 438, 308, 257, 376, 272, 281, 0, + 0, 326, 357, 200, 414, 377, 555, 566, 561, 562, + 559, 560, 554, 558, 557, 556, 569, 546, 547, 548, + 549, 551, 0, 563, 564, 550, 170, 184, 277, 0, + 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 247, 0, 303, 0, 0, 0, 0, 427, - 0, 0, 0, 0, 0, 0, 0, 274, 0, 271, - 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, - 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, - 0, 0, 355, 280, 400, 344, 410, 428, 429, 217, - 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, - 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, - 186, 364, 202, 179, 386, 408, 199, 367, 0, 0, - 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, - 222, 243, 212, 316, 403, 404, 211, 442, 190, 423, - 183, 0, 422, 309, 399, 407, 298, 289, 182, 405, - 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, - 304, 306, 0, 177, 0, 380, 416, 443, 195, 196, - 197, 0, 232, 236, 242, 244, 250, 251, 258, 276, - 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, - 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, - 0, 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 170, 184, 277, - 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, + 172, 173, 185, 193, 203, 215, 230, 238, 248, 253, + 256, 260, 261, 264, 269, 286, 291, 292, 293, 294, + 310, 311, 312, 315, 318, 319, 322, 324, 325, 328, + 334, 335, 336, 337, 338, 340, 347, 351, 359, 360, + 361, 362, 363, 365, 366, 370, 371, 372, 373, 381, + 385, 401, 402, 413, 425, 430, 249, 409, 431, 0, + 285, 0, 0, 287, 234, 252, 262, 0, 420, 382, + 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, + 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, + 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 317, 0, + 0, 0, 0, 510, 0, 0, 0, 224, 509, 0, + 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, + 369, 209, 284, 282, 398, 235, 227, 223, 208, 259, + 290, 329, 387, 323, 553, 279, 0, 0, 378, 302, + 0, 0, 0, 0, 0, 544, 545, 0, 0, 0, + 0, 0, 0, 0, 0, 265, 207, 175, 314, 379, + 239, 71, 0, 587, 167, 168, 169, 531, 530, 533, + 534, 535, 536, 0, 0, 198, 532, 205, 537, 538, + 539, 0, 219, 263, 226, 218, 395, 0, 0, 0, + 191, 0, 0, 0, 0, 0, 507, 524, 0, 552, + 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 521, + 522, 0, 0, 0, 0, 568, 0, 523, 0, 0, + 516, 517, 519, 518, 520, 525, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 247, 0, 303, 0, 567, + 0, 0, 427, 0, 0, 565, 0, 0, 0, 0, + 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, + 0, 0, 0, 210, 0, 356, 327, 412, 194, 237, + 349, 332, 354, 0, 0, 355, 280, 400, 344, 410, + 428, 429, 217, 307, 418, 391, 424, 439, 188, 214, + 321, 384, 415, 375, 300, 396, 397, 270, 374, 245, + 174, 278, 436, 186, 364, 202, 179, 386, 408, 199, + 367, 0, 0, 441, 181, 406, 383, 297, 267, 268, + 180, 0, 348, 222, 243, 212, 316, 403, 404, 211, + 442, 190, 423, 183, 0, 422, 309, 399, 407, 298, + 289, 182, 405, 296, 288, 273, 233, 254, 342, 283, + 343, 255, 305, 304, 306, 0, 177, 0, 380, 416, + 443, 195, 196, 197, 0, 232, 236, 242, 244, 250, + 251, 258, 276, 320, 341, 339, 345, 0, 394, 411, + 419, 426, 432, 433, 437, 434, 435, 438, 308, 257, + 376, 272, 281, 0, 0, 326, 357, 200, 414, 377, + 555, 566, 561, 562, 559, 560, 554, 558, 557, 556, + 569, 546, 547, 548, 549, 551, 0, 563, 564, 550, + 170, 184, 277, 0, 346, 240, 440, 421, 417, 0, + 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 172, 173, 185, 193, 203, 215, + 230, 238, 248, 253, 256, 260, 261, 264, 269, 286, + 291, 292, 293, 294, 310, 311, 312, 315, 318, 319, + 322, 324, 325, 328, 334, 335, 336, 337, 338, 340, + 347, 351, 359, 360, 361, 362, 363, 365, 366, 370, + 371, 372, 373, 381, 385, 401, 402, 413, 425, 430, + 249, 409, 431, 0, 285, 0, 0, 287, 234, 252, + 262, 0, 420, 382, 189, 353, 241, 178, 206, 192, + 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, + 204, 350, 201, 368, 388, 389, 390, 392, 299, 220, + 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 317, 0, 0, 0, 0, 510, 0, 0, + 0, 224, 509, 0, 0, 0, 275, 221, 0, 0, + 331, 0, 176, 0, 369, 209, 284, 282, 398, 235, + 227, 223, 208, 259, 290, 329, 387, 323, 553, 279, + 0, 0, 378, 302, 0, 0, 0, 0, 0, 544, + 545, 0, 0, 0, 0, 0, 0, 0, 0, 265, + 207, 175, 314, 379, 239, 71, 0, 0, 167, 168, + 169, 531, 530, 533, 534, 535, 536, 0, 0, 198, + 532, 205, 537, 538, 539, 0, 219, 263, 226, 218, + 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, + 507, 524, 0, 552, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 172, 173, 185, 193, 203, 215, 230, 238, 248, - 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, + 0, 0, 0, 521, 522, 600, 0, 0, 0, 568, + 0, 523, 0, 0, 516, 517, 519, 518, 520, 525, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, + 0, 303, 0, 567, 0, 0, 427, 0, 0, 565, + 0, 0, 0, 0, 274, 0, 271, 171, 187, 0, + 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, + 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, + 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, + 424, 439, 188, 214, 321, 384, 415, 375, 300, 396, + 397, 270, 374, 245, 174, 278, 436, 186, 364, 202, + 179, 386, 408, 199, 367, 0, 0, 441, 181, 406, + 383, 297, 267, 268, 180, 0, 348, 222, 243, 212, + 316, 403, 404, 211, 442, 190, 423, 183, 0, 422, + 309, 399, 407, 298, 289, 182, 405, 296, 288, 273, + 233, 254, 342, 283, 343, 255, 305, 304, 306, 0, + 177, 0, 380, 416, 443, 195, 196, 197, 0, 232, + 236, 242, 244, 250, 251, 258, 276, 320, 341, 339, + 345, 0, 394, 411, 419, 426, 432, 433, 437, 434, + 435, 438, 308, 257, 376, 272, 281, 0, 0, 326, + 357, 200, 414, 377, 555, 566, 561, 562, 559, 560, + 554, 558, 557, 556, 569, 546, 547, 548, 549, 551, + 0, 563, 564, 550, 170, 184, 277, 0, 346, 240, + 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, + 185, 193, 203, 215, 230, 238, 248, 253, 256, 260, + 261, 264, 269, 286, 291, 292, 293, 294, 310, 311, + 312, 315, 318, 319, 322, 324, 325, 328, 334, 335, + 336, 337, 338, 340, 347, 351, 359, 360, 361, 362, + 363, 365, 366, 370, 371, 372, 373, 381, 385, 401, + 402, 413, 425, 430, 249, 409, 431, 0, 285, 0, + 0, 287, 234, 252, 262, 0, 420, 382, 189, 353, + 241, 178, 206, 192, 213, 228, 231, 266, 295, 301, + 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, + 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, + 0, 510, 0, 0, 0, 224, 509, 0, 0, 0, + 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, + 284, 282, 398, 235, 227, 223, 208, 259, 290, 329, + 387, 323, 553, 279, 0, 0, 378, 302, 0, 0, + 0, 0, 0, 544, 545, 0, 0, 0, 0, 0, + 0, 0, 0, 265, 207, 175, 314, 379, 239, 71, + 0, 0, 167, 168, 169, 531, 1422, 533, 534, 535, + 536, 0, 0, 198, 532, 205, 537, 538, 539, 0, + 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, + 0, 0, 0, 0, 507, 524, 0, 552, 0, 0, + 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 521, 522, 600, + 0, 0, 0, 568, 0, 523, 0, 0, 516, 517, + 519, 518, 520, 525, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 247, 0, 303, 0, 567, 0, 0, + 427, 0, 0, 565, 0, 0, 0, 0, 274, 0, + 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, + 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, + 354, 0, 0, 355, 280, 400, 344, 410, 428, 429, + 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, + 415, 375, 300, 396, 397, 270, 374, 245, 174, 278, + 436, 186, 364, 202, 179, 386, 408, 199, 367, 0, + 0, 441, 181, 406, 383, 297, 267, 268, 180, 0, + 348, 222, 243, 212, 316, 403, 404, 211, 442, 190, + 423, 183, 0, 422, 309, 399, 407, 298, 289, 182, + 405, 296, 288, 273, 233, 254, 342, 283, 343, 255, + 305, 304, 306, 0, 177, 0, 380, 416, 443, 195, + 196, 197, 0, 232, 236, 242, 244, 250, 251, 258, + 276, 320, 341, 339, 345, 0, 394, 411, 419, 426, + 432, 433, 437, 434, 435, 438, 308, 257, 376, 272, + 281, 0, 0, 326, 357, 200, 414, 377, 555, 566, + 561, 562, 559, 560, 554, 558, 557, 556, 569, 546, + 547, 548, 549, 551, 0, 563, 564, 550, 170, 184, + 277, 0, 346, 240, 440, 421, 417, 0, 0, 216, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 172, 173, 185, 193, 203, 215, 230, 238, + 248, 253, 256, 260, 261, 264, 269, 286, 291, 292, + 293, 294, 310, 311, 312, 315, 318, 319, 322, 324, + 325, 328, 334, 335, 336, 337, 338, 340, 347, 351, + 359, 360, 361, 362, 363, 365, 366, 370, 371, 372, + 373, 381, 385, 401, 402, 413, 425, 430, 249, 409, + 431, 0, 285, 0, 0, 287, 234, 252, 262, 0, + 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, + 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, + 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 317, 0, 0, 0, 0, 510, 0, 0, 0, 224, + 509, 0, 0, 0, 275, 221, 0, 0, 331, 0, + 176, 0, 369, 209, 284, 282, 398, 235, 227, 223, + 208, 259, 290, 329, 387, 323, 553, 279, 0, 0, + 378, 302, 0, 0, 0, 0, 0, 544, 545, 0, + 0, 0, 0, 0, 0, 0, 0, 265, 207, 175, + 314, 379, 239, 71, 0, 0, 167, 168, 169, 531, + 1419, 533, 534, 535, 536, 0, 0, 198, 532, 205, + 537, 538, 539, 0, 219, 263, 226, 218, 395, 0, + 0, 0, 191, 0, 0, 0, 0, 0, 507, 524, + 0, 552, 0, 0, 0, 229, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 521, 522, 600, 0, 0, 0, 568, 0, 523, + 0, 0, 516, 517, 519, 518, 520, 525, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 247, 0, 303, + 0, 567, 0, 0, 427, 0, 0, 565, 0, 0, + 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, + 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, + 194, 237, 349, 332, 354, 0, 0, 355, 280, 400, + 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, + 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, + 374, 245, 174, 278, 436, 186, 364, 202, 179, 386, + 408, 199, 367, 0, 0, 441, 181, 406, 383, 297, + 267, 268, 180, 0, 348, 222, 243, 212, 316, 403, + 404, 211, 442, 190, 423, 183, 0, 422, 309, 399, + 407, 298, 289, 182, 405, 296, 288, 273, 233, 254, + 342, 283, 343, 255, 305, 304, 306, 0, 177, 0, + 380, 416, 443, 195, 196, 197, 0, 232, 236, 242, + 244, 250, 251, 258, 276, 320, 341, 339, 345, 0, + 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, + 308, 257, 376, 272, 281, 0, 0, 326, 357, 200, + 414, 377, 555, 566, 561, 562, 559, 560, 554, 558, + 557, 556, 569, 546, 547, 548, 549, 551, 0, 563, + 564, 550, 170, 184, 277, 0, 346, 240, 440, 421, + 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 172, 173, 185, 193, + 203, 215, 230, 238, 248, 253, 256, 260, 261, 264, + 269, 286, 291, 292, 293, 294, 310, 311, 312, 315, + 318, 319, 322, 324, 325, 328, 334, 335, 336, 337, + 338, 340, 347, 351, 359, 360, 361, 362, 363, 365, + 366, 370, 371, 372, 373, 381, 385, 401, 402, 413, + 425, 430, 249, 409, 431, 0, 285, 0, 0, 287, + 234, 252, 262, 0, 420, 382, 189, 353, 241, 178, + 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, + 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, + 299, 220, 580, 393, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 317, 0, 0, 0, 0, + 510, 0, 0, 0, 224, 509, 0, 0, 0, 275, + 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, + 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, + 323, 553, 279, 0, 0, 378, 302, 0, 0, 0, + 0, 0, 544, 545, 0, 0, 0, 0, 0, 0, + 0, 0, 265, 207, 175, 314, 379, 239, 71, 0, + 0, 167, 168, 169, 531, 530, 533, 534, 535, 536, + 0, 0, 198, 532, 205, 537, 538, 539, 0, 219, + 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, + 0, 0, 0, 507, 524, 0, 552, 0, 0, 0, + 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 521, 522, 0, 0, + 0, 0, 568, 0, 523, 0, 0, 516, 517, 519, + 518, 520, 525, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 247, 0, 303, 0, 567, 0, 0, 427, + 0, 0, 565, 0, 0, 0, 0, 274, 0, 271, + 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, + 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, + 0, 0, 355, 280, 400, 344, 410, 428, 429, 217, + 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, + 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, + 186, 364, 202, 179, 386, 408, 199, 367, 0, 0, + 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, + 222, 243, 212, 316, 403, 404, 211, 442, 190, 423, + 183, 0, 422, 309, 399, 407, 298, 289, 182, 405, + 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, + 304, 306, 0, 177, 0, 380, 416, 443, 195, 196, + 197, 0, 232, 236, 242, 244, 250, 251, 258, 276, + 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, + 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, + 0, 0, 326, 357, 200, 414, 377, 555, 566, 561, + 562, 559, 560, 554, 558, 557, 556, 569, 546, 547, + 548, 549, 551, 0, 563, 564, 550, 170, 184, 277, + 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 172, 173, 185, 193, 203, 215, 230, 238, 248, + 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, 372, 373, @@ -2754,25 +2423,25 @@ var yyAct = [...]int{ 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 317, - 0, 0, 0, 1446, 0, 0, 0, 0, 224, 0, + 0, 0, 0, 0, 510, 0, 0, 0, 224, 509, 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, 235, 227, 223, 208, - 259, 290, 329, 387, 323, 0, 279, 0, 0, 378, - 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 259, 290, 329, 387, 323, 553, 279, 0, 0, 378, + 302, 0, 0, 0, 0, 0, 544, 545, 0, 0, 0, 0, 0, 0, 0, 0, 265, 207, 175, 314, - 379, 239, 0, 0, 0, 167, 168, 169, 0, 1261, - 0, 0, 0, 0, 0, 0, 198, 0, 205, 0, - 0, 0, 0, 219, 263, 226, 218, 395, 0, 0, - 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 379, 239, 71, 0, 0, 167, 168, 169, 531, 530, + 533, 534, 535, 536, 0, 0, 198, 532, 205, 537, + 538, 539, 0, 219, 263, 226, 218, 395, 0, 0, + 0, 191, 0, 0, 0, 0, 0, 507, 524, 0, + 552, 0, 0, 0, 229, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 521, 522, 0, 0, 0, 0, 568, 0, 523, 0, + 0, 516, 517, 519, 518, 520, 525, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, 303, 0, - 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, + 567, 0, 0, 427, 0, 0, 565, 0, 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, - 237, 349, 332, 354, 0, 1444, 355, 280, 400, 344, + 237, 349, 332, 354, 0, 0, 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, 202, 179, 386, 408, @@ -2785,9 +2454,9 @@ var yyAct = [...]int{ 250, 251, 258, 276, 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, 0, 0, 326, 357, 200, 414, - 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 170, 184, 277, 0, 346, 240, 440, 421, 417, + 377, 555, 566, 561, 562, 559, 560, 554, 558, 557, + 556, 569, 546, 547, 548, 549, 551, 0, 563, 564, + 550, 170, 184, 277, 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, 185, 193, 203, @@ -2804,22 +2473,22 @@ var yyAct = [...]int{ 0, 0, 0, 317, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, - 235, 227, 223, 208, 259, 290, 329, 387, 323, 0, + 235, 227, 223, 208, 259, 290, 329, 387, 323, 553, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, - 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, - 198, 0, 205, 0, 0, 0, 0, 219, 263, 226, + 544, 545, 0, 0, 0, 0, 0, 0, 0, 0, + 265, 207, 175, 314, 379, 239, 71, 0, 0, 167, + 168, 169, 531, 530, 533, 534, 535, 536, 0, 0, + 198, 532, 205, 537, 538, 539, 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 229, 0, - 0, 0, 0, 0, 0, 0, 0, 760, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 524, 0, 552, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 247, 0, 303, 0, 0, 0, 0, 427, 0, 0, - 0, 0, 0, 0, 0, 274, 766, 271, 171, 187, - 764, 0, 313, 352, 358, 0, 0, 0, 210, 0, - 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, + 0, 0, 0, 0, 521, 522, 0, 0, 0, 0, + 568, 0, 523, 0, 0, 516, 517, 519, 518, 520, + 525, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 247, 0, 303, 0, 567, 0, 0, 427, 0, 0, + 565, 0, 0, 0, 0, 274, 0, 271, 171, 187, + 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, + 356, 327, 412, 194, 237, 349, 332, 354, 2240, 0, 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, @@ -2832,9 +2501,9 @@ var yyAct = [...]int{ 232, 236, 242, 244, 250, 251, 258, 276, 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, 0, 0, - 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 170, 184, 277, 0, 346, + 326, 357, 200, 414, 377, 555, 566, 561, 562, 559, + 560, 554, 558, 557, 556, 569, 546, 547, 548, 549, + 551, 0, 563, 564, 550, 170, 184, 277, 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, @@ -2849,22 +2518,22 @@ var yyAct = [...]int{ 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 317, 0, 0, - 0, 1446, 0, 0, 0, 0, 224, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, - 329, 387, 323, 0, 279, 0, 0, 378, 302, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 329, 387, 323, 553, 279, 0, 0, 378, 302, 0, + 0, 0, 0, 0, 544, 545, 0, 0, 0, 0, 0, 0, 0, 0, 265, 207, 175, 314, 379, 239, - 0, 0, 0, 167, 168, 169, 0, 1261, 0, 0, - 0, 0, 0, 0, 198, 0, 205, 0, 0, 0, + 71, 0, 587, 167, 168, 169, 531, 530, 533, 534, + 535, 536, 0, 0, 198, 532, 205, 537, 538, 539, 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 524, 0, 552, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 247, 0, 303, 0, 0, 0, - 0, 427, 0, 0, 0, 0, 0, 0, 0, 274, + 0, 0, 0, 0, 0, 0, 0, 0, 521, 522, + 0, 0, 0, 0, 568, 0, 523, 0, 0, 516, + 517, 519, 518, 520, 525, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 247, 0, 303, 0, 567, 0, + 0, 427, 0, 0, 565, 0, 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, 280, 400, 344, 410, 428, @@ -2879,9 +2548,9 @@ var yyAct = [...]int{ 195, 196, 197, 0, 232, 236, 242, 244, 250, 251, 258, 276, 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, - 272, 281, 0, 0, 326, 357, 200, 414, 377, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, + 272, 281, 0, 0, 326, 357, 200, 414, 377, 555, + 566, 561, 562, 559, 560, 554, 558, 557, 556, 569, + 546, 547, 548, 549, 551, 0, 563, 564, 550, 170, 184, 277, 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2899,19 +2568,19 @@ var yyAct = [...]int{ 0, 317, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, 235, 227, - 223, 208, 259, 290, 329, 387, 323, 0, 279, 0, - 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, + 223, 208, 259, 290, 329, 387, 323, 553, 279, 0, + 0, 378, 302, 0, 0, 0, 0, 0, 544, 545, 0, 0, 0, 0, 0, 0, 0, 0, 265, 207, - 175, 314, 379, 239, 0, 0, 586, 167, 168, 169, - 0, 0, 0, 0, 0, 0, 0, 0, 198, 0, - 205, 0, 0, 0, 0, 219, 263, 226, 218, 395, + 175, 314, 379, 239, 71, 0, 0, 167, 168, 169, + 531, 530, 533, 534, 535, 536, 0, 0, 198, 532, + 205, 537, 538, 539, 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 524, 0, 552, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 521, 522, 0, 0, 0, 0, 568, 0, + 523, 0, 0, 516, 517, 519, 518, 520, 525, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, - 303, 0, 0, 0, 0, 427, 0, 0, 0, 2127, + 303, 0, 567, 0, 0, 427, 0, 0, 565, 0, 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, 280, @@ -2927,9 +2596,9 @@ var yyAct = [...]int{ 242, 244, 250, 251, 258, 276, 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, 0, 0, 326, 357, - 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 170, 184, 277, 0, 346, 240, 440, + 200, 414, 377, 555, 566, 561, 562, 559, 560, 554, + 558, 557, 556, 569, 546, 547, 548, 549, 551, 0, + 563, 564, 550, 170, 184, 277, 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, 185, @@ -2942,149 +2611,149 @@ var yyAct = [...]int{ 287, 234, 252, 262, 0, 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, - 392, 299, 220, 35, 393, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, - 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, - 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, - 284, 282, 398, 235, 227, 223, 208, 259, 290, 329, - 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, + 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 317, 0, 0, 0, 0, + 0, 0, 0, 0, 224, 0, 0, 0, 0, 275, + 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, + 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, + 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 265, 207, 175, 314, 379, 239, 71, - 0, 0, 167, 168, 169, 0, 0, 0, 0, 0, - 0, 0, 0, 198, 0, 205, 0, 0, 0, 0, - 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, + 0, 0, 265, 207, 175, 314, 379, 239, 0, 0, + 0, 167, 168, 169, 0, 0, 0, 0, 0, 0, + 0, 0, 198, 0, 205, 0, 0, 0, 0, 219, + 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, + 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 977, 976, 986, 987, 979, 980, 981, 982, + 983, 984, 985, 978, 0, 0, 988, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 247, 0, 303, 0, 0, 0, 0, 427, + 0, 0, 0, 0, 0, 0, 0, 274, 0, 271, + 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, + 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, + 0, 0, 355, 280, 400, 344, 410, 428, 429, 217, + 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, + 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, + 186, 364, 202, 179, 386, 408, 199, 367, 0, 0, + 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, + 222, 243, 212, 316, 403, 404, 211, 442, 190, 423, + 183, 0, 422, 309, 399, 407, 298, 289, 182, 405, + 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, + 304, 306, 0, 177, 0, 380, 416, 443, 195, 196, + 197, 0, 232, 236, 242, 244, 250, 251, 258, 276, + 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, + 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, + 0, 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 170, 184, 277, + 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 247, 0, 303, 0, 0, 0, 0, - 427, 0, 0, 0, 0, 0, 0, 0, 274, 0, - 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, - 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, - 354, 0, 0, 355, 280, 400, 344, 410, 428, 429, - 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, - 415, 375, 300, 396, 397, 270, 374, 245, 174, 278, - 436, 186, 364, 202, 179, 386, 408, 199, 367, 0, - 0, 441, 181, 406, 383, 297, 267, 268, 180, 0, - 348, 222, 243, 212, 316, 403, 404, 211, 442, 190, - 423, 183, 0, 422, 309, 399, 407, 298, 289, 182, - 405, 296, 288, 273, 233, 254, 342, 283, 343, 255, - 305, 304, 306, 0, 177, 0, 380, 416, 443, 195, - 196, 197, 0, 232, 236, 242, 244, 250, 251, 258, - 276, 320, 341, 339, 345, 0, 394, 411, 419, 426, - 432, 433, 437, 434, 435, 438, 308, 257, 376, 272, - 281, 0, 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 170, 184, - 277, 0, 346, 240, 440, 421, 417, 0, 0, 216, + 0, 172, 173, 185, 193, 203, 215, 230, 238, 248, + 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, + 294, 310, 311, 312, 315, 318, 319, 322, 324, 325, + 328, 334, 335, 336, 337, 338, 340, 347, 351, 359, + 360, 361, 362, 363, 365, 366, 370, 371, 372, 373, + 381, 385, 401, 402, 413, 425, 430, 249, 409, 431, + 0, 285, 0, 0, 287, 234, 252, 262, 0, 420, + 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, + 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, + 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 317, + 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, + 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, + 0, 369, 209, 284, 282, 398, 235, 227, 223, 208, + 259, 290, 329, 387, 323, 0, 279, 0, 0, 378, + 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 265, 207, 175, 314, + 379, 239, 0, 0, 0, 167, 168, 169, 0, 0, + 0, 0, 0, 0, 0, 0, 198, 0, 205, 0, + 0, 0, 0, 219, 263, 226, 218, 395, 0, 0, + 0, 191, 0, 805, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 172, 173, 185, 193, 203, 215, 230, 238, - 248, 253, 256, 260, 261, 264, 269, 286, 291, 292, - 293, 294, 310, 311, 312, 315, 318, 319, 322, 324, - 325, 328, 334, 335, 336, 337, 338, 340, 347, 351, - 359, 360, 361, 362, 363, 365, 366, 370, 371, 372, - 373, 381, 385, 401, 402, 413, 425, 430, 249, 409, - 431, 0, 285, 0, 0, 287, 234, 252, 262, 0, - 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, - 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, - 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 317, 0, 0, 0, 0, 0, 0, 0, 0, 224, - 0, 0, 0, 0, 275, 221, 0, 0, 331, 0, - 176, 0, 369, 209, 284, 282, 398, 235, 227, 223, - 208, 259, 290, 329, 387, 323, 0, 279, 0, 0, - 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 265, 207, 175, - 314, 379, 239, 0, 0, 0, 167, 168, 169, 0, - 0, 1465, 0, 0, 1466, 0, 0, 198, 0, 205, - 0, 0, 0, 0, 219, 263, 226, 218, 395, 0, - 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 247, 0, 303, - 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, - 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, - 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, - 194, 237, 349, 332, 354, 0, 0, 355, 280, 400, - 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, - 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, - 374, 245, 174, 278, 436, 186, 364, 202, 179, 386, - 408, 199, 367, 0, 0, 441, 181, 406, 383, 297, - 267, 268, 180, 0, 348, 222, 243, 212, 316, 403, - 404, 211, 442, 190, 423, 183, 0, 422, 309, 399, - 407, 298, 289, 182, 405, 296, 288, 273, 233, 254, - 342, 283, 343, 255, 305, 304, 306, 0, 177, 0, - 380, 416, 443, 195, 196, 197, 0, 232, 236, 242, - 244, 250, 251, 258, 276, 320, 341, 339, 345, 0, - 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, - 308, 257, 376, 272, 281, 0, 0, 326, 357, 200, - 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 170, 184, 277, 0, 346, 240, 440, 421, - 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 172, 173, 185, 193, - 203, 215, 230, 238, 248, 253, 256, 260, 261, 264, - 269, 286, 291, 292, 293, 294, 310, 311, 312, 315, - 318, 319, 322, 324, 325, 328, 334, 335, 336, 337, - 338, 340, 347, 351, 359, 360, 361, 362, 363, 365, - 366, 370, 371, 372, 373, 381, 385, 401, 402, 413, - 425, 430, 249, 409, 431, 0, 285, 0, 0, 287, - 234, 252, 262, 0, 420, 382, 189, 353, 241, 178, - 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, - 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, - 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 317, 0, 0, 0, 0, 0, - 0, 0, 0, 224, 1111, 0, 0, 0, 275, 221, - 0, 0, 331, 0, 176, 0, 369, 209, 284, 282, - 398, 235, 227, 223, 208, 259, 290, 329, 387, 323, - 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 247, 0, 303, 0, + 0, 0, 804, 427, 0, 0, 0, 0, 0, 801, + 802, 274, 767, 271, 171, 187, 795, 799, 313, 352, + 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, + 237, 349, 332, 354, 0, 0, 355, 280, 400, 344, + 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, + 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, + 245, 174, 278, 436, 186, 364, 202, 179, 386, 408, + 199, 367, 0, 0, 441, 181, 406, 383, 297, 267, + 268, 180, 0, 348, 222, 243, 212, 316, 403, 404, + 211, 442, 190, 423, 183, 0, 422, 309, 399, 407, + 298, 289, 182, 405, 296, 288, 273, 233, 254, 342, + 283, 343, 255, 305, 304, 306, 0, 177, 0, 380, + 416, 443, 195, 196, 197, 0, 232, 236, 242, 244, + 250, 251, 258, 276, 320, 341, 339, 345, 0, 394, + 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, + 257, 376, 272, 281, 0, 0, 326, 357, 200, 414, + 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 265, 207, 175, 314, 379, 239, 0, 0, 0, - 167, 168, 169, 0, 1110, 0, 0, 0, 0, 0, - 0, 198, 0, 205, 0, 0, 0, 0, 219, 263, - 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 229, + 0, 170, 184, 277, 0, 346, 240, 440, 421, 417, + 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 172, 173, 185, 193, 203, + 215, 230, 238, 248, 253, 256, 260, 261, 264, 269, + 286, 291, 292, 293, 294, 310, 311, 312, 315, 318, + 319, 322, 324, 325, 328, 334, 335, 336, 337, 338, + 340, 347, 351, 359, 360, 361, 362, 363, 365, 366, + 370, 371, 372, 373, 381, 385, 401, 402, 413, 425, + 430, 249, 409, 431, 0, 285, 0, 0, 287, 234, + 252, 262, 0, 420, 382, 189, 353, 241, 178, 206, + 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, + 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, + 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 317, 0, 0, 0, 1080, 0, 0, + 0, 0, 224, 0, 0, 0, 0, 275, 221, 0, + 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, + 235, 227, 223, 208, 259, 290, 329, 387, 323, 0, + 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, + 168, 169, 0, 1082, 0, 0, 0, 0, 0, 0, + 198, 0, 205, 0, 0, 0, 0, 219, 263, 226, + 218, 395, 0, 0, 0, 191, 0, 0, 966, 967, + 965, 0, 0, 0, 0, 0, 0, 0, 229, 0, + 0, 0, 0, 0, 0, 0, 968, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 247, 0, 303, 0, 0, 0, 0, 427, 0, - 0, 0, 0, 0, 0, 0, 274, 0, 271, 171, - 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, - 0, 356, 327, 412, 194, 237, 349, 332, 354, 0, - 0, 355, 280, 400, 344, 410, 428, 429, 217, 307, - 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, - 300, 396, 397, 270, 374, 245, 174, 278, 436, 186, - 364, 202, 179, 386, 408, 199, 367, 0, 0, 441, - 181, 406, 383, 297, 267, 268, 180, 0, 348, 222, - 243, 212, 316, 403, 404, 211, 442, 190, 423, 183, - 0, 422, 309, 399, 407, 298, 289, 182, 405, 296, - 288, 273, 233, 254, 342, 283, 343, 255, 305, 304, - 306, 0, 177, 0, 380, 416, 443, 195, 196, 197, - 0, 232, 236, 242, 244, 250, 251, 258, 276, 320, - 341, 339, 345, 0, 394, 411, 419, 426, 432, 433, - 437, 434, 435, 438, 308, 257, 376, 272, 281, 0, - 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 170, 184, 277, 0, - 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, + 247, 0, 303, 0, 0, 0, 0, 427, 0, 0, + 0, 0, 0, 0, 0, 274, 0, 271, 171, 187, + 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, + 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, + 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, + 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, + 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, + 202, 179, 386, 408, 199, 367, 0, 0, 441, 181, + 406, 383, 297, 267, 268, 180, 0, 348, 222, 243, + 212, 316, 403, 404, 211, 442, 190, 423, 183, 0, + 422, 309, 399, 407, 298, 289, 182, 405, 296, 288, + 273, 233, 254, 342, 283, 343, 255, 305, 304, 306, + 0, 177, 0, 380, 416, 443, 195, 196, 197, 0, + 232, 236, 242, 244, 250, 251, 258, 276, 320, 341, + 339, 345, 0, 394, 411, 419, 426, 432, 433, 437, + 434, 435, 438, 308, 257, 376, 272, 281, 0, 0, + 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 170, 184, 277, 0, 346, + 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 172, 173, 185, 193, 203, 215, 230, 238, 248, 253, - 256, 260, 261, 264, 269, 286, 291, 292, 293, 294, - 310, 311, 312, 315, 318, 319, 322, 324, 325, 328, - 334, 335, 336, 337, 338, 340, 347, 351, 359, 360, - 361, 362, 363, 365, 366, 370, 371, 372, 373, 381, - 385, 401, 402, 413, 425, 430, 249, 409, 431, 0, - 285, 0, 0, 287, 234, 252, 262, 0, 420, 382, - 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, - 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, - 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, + 173, 185, 193, 203, 215, 230, 238, 248, 253, 256, + 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, + 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, + 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, + 362, 363, 365, 366, 370, 371, 372, 373, 381, 385, + 401, 402, 413, 425, 430, 249, 409, 431, 0, 285, + 0, 0, 287, 234, 252, 262, 0, 420, 382, 189, + 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, + 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, + 389, 390, 392, 299, 220, 35, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, @@ -3092,7 +2761,7 @@ var yyAct = [...]int{ 290, 329, 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 265, 207, 175, 314, 379, - 239, 0, 0, 0, 167, 168, 169, 0, 0, 0, + 239, 71, 0, 587, 167, 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, 198, 0, 205, 0, 0, 0, 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -3101,7 +2770,7 @@ var yyAct = [...]int{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, 303, 0, 0, - 0, 0, 427, 0, 0, 0, 2210, 0, 0, 0, + 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, 280, 400, 344, 410, @@ -3133,14 +2802,14 @@ var yyAct = [...]int{ 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 317, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 317, 0, 0, 0, 1449, 0, 0, 0, 0, 224, 0, 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, 168, - 169, 0, 0, 0, 0, 0, 0, 0, 0, 198, + 169, 0, 1263, 0, 0, 0, 0, 0, 0, 198, 0, 205, 0, 0, 0, 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, @@ -3149,9 +2818,9 @@ var yyAct = [...]int{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, 303, 0, 0, 0, 0, 427, 0, 0, 0, - 2127, 0, 0, 0, 274, 0, 271, 171, 187, 0, + 0, 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, - 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, + 327, 412, 194, 237, 349, 332, 354, 0, 1447, 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, 202, @@ -3186,18 +2855,18 @@ var yyAct = [...]int{ 284, 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 265, 207, 175, 314, 379, 239, 71, + 0, 0, 0, 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, 198, 0, 205, 0, 0, 0, 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 761, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, 303, 0, 0, 0, 0, - 427, 0, 0, 0, 0, 0, 0, 0, 274, 0, - 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, + 427, 0, 0, 0, 0, 0, 0, 0, 274, 767, + 271, 171, 187, 765, 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, @@ -3228,14 +2897,14 @@ var yyAct = [...]int{ 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 317, 0, 0, 0, 0, 0, 0, 0, 0, 224, + 317, 0, 0, 0, 1449, 0, 0, 0, 0, 224, 0, 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, 168, 169, 0, - 1261, 0, 0, 0, 0, 0, 0, 198, 0, 205, + 1263, 0, 0, 0, 0, 0, 0, 198, 0, 205, 0, 0, 0, 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, @@ -3281,8 +2950,8 @@ var yyAct = [...]int{ 398, 235, 227, 223, 208, 259, 290, 329, 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 265, 207, 175, 314, 379, 239, 0, 0, 0, - 167, 168, 169, 0, 1080, 0, 0, 0, 0, 0, + 0, 265, 207, 175, 314, 379, 239, 0, 0, 587, + 167, 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, 198, 0, 205, 0, 0, 0, 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 229, @@ -3291,7 +2960,7 @@ var yyAct = [...]int{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, 303, 0, 0, 0, 0, 427, 0, - 0, 0, 0, 0, 0, 0, 274, 0, 271, 171, + 0, 0, 2130, 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, 280, 400, 344, 410, 428, 429, 217, 307, @@ -3321,785 +2990,1167 @@ var yyAct = [...]int{ 285, 0, 0, 287, 234, 252, 262, 0, 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, - 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 317, 0, - 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, - 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, - 369, 209, 284, 282, 398, 235, 227, 223, 208, 259, - 290, 329, 387, 323, 0, 279, 0, 0, 378, 302, + 388, 389, 390, 392, 299, 220, 35, 393, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 317, + 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, + 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, + 0, 369, 209, 284, 282, 398, 235, 227, 223, 208, + 259, 290, 329, 387, 323, 0, 279, 0, 0, 378, + 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 265, 207, 175, 314, + 379, 239, 71, 0, 0, 167, 168, 169, 0, 0, + 0, 0, 0, 0, 0, 0, 198, 0, 205, 0, + 0, 0, 0, 219, 263, 226, 218, 395, 0, 0, + 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 265, 207, 175, 314, 379, - 239, 0, 0, 0, 167, 168, 169, 0, 0, 0, - 0, 0, 0, 0, 0, 198, 0, 205, 0, 0, - 0, 0, 219, 263, 226, 218, 395, 0, 0, 0, - 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 247, 0, 303, 0, + 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, + 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, + 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, + 237, 349, 332, 354, 0, 0, 355, 280, 400, 344, + 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, + 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, + 245, 174, 278, 436, 186, 364, 202, 179, 386, 408, + 199, 367, 0, 0, 441, 181, 406, 383, 297, 267, + 268, 180, 0, 348, 222, 243, 212, 316, 403, 404, + 211, 442, 190, 423, 183, 0, 422, 309, 399, 407, + 298, 289, 182, 405, 296, 288, 273, 233, 254, 342, + 283, 343, 255, 305, 304, 306, 0, 177, 0, 380, + 416, 443, 195, 196, 197, 0, 232, 236, 242, 244, + 250, 251, 258, 276, 320, 341, 339, 345, 0, 394, + 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, + 257, 376, 272, 281, 0, 0, 326, 357, 200, 414, + 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 247, 0, 303, 0, 0, - 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, - 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, - 0, 0, 0, 210, 0, 356, 327, 412, 194, 237, - 349, 332, 354, 0, 0, 355, 280, 400, 344, 410, - 428, 429, 217, 307, 418, 391, 424, 439, 188, 214, - 321, 384, 415, 375, 300, 396, 397, 270, 374, 245, - 174, 278, 436, 186, 364, 202, 179, 386, 408, 199, - 367, 0, 0, 441, 181, 406, 383, 297, 267, 268, - 180, 0, 348, 222, 243, 212, 316, 403, 404, 211, - 442, 190, 423, 183, 0, 422, 309, 399, 407, 298, - 289, 182, 405, 296, 288, 273, 233, 254, 342, 283, - 343, 255, 305, 304, 306, 0, 177, 0, 380, 416, - 443, 195, 196, 197, 0, 232, 236, 242, 244, 250, - 251, 258, 276, 320, 341, 339, 345, 0, 394, 411, - 419, 426, 432, 433, 437, 434, 435, 438, 308, 257, - 376, 272, 281, 0, 0, 326, 357, 200, 414, 377, + 0, 170, 184, 277, 0, 346, 240, 440, 421, 417, + 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 172, 173, 185, 193, 203, + 215, 230, 238, 248, 253, 256, 260, 261, 264, 269, + 286, 291, 292, 293, 294, 310, 311, 312, 315, 318, + 319, 322, 324, 325, 328, 334, 335, 336, 337, 338, + 340, 347, 351, 359, 360, 361, 362, 363, 365, 366, + 370, 371, 372, 373, 381, 385, 401, 402, 413, 425, + 430, 249, 409, 431, 0, 285, 0, 0, 287, 234, + 252, 262, 0, 420, 382, 189, 353, 241, 178, 206, + 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, + 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, + 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 317, 0, 0, 0, 0, 0, 0, + 0, 0, 224, 0, 0, 0, 0, 275, 221, 0, + 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, + 235, 227, 223, 208, 259, 290, 329, 387, 323, 0, + 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 170, 184, 277, 1351, 346, 240, 440, 421, 417, 0, - 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, + 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, + 168, 169, 0, 0, 1468, 0, 0, 1469, 0, 0, + 198, 0, 205, 0, 0, 0, 0, 219, 263, 226, + 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 172, 173, 185, 193, 203, 215, - 230, 238, 248, 253, 256, 260, 261, 264, 269, 286, - 291, 292, 293, 294, 310, 311, 312, 315, 318, 319, - 322, 324, 325, 328, 334, 335, 336, 337, 338, 340, - 347, 351, 359, 360, 361, 362, 363, 365, 366, 370, - 371, 372, 373, 381, 385, 401, 402, 413, 425, 430, - 249, 409, 431, 0, 285, 0, 0, 287, 234, 252, - 262, 0, 420, 382, 189, 353, 241, 178, 206, 192, - 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, - 204, 350, 201, 368, 388, 389, 390, 392, 299, 220, - 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 317, 0, 1233, 0, 0, 0, 0, 0, - 0, 224, 0, 0, 0, 0, 275, 221, 0, 0, - 331, 0, 176, 0, 369, 209, 284, 282, 398, 235, - 227, 223, 208, 259, 290, 329, 387, 323, 0, 279, - 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 265, - 207, 175, 314, 379, 239, 0, 0, 0, 167, 168, - 169, 0, 0, 0, 0, 0, 0, 0, 0, 198, - 0, 205, 0, 0, 0, 0, 219, 263, 226, 218, - 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, - 0, 303, 0, 0, 0, 0, 427, 0, 0, 0, - 0, 0, 0, 0, 274, 0, 271, 171, 187, 0, - 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, - 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, - 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, - 424, 439, 188, 214, 321, 384, 415, 375, 300, 396, - 397, 270, 374, 245, 174, 278, 436, 186, 364, 202, - 179, 386, 408, 199, 367, 0, 0, 441, 181, 406, - 383, 297, 267, 268, 180, 0, 348, 222, 243, 212, - 316, 403, 404, 211, 442, 190, 423, 183, 0, 422, - 309, 399, 407, 298, 289, 182, 405, 296, 288, 273, - 233, 254, 342, 283, 343, 255, 305, 304, 306, 0, - 177, 0, 380, 416, 443, 195, 196, 197, 0, 232, - 236, 242, 244, 250, 251, 258, 276, 320, 341, 339, - 345, 0, 394, 411, 419, 426, 432, 433, 437, 434, - 435, 438, 308, 257, 376, 272, 281, 0, 0, 326, - 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, + 247, 0, 303, 0, 0, 0, 0, 427, 0, 0, + 0, 0, 0, 0, 0, 274, 0, 271, 171, 187, + 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, + 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, + 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, + 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, + 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, + 202, 179, 386, 408, 199, 367, 0, 0, 441, 181, + 406, 383, 297, 267, 268, 180, 0, 348, 222, 243, + 212, 316, 403, 404, 211, 442, 190, 423, 183, 0, + 422, 309, 399, 407, 298, 289, 182, 405, 296, 288, + 273, 233, 254, 342, 283, 343, 255, 305, 304, 306, + 0, 177, 0, 380, 416, 443, 195, 196, 197, 0, + 232, 236, 242, 244, 250, 251, 258, 276, 320, 341, + 339, 345, 0, 394, 411, 419, 426, 432, 433, 437, + 434, 435, 438, 308, 257, 376, 272, 281, 0, 0, + 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 170, 184, 277, 0, 346, 240, - 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 170, 184, 277, 0, 346, + 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, - 185, 193, 203, 215, 230, 238, 248, 253, 256, 260, - 261, 264, 269, 286, 291, 292, 293, 294, 310, 311, - 312, 315, 318, 319, 322, 324, 325, 328, 334, 335, - 336, 337, 338, 340, 347, 351, 359, 360, 361, 362, - 363, 365, 366, 370, 371, 372, 373, 381, 385, 401, - 402, 413, 425, 430, 249, 409, 431, 0, 285, 0, - 0, 287, 234, 252, 262, 0, 420, 382, 189, 353, - 241, 178, 206, 192, 213, 228, 231, 266, 295, 301, - 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, - 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 317, 0, 1231, 0, - 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, - 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, - 284, 282, 398, 235, 227, 223, 208, 259, 290, 329, - 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, + 173, 185, 193, 203, 215, 230, 238, 248, 253, 256, + 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, + 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, + 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, + 362, 363, 365, 366, 370, 371, 372, 373, 381, 385, + 401, 402, 413, 425, 430, 249, 409, 431, 0, 285, + 0, 0, 287, 234, 252, 262, 0, 420, 382, 189, + 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, + 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, + 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 317, 0, 0, + 0, 0, 0, 0, 0, 0, 224, 1113, 0, 0, + 0, 275, 221, 0, 0, 331, 0, 176, 0, 369, + 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, + 329, 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 265, 207, 175, 314, 379, 239, 0, - 0, 0, 167, 168, 169, 0, 0, 0, 0, 0, - 0, 0, 0, 198, 0, 205, 0, 0, 0, 0, - 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, + 0, 0, 0, 0, 265, 207, 175, 314, 379, 239, + 0, 0, 0, 167, 168, 169, 0, 1112, 0, 0, + 0, 0, 0, 0, 198, 0, 205, 0, 0, 0, + 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 247, 0, 303, 0, 0, 0, 0, - 427, 0, 0, 0, 0, 0, 0, 0, 274, 0, - 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, - 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, - 354, 0, 0, 355, 280, 400, 344, 410, 428, 429, - 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, - 415, 375, 300, 396, 397, 270, 374, 245, 174, 278, - 436, 186, 364, 202, 179, 386, 408, 199, 367, 0, - 0, 441, 181, 406, 383, 297, 267, 268, 180, 0, - 348, 222, 243, 212, 316, 403, 404, 211, 442, 190, - 423, 183, 0, 422, 309, 399, 407, 298, 289, 182, - 405, 296, 288, 273, 233, 254, 342, 283, 343, 255, - 305, 304, 306, 0, 177, 0, 380, 416, 443, 195, - 196, 197, 0, 232, 236, 242, 244, 250, 251, 258, - 276, 320, 341, 339, 345, 0, 394, 411, 419, 426, - 432, 433, 437, 434, 435, 438, 308, 257, 376, 272, - 281, 0, 0, 326, 357, 200, 414, 377, 0, 0, + 0, 0, 0, 0, 247, 0, 303, 0, 0, 0, + 0, 427, 0, 0, 0, 0, 0, 0, 0, 274, + 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, + 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, + 332, 354, 0, 0, 355, 280, 400, 344, 410, 428, + 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, + 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, + 278, 436, 186, 364, 202, 179, 386, 408, 199, 367, + 0, 0, 441, 181, 406, 383, 297, 267, 268, 180, + 0, 348, 222, 243, 212, 316, 403, 404, 211, 442, + 190, 423, 183, 0, 422, 309, 399, 407, 298, 289, + 182, 405, 296, 288, 273, 233, 254, 342, 283, 343, + 255, 305, 304, 306, 0, 177, 0, 380, 416, 443, + 195, 196, 197, 0, 232, 236, 242, 244, 250, 251, + 258, 276, 320, 341, 339, 345, 0, 394, 411, 419, + 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, + 272, 281, 0, 0, 326, 357, 200, 414, 377, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, + 184, 277, 0, 346, 240, 440, 421, 417, 0, 0, + 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 172, 173, 185, 193, 203, 215, 230, + 238, 248, 253, 256, 260, 261, 264, 269, 286, 291, + 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, + 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, + 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, + 372, 373, 381, 385, 401, 402, 413, 425, 430, 249, + 409, 431, 0, 285, 0, 0, 287, 234, 252, 262, + 0, 420, 382, 189, 353, 241, 178, 206, 192, 213, + 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, + 350, 201, 368, 388, 389, 390, 392, 299, 220, 393, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 317, 0, 0, 0, 0, 0, 0, 0, 0, + 224, 0, 0, 0, 0, 275, 221, 0, 0, 331, + 0, 176, 0, 369, 209, 284, 282, 398, 235, 227, + 223, 208, 259, 290, 329, 387, 323, 0, 279, 0, + 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 265, 207, + 175, 314, 379, 239, 0, 0, 0, 167, 168, 169, + 0, 0, 0, 0, 0, 0, 0, 0, 198, 0, + 205, 0, 0, 0, 0, 219, 263, 226, 218, 395, + 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, + 303, 0, 0, 0, 0, 427, 0, 0, 0, 2213, + 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, + 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, + 412, 194, 237, 349, 332, 354, 0, 0, 355, 280, + 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, + 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, + 270, 374, 245, 174, 278, 436, 186, 364, 202, 179, + 386, 408, 199, 367, 0, 0, 441, 181, 406, 383, + 297, 267, 268, 180, 0, 348, 222, 243, 212, 316, + 403, 404, 211, 442, 190, 423, 183, 0, 422, 309, + 399, 407, 298, 289, 182, 405, 296, 288, 273, 233, + 254, 342, 283, 343, 255, 305, 304, 306, 0, 177, + 0, 380, 416, 443, 195, 196, 197, 0, 232, 236, + 242, 244, 250, 251, 258, 276, 320, 341, 339, 345, + 0, 394, 411, 419, 426, 432, 433, 437, 434, 435, + 438, 308, 257, 376, 272, 281, 0, 0, 326, 357, + 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 170, 184, 277, 0, 346, 240, 440, + 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 172, 173, 185, + 193, 203, 215, 230, 238, 248, 253, 256, 260, 261, + 264, 269, 286, 291, 292, 293, 294, 310, 311, 312, + 315, 318, 319, 322, 324, 325, 328, 334, 335, 336, + 337, 338, 340, 347, 351, 359, 360, 361, 362, 363, + 365, 366, 370, 371, 372, 373, 381, 385, 401, 402, + 413, 425, 430, 249, 409, 431, 0, 285, 0, 0, + 287, 234, 252, 262, 0, 420, 382, 189, 353, 241, + 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, + 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, + 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 317, 0, 0, 0, 0, + 0, 0, 0, 0, 224, 0, 0, 0, 0, 275, + 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, + 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, + 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 265, 207, 175, 314, 379, 239, 0, 0, + 0, 167, 168, 169, 0, 0, 0, 0, 0, 0, + 0, 0, 198, 0, 205, 0, 0, 0, 0, 219, + 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 247, 0, 303, 0, 0, 0, 0, 427, + 0, 0, 0, 2130, 0, 0, 0, 274, 0, 271, + 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, + 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, + 0, 0, 355, 280, 400, 344, 410, 428, 429, 217, + 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, + 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, + 186, 364, 202, 179, 386, 408, 199, 367, 0, 0, + 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, + 222, 243, 212, 316, 403, 404, 211, 442, 190, 423, + 183, 0, 422, 309, 399, 407, 298, 289, 182, 405, + 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, + 304, 306, 0, 177, 0, 380, 416, 443, 195, 196, + 197, 0, 232, 236, 242, 244, 250, 251, 258, 276, + 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, + 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, + 0, 0, 326, 357, 200, 414, 377, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 170, 184, 277, + 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 172, 173, 185, 193, 203, 215, 230, 238, 248, + 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, + 294, 310, 311, 312, 315, 318, 319, 322, 324, 325, + 328, 334, 335, 336, 337, 338, 340, 347, 351, 359, + 360, 361, 362, 363, 365, 366, 370, 371, 372, 373, + 381, 385, 401, 402, 413, 425, 430, 249, 409, 431, + 0, 285, 0, 0, 287, 234, 252, 262, 0, 420, + 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, + 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, + 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 317, + 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, + 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, + 0, 369, 209, 284, 282, 398, 235, 227, 223, 208, + 259, 290, 329, 387, 323, 0, 279, 0, 0, 378, + 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 265, 207, 175, 314, + 379, 239, 71, 0, 0, 167, 168, 169, 0, 0, + 0, 0, 0, 0, 0, 0, 198, 0, 205, 0, + 0, 0, 0, 219, 263, 226, 218, 395, 0, 0, + 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 247, 0, 303, 0, + 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, + 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, + 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, + 237, 349, 332, 354, 0, 0, 355, 280, 400, 344, + 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, + 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, + 245, 174, 278, 436, 186, 364, 202, 179, 386, 408, + 199, 367, 0, 0, 441, 181, 406, 383, 297, 267, + 268, 180, 0, 348, 222, 243, 212, 316, 403, 404, + 211, 442, 190, 423, 183, 0, 422, 309, 399, 407, + 298, 289, 182, 405, 296, 288, 273, 233, 254, 342, + 283, 343, 255, 305, 304, 306, 0, 177, 0, 380, + 416, 443, 195, 196, 197, 0, 232, 236, 242, 244, + 250, 251, 258, 276, 320, 341, 339, 345, 0, 394, + 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, + 257, 376, 272, 281, 0, 0, 326, 357, 200, 414, + 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 170, 184, 277, 0, 346, 240, 440, 421, 417, + 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 172, 173, 185, 193, 203, + 215, 230, 238, 248, 253, 256, 260, 261, 264, 269, + 286, 291, 292, 293, 294, 310, 311, 312, 315, 318, + 319, 322, 324, 325, 328, 334, 335, 336, 337, 338, + 340, 347, 351, 359, 360, 361, 362, 363, 365, 366, + 370, 371, 372, 373, 381, 385, 401, 402, 413, 425, + 430, 249, 409, 431, 0, 285, 0, 0, 287, 234, + 252, 262, 0, 420, 382, 189, 353, 241, 178, 206, + 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, + 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, + 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 317, 0, 0, 0, 0, 0, 0, + 0, 0, 224, 0, 0, 0, 0, 275, 221, 0, + 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, + 235, 227, 223, 208, 259, 290, 329, 387, 323, 0, + 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, + 168, 169, 0, 1263, 0, 0, 0, 0, 0, 0, + 198, 0, 205, 0, 0, 0, 0, 219, 263, 226, + 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 229, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 247, 0, 303, 0, 0, 0, 0, 427, 0, 0, + 0, 0, 0, 0, 0, 274, 0, 271, 171, 187, + 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, + 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, + 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, + 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, + 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, + 202, 179, 386, 408, 199, 367, 0, 0, 441, 181, + 406, 383, 297, 267, 268, 180, 0, 348, 222, 243, + 212, 316, 403, 404, 211, 442, 190, 423, 183, 0, + 422, 309, 399, 407, 298, 289, 182, 405, 296, 288, + 273, 233, 254, 342, 283, 343, 255, 305, 304, 306, + 0, 177, 0, 380, 416, 443, 195, 196, 197, 0, + 232, 236, 242, 244, 250, 251, 258, 276, 320, 341, + 339, 345, 0, 394, 411, 419, 426, 432, 433, 437, + 434, 435, 438, 308, 257, 376, 272, 281, 0, 0, + 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 170, 184, 277, 0, 346, + 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, + 173, 185, 193, 203, 215, 230, 238, 248, 253, 256, + 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, + 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, + 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, + 362, 363, 365, 366, 370, 371, 372, 373, 381, 385, + 401, 402, 413, 425, 430, 249, 409, 431, 0, 285, + 0, 0, 287, 234, 252, 262, 0, 420, 382, 189, + 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, + 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, + 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 317, 0, 0, + 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, + 0, 275, 221, 0, 0, 331, 0, 176, 0, 369, + 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, + 329, 387, 323, 0, 279, 0, 0, 378, 302, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 265, 207, 175, 314, 379, 239, + 0, 0, 0, 167, 168, 169, 0, 1082, 0, 0, + 0, 0, 0, 0, 198, 0, 205, 0, 0, 0, + 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 247, 0, 303, 0, 0, 0, + 0, 427, 0, 0, 0, 0, 0, 0, 0, 274, + 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, + 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, + 332, 354, 0, 0, 355, 280, 400, 344, 410, 428, + 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, + 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, + 278, 436, 186, 364, 202, 179, 386, 408, 199, 367, + 0, 0, 441, 181, 406, 383, 297, 267, 268, 180, + 0, 348, 222, 243, 212, 316, 403, 404, 211, 442, + 190, 423, 183, 0, 422, 309, 399, 407, 298, 289, + 182, 405, 296, 288, 273, 233, 254, 342, 283, 343, + 255, 305, 304, 306, 0, 177, 0, 380, 416, 443, + 195, 196, 197, 0, 232, 236, 242, 244, 250, 251, + 258, 276, 320, 341, 339, 345, 0, 394, 411, 419, + 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, + 272, 281, 0, 0, 326, 357, 200, 414, 377, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, + 184, 277, 0, 346, 240, 440, 421, 417, 0, 0, + 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 172, 173, 185, 193, 203, 215, 230, + 238, 248, 253, 256, 260, 261, 264, 269, 286, 291, + 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, + 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, + 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, + 372, 373, 381, 385, 401, 402, 413, 425, 430, 249, + 409, 431, 0, 285, 0, 0, 287, 234, 252, 262, + 0, 420, 382, 189, 353, 241, 178, 206, 192, 213, + 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, + 350, 201, 368, 388, 389, 390, 392, 299, 220, 393, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 317, 0, 0, 0, 0, 0, 0, 0, 0, + 224, 0, 0, 0, 0, 275, 221, 0, 0, 331, + 0, 176, 0, 369, 209, 284, 282, 398, 235, 227, + 223, 208, 259, 290, 329, 387, 323, 0, 279, 0, + 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 265, 207, + 175, 314, 379, 239, 0, 0, 0, 167, 168, 169, + 0, 0, 0, 0, 0, 0, 0, 0, 198, 0, + 205, 0, 0, 0, 0, 219, 263, 226, 218, 395, + 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, + 303, 0, 0, 0, 0, 427, 0, 0, 0, 0, + 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, + 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, + 412, 194, 237, 349, 332, 354, 0, 0, 355, 280, + 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, + 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, + 270, 374, 245, 174, 278, 436, 186, 364, 202, 179, + 386, 408, 199, 367, 0, 0, 441, 181, 406, 383, + 297, 267, 268, 180, 0, 348, 222, 243, 212, 316, + 403, 404, 211, 442, 190, 423, 183, 0, 422, 309, + 399, 407, 298, 289, 182, 405, 296, 288, 273, 233, + 254, 342, 283, 343, 255, 305, 304, 306, 0, 177, + 0, 380, 416, 443, 195, 196, 197, 0, 232, 236, + 242, 244, 250, 251, 258, 276, 320, 341, 339, 345, + 0, 394, 411, 419, 426, 432, 433, 437, 434, 435, + 438, 308, 257, 376, 272, 281, 0, 0, 326, 357, + 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 170, 184, 277, 1354, 346, 240, 440, + 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 172, 173, 185, + 193, 203, 215, 230, 238, 248, 253, 256, 260, 261, + 264, 269, 286, 291, 292, 293, 294, 310, 311, 312, + 315, 318, 319, 322, 324, 325, 328, 334, 335, 336, + 337, 338, 340, 347, 351, 359, 360, 361, 362, 363, + 365, 366, 370, 371, 372, 373, 381, 385, 401, 402, + 413, 425, 430, 249, 409, 431, 0, 285, 0, 0, + 287, 234, 252, 262, 0, 420, 382, 189, 353, 241, + 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, + 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, + 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 317, 0, 1235, 0, 0, + 0, 0, 0, 0, 224, 0, 0, 0, 0, 275, + 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, + 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, + 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 265, 207, 175, 314, 379, 239, 0, 0, + 0, 167, 168, 169, 0, 0, 0, 0, 0, 0, + 0, 0, 198, 0, 205, 0, 0, 0, 0, 219, + 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 170, 184, - 277, 0, 346, 240, 440, 421, 417, 0, 0, 216, + 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 172, 173, 185, 193, 203, 215, 230, 238, - 248, 253, 256, 260, 261, 264, 269, 286, 291, 292, - 293, 294, 310, 311, 312, 315, 318, 319, 322, 324, - 325, 328, 334, 335, 336, 337, 338, 340, 347, 351, - 359, 360, 361, 362, 363, 365, 366, 370, 371, 372, - 373, 381, 385, 401, 402, 413, 425, 430, 249, 409, - 431, 0, 285, 0, 0, 287, 234, 252, 262, 0, - 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, - 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, - 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 317, 0, 1229, 0, 0, 0, 0, 0, 0, 224, - 0, 0, 0, 0, 275, 221, 0, 0, 331, 0, - 176, 0, 369, 209, 284, 282, 398, 235, 227, 223, - 208, 259, 290, 329, 387, 323, 0, 279, 0, 0, - 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 265, 207, 175, - 314, 379, 239, 0, 0, 0, 167, 168, 169, 0, - 0, 0, 0, 0, 0, 0, 0, 198, 0, 205, - 0, 0, 0, 0, 219, 263, 226, 218, 395, 0, - 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, + 0, 0, 247, 0, 303, 0, 0, 0, 0, 427, + 0, 0, 0, 0, 0, 0, 0, 274, 0, 271, + 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, + 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, + 0, 0, 355, 280, 400, 344, 410, 428, 429, 217, + 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, + 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, + 186, 364, 202, 179, 386, 408, 199, 367, 0, 0, + 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, + 222, 243, 212, 316, 403, 404, 211, 442, 190, 423, + 183, 0, 422, 309, 399, 407, 298, 289, 182, 405, + 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, + 304, 306, 0, 177, 0, 380, 416, 443, 195, 196, + 197, 0, 232, 236, 242, 244, 250, 251, 258, 276, + 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, + 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, + 0, 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 170, 184, 277, + 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 247, 0, 303, - 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, - 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, - 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, - 194, 237, 349, 332, 354, 0, 0, 355, 280, 400, - 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, - 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, - 374, 245, 174, 278, 436, 186, 364, 202, 179, 386, - 408, 199, 367, 0, 0, 441, 181, 406, 383, 297, - 267, 268, 180, 0, 348, 222, 243, 212, 316, 403, - 404, 211, 442, 190, 423, 183, 0, 422, 309, 399, - 407, 298, 289, 182, 405, 296, 288, 273, 233, 254, - 342, 283, 343, 255, 305, 304, 306, 0, 177, 0, - 380, 416, 443, 195, 196, 197, 0, 232, 236, 242, - 244, 250, 251, 258, 276, 320, 341, 339, 345, 0, - 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, - 308, 257, 376, 272, 281, 0, 0, 326, 357, 200, - 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 172, 173, 185, 193, 203, 215, 230, 238, 248, + 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, + 294, 310, 311, 312, 315, 318, 319, 322, 324, 325, + 328, 334, 335, 336, 337, 338, 340, 347, 351, 359, + 360, 361, 362, 363, 365, 366, 370, 371, 372, 373, + 381, 385, 401, 402, 413, 425, 430, 249, 409, 431, + 0, 285, 0, 0, 287, 234, 252, 262, 0, 420, + 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, + 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, + 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 317, + 0, 1233, 0, 0, 0, 0, 0, 0, 224, 0, + 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, + 0, 369, 209, 284, 282, 398, 235, 227, 223, 208, + 259, 290, 329, 387, 323, 0, 279, 0, 0, 378, + 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 265, 207, 175, 314, + 379, 239, 0, 0, 0, 167, 168, 169, 0, 0, + 0, 0, 0, 0, 0, 0, 198, 0, 205, 0, + 0, 0, 0, 219, 263, 226, 218, 395, 0, 0, + 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 170, 184, 277, 0, 346, 240, 440, 421, - 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 172, 173, 185, 193, - 203, 215, 230, 238, 248, 253, 256, 260, 261, 264, - 269, 286, 291, 292, 293, 294, 310, 311, 312, 315, - 318, 319, 322, 324, 325, 328, 334, 335, 336, 337, - 338, 340, 347, 351, 359, 360, 361, 362, 363, 365, - 366, 370, 371, 372, 373, 381, 385, 401, 402, 413, - 425, 430, 249, 409, 431, 0, 285, 0, 0, 287, - 234, 252, 262, 0, 420, 382, 189, 353, 241, 178, - 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, - 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, - 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 317, 0, 1227, 0, 0, 0, - 0, 0, 0, 224, 0, 0, 0, 0, 275, 221, - 0, 0, 331, 0, 176, 0, 369, 209, 284, 282, - 398, 235, 227, 223, 208, 259, 290, 329, 387, 323, - 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 265, 207, 175, 314, 379, 239, 0, 0, 0, - 167, 168, 169, 0, 0, 0, 0, 0, 0, 0, - 0, 198, 0, 205, 0, 0, 0, 0, 219, 263, - 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 229, + 0, 0, 0, 0, 0, 0, 247, 0, 303, 0, + 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, + 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, + 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, + 237, 349, 332, 354, 0, 0, 355, 280, 400, 344, + 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, + 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, + 245, 174, 278, 436, 186, 364, 202, 179, 386, 408, + 199, 367, 0, 0, 441, 181, 406, 383, 297, 267, + 268, 180, 0, 348, 222, 243, 212, 316, 403, 404, + 211, 442, 190, 423, 183, 0, 422, 309, 399, 407, + 298, 289, 182, 405, 296, 288, 273, 233, 254, 342, + 283, 343, 255, 305, 304, 306, 0, 177, 0, 380, + 416, 443, 195, 196, 197, 0, 232, 236, 242, 244, + 250, 251, 258, 276, 320, 341, 339, 345, 0, 394, + 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, + 257, 376, 272, 281, 0, 0, 326, 357, 200, 414, + 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 170, 184, 277, 0, 346, 240, 440, 421, 417, + 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 172, 173, 185, 193, 203, + 215, 230, 238, 248, 253, 256, 260, 261, 264, 269, + 286, 291, 292, 293, 294, 310, 311, 312, 315, 318, + 319, 322, 324, 325, 328, 334, 335, 336, 337, 338, + 340, 347, 351, 359, 360, 361, 362, 363, 365, 366, + 370, 371, 372, 373, 381, 385, 401, 402, 413, 425, + 430, 249, 409, 431, 0, 285, 0, 0, 287, 234, + 252, 262, 0, 420, 382, 189, 353, 241, 178, 206, + 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, + 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, + 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 317, 0, 1231, 0, 0, 0, 0, + 0, 0, 224, 0, 0, 0, 0, 275, 221, 0, + 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, + 235, 227, 223, 208, 259, 290, 329, 387, 323, 0, + 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, + 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, + 198, 0, 205, 0, 0, 0, 0, 219, 263, 226, + 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 247, 0, 303, 0, 0, 0, 0, 427, 0, - 0, 0, 0, 0, 0, 0, 274, 0, 271, 171, - 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, - 0, 356, 327, 412, 194, 237, 349, 332, 354, 0, - 0, 355, 280, 400, 344, 410, 428, 429, 217, 307, - 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, - 300, 396, 397, 270, 374, 245, 174, 278, 436, 186, - 364, 202, 179, 386, 408, 199, 367, 0, 0, 441, - 181, 406, 383, 297, 267, 268, 180, 0, 348, 222, - 243, 212, 316, 403, 404, 211, 442, 190, 423, 183, - 0, 422, 309, 399, 407, 298, 289, 182, 405, 296, - 288, 273, 233, 254, 342, 283, 343, 255, 305, 304, - 306, 0, 177, 0, 380, 416, 443, 195, 196, 197, - 0, 232, 236, 242, 244, 250, 251, 258, 276, 320, - 341, 339, 345, 0, 394, 411, 419, 426, 432, 433, - 437, 434, 435, 438, 308, 257, 376, 272, 281, 0, - 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 170, 184, 277, 0, - 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, + 247, 0, 303, 0, 0, 0, 0, 427, 0, 0, + 0, 0, 0, 0, 0, 274, 0, 271, 171, 187, + 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, + 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, + 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, + 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, + 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, + 202, 179, 386, 408, 199, 367, 0, 0, 441, 181, + 406, 383, 297, 267, 268, 180, 0, 348, 222, 243, + 212, 316, 403, 404, 211, 442, 190, 423, 183, 0, + 422, 309, 399, 407, 298, 289, 182, 405, 296, 288, + 273, 233, 254, 342, 283, 343, 255, 305, 304, 306, + 0, 177, 0, 380, 416, 443, 195, 196, 197, 0, + 232, 236, 242, 244, 250, 251, 258, 276, 320, 341, + 339, 345, 0, 394, 411, 419, 426, 432, 433, 437, + 434, 435, 438, 308, 257, 376, 272, 281, 0, 0, + 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 170, 184, 277, 0, 346, + 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 172, 173, 185, 193, 203, 215, 230, 238, 248, 253, - 256, 260, 261, 264, 269, 286, 291, 292, 293, 294, - 310, 311, 312, 315, 318, 319, 322, 324, 325, 328, - 334, 335, 336, 337, 338, 340, 347, 351, 359, 360, - 361, 362, 363, 365, 366, 370, 371, 372, 373, 381, - 385, 401, 402, 413, 425, 430, 249, 409, 431, 0, - 285, 0, 0, 287, 234, 252, 262, 0, 420, 382, - 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, - 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, - 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 317, 0, - 1225, 0, 0, 0, 0, 0, 0, 224, 0, 0, - 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, - 369, 209, 284, 282, 398, 235, 227, 223, 208, 259, - 290, 329, 387, 323, 0, 279, 0, 0, 378, 302, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, + 173, 185, 193, 203, 215, 230, 238, 248, 253, 256, + 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, + 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, + 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, + 362, 363, 365, 366, 370, 371, 372, 373, 381, 385, + 401, 402, 413, 425, 430, 249, 409, 431, 0, 285, + 0, 0, 287, 234, 252, 262, 0, 420, 382, 189, + 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, + 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, + 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 317, 0, 1229, + 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, + 0, 275, 221, 0, 0, 331, 0, 176, 0, 369, + 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, + 329, 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 265, 207, 175, 314, 379, - 239, 0, 0, 0, 167, 168, 169, 0, 0, 0, - 0, 0, 0, 0, 0, 198, 0, 205, 0, 0, - 0, 0, 219, 263, 226, 218, 395, 0, 0, 0, - 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 265, 207, 175, 314, 379, 239, + 0, 0, 0, 167, 168, 169, 0, 0, 0, 0, + 0, 0, 0, 0, 198, 0, 205, 0, 0, 0, + 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 247, 0, 303, 0, 0, - 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, - 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, - 0, 0, 0, 210, 0, 356, 327, 412, 194, 237, - 349, 332, 354, 0, 0, 355, 280, 400, 344, 410, - 428, 429, 217, 307, 418, 391, 424, 439, 188, 214, - 321, 384, 415, 375, 300, 396, 397, 270, 374, 245, - 174, 278, 436, 186, 364, 202, 179, 386, 408, 199, - 367, 0, 0, 441, 181, 406, 383, 297, 267, 268, - 180, 0, 348, 222, 243, 212, 316, 403, 404, 211, - 442, 190, 423, 183, 0, 422, 309, 399, 407, 298, - 289, 182, 405, 296, 288, 273, 233, 254, 342, 283, - 343, 255, 305, 304, 306, 0, 177, 0, 380, 416, - 443, 195, 196, 197, 0, 232, 236, 242, 244, 250, - 251, 258, 276, 320, 341, 339, 345, 0, 394, 411, - 419, 426, 432, 433, 437, 434, 435, 438, 308, 257, - 376, 272, 281, 0, 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 247, 0, 303, 0, 0, 0, + 0, 427, 0, 0, 0, 0, 0, 0, 0, 274, + 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, + 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, + 332, 354, 0, 0, 355, 280, 400, 344, 410, 428, + 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, + 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, + 278, 436, 186, 364, 202, 179, 386, 408, 199, 367, + 0, 0, 441, 181, 406, 383, 297, 267, 268, 180, + 0, 348, 222, 243, 212, 316, 403, 404, 211, 442, + 190, 423, 183, 0, 422, 309, 399, 407, 298, 289, + 182, 405, 296, 288, 273, 233, 254, 342, 283, 343, + 255, 305, 304, 306, 0, 177, 0, 380, 416, 443, + 195, 196, 197, 0, 232, 236, 242, 244, 250, 251, + 258, 276, 320, 341, 339, 345, 0, 394, 411, 419, + 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, + 272, 281, 0, 0, 326, 357, 200, 414, 377, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, + 184, 277, 0, 346, 240, 440, 421, 417, 0, 0, + 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 172, 173, 185, 193, 203, 215, 230, + 238, 248, 253, 256, 260, 261, 264, 269, 286, 291, + 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, + 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, + 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, + 372, 373, 381, 385, 401, 402, 413, 425, 430, 249, + 409, 431, 0, 285, 0, 0, 287, 234, 252, 262, + 0, 420, 382, 189, 353, 241, 178, 206, 192, 213, + 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, + 350, 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 170, 184, 277, 0, 346, 240, 440, 421, 417, 0, - 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 317, 0, 1227, 0, 0, 0, 0, 0, 0, + 224, 0, 0, 0, 0, 275, 221, 0, 0, 331, + 0, 176, 0, 369, 209, 284, 282, 398, 235, 227, + 223, 208, 259, 290, 329, 387, 323, 0, 279, 0, + 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 265, 207, + 175, 314, 379, 239, 0, 0, 0, 167, 168, 169, + 0, 0, 0, 0, 0, 0, 0, 0, 198, 0, + 205, 0, 0, 0, 0, 219, 263, 226, 218, 395, + 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 172, 173, 185, 193, 203, 215, - 230, 238, 248, 253, 256, 260, 261, 264, 269, 286, - 291, 292, 293, 294, 310, 311, 312, 315, 318, 319, - 322, 324, 325, 328, 334, 335, 336, 337, 338, 340, - 347, 351, 359, 360, 361, 362, 363, 365, 366, 370, - 371, 372, 373, 381, 385, 401, 402, 413, 425, 430, - 249, 409, 431, 0, 285, 0, 0, 287, 234, 252, - 262, 0, 420, 382, 189, 353, 241, 178, 206, 192, - 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, - 204, 350, 201, 368, 388, 389, 390, 392, 299, 220, - 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 317, 0, 1221, 0, 0, 0, 0, 0, - 0, 224, 0, 0, 0, 0, 275, 221, 0, 0, - 331, 0, 176, 0, 369, 209, 284, 282, 398, 235, - 227, 223, 208, 259, 290, 329, 387, 323, 0, 279, - 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 265, - 207, 175, 314, 379, 239, 0, 0, 0, 167, 168, - 169, 0, 0, 0, 0, 0, 0, 0, 0, 198, - 0, 205, 0, 0, 0, 0, 219, 263, 226, 218, - 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, + 303, 0, 0, 0, 0, 427, 0, 0, 0, 0, + 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, + 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, + 412, 194, 237, 349, 332, 354, 0, 0, 355, 280, + 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, + 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, + 270, 374, 245, 174, 278, 436, 186, 364, 202, 179, + 386, 408, 199, 367, 0, 0, 441, 181, 406, 383, + 297, 267, 268, 180, 0, 348, 222, 243, 212, 316, + 403, 404, 211, 442, 190, 423, 183, 0, 422, 309, + 399, 407, 298, 289, 182, 405, 296, 288, 273, 233, + 254, 342, 283, 343, 255, 305, 304, 306, 0, 177, + 0, 380, 416, 443, 195, 196, 197, 0, 232, 236, + 242, 244, 250, 251, 258, 276, 320, 341, 339, 345, + 0, 394, 411, 419, 426, 432, 433, 437, 434, 435, + 438, 308, 257, 376, 272, 281, 0, 0, 326, 357, + 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, - 0, 303, 0, 0, 0, 0, 427, 0, 0, 0, - 0, 0, 0, 0, 274, 0, 271, 171, 187, 0, - 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, - 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, - 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, - 424, 439, 188, 214, 321, 384, 415, 375, 300, 396, - 397, 270, 374, 245, 174, 278, 436, 186, 364, 202, - 179, 386, 408, 199, 367, 0, 0, 441, 181, 406, - 383, 297, 267, 268, 180, 0, 348, 222, 243, 212, - 316, 403, 404, 211, 442, 190, 423, 183, 0, 422, - 309, 399, 407, 298, 289, 182, 405, 296, 288, 273, - 233, 254, 342, 283, 343, 255, 305, 304, 306, 0, - 177, 0, 380, 416, 443, 195, 196, 197, 0, 232, - 236, 242, 244, 250, 251, 258, 276, 320, 341, 339, - 345, 0, 394, 411, 419, 426, 432, 433, 437, 434, - 435, 438, 308, 257, 376, 272, 281, 0, 0, 326, - 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 170, 184, 277, 0, 346, 240, 440, + 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 170, 184, 277, 0, 346, 240, - 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 172, 173, 185, + 193, 203, 215, 230, 238, 248, 253, 256, 260, 261, + 264, 269, 286, 291, 292, 293, 294, 310, 311, 312, + 315, 318, 319, 322, 324, 325, 328, 334, 335, 336, + 337, 338, 340, 347, 351, 359, 360, 361, 362, 363, + 365, 366, 370, 371, 372, 373, 381, 385, 401, 402, + 413, 425, 430, 249, 409, 431, 0, 285, 0, 0, + 287, 234, 252, 262, 0, 420, 382, 189, 353, 241, + 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, + 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, + 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 317, 0, 1223, 0, 0, + 0, 0, 0, 0, 224, 0, 0, 0, 0, 275, + 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, + 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, + 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, - 185, 193, 203, 215, 230, 238, 248, 253, 256, 260, - 261, 264, 269, 286, 291, 292, 293, 294, 310, 311, - 312, 315, 318, 319, 322, 324, 325, 328, 334, 335, - 336, 337, 338, 340, 347, 351, 359, 360, 361, 362, - 363, 365, 366, 370, 371, 372, 373, 381, 385, 401, - 402, 413, 425, 430, 249, 409, 431, 0, 285, 0, - 0, 287, 234, 252, 262, 0, 420, 382, 189, 353, - 241, 178, 206, 192, 213, 228, 231, 266, 295, 301, - 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, - 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 317, 0, 1219, 0, - 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, - 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, - 284, 282, 398, 235, 227, 223, 208, 259, 290, 329, - 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, + 0, 0, 265, 207, 175, 314, 379, 239, 0, 0, + 0, 167, 168, 169, 0, 0, 0, 0, 0, 0, + 0, 0, 198, 0, 205, 0, 0, 0, 0, 219, + 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 265, 207, 175, 314, 379, 239, 0, - 0, 0, 167, 168, 169, 0, 0, 0, 0, 0, - 0, 0, 0, 198, 0, 205, 0, 0, 0, 0, - 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, + 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 247, 0, 303, 0, 0, 0, 0, 427, + 0, 0, 0, 0, 0, 0, 0, 274, 0, 271, + 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, + 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, + 0, 0, 355, 280, 400, 344, 410, 428, 429, 217, + 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, + 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, + 186, 364, 202, 179, 386, 408, 199, 367, 0, 0, + 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, + 222, 243, 212, 316, 403, 404, 211, 442, 190, 423, + 183, 0, 422, 309, 399, 407, 298, 289, 182, 405, + 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, + 304, 306, 0, 177, 0, 380, 416, 443, 195, 196, + 197, 0, 232, 236, 242, 244, 250, 251, 258, 276, + 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, + 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, + 0, 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 247, 0, 303, 0, 0, 0, 0, - 427, 0, 0, 0, 0, 0, 0, 0, 274, 0, - 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, - 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, - 354, 0, 0, 355, 280, 400, 344, 410, 428, 429, - 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, - 415, 375, 300, 396, 397, 270, 374, 245, 174, 278, - 436, 186, 364, 202, 179, 386, 408, 199, 367, 0, - 0, 441, 181, 406, 383, 297, 267, 268, 180, 0, - 348, 222, 243, 212, 316, 403, 404, 211, 442, 190, - 423, 183, 0, 422, 309, 399, 407, 298, 289, 182, - 405, 296, 288, 273, 233, 254, 342, 283, 343, 255, - 305, 304, 306, 0, 177, 0, 380, 416, 443, 195, - 196, 197, 0, 232, 236, 242, 244, 250, 251, 258, - 276, 320, 341, 339, 345, 0, 394, 411, 419, 426, - 432, 433, 437, 434, 435, 438, 308, 257, 376, 272, - 281, 0, 0, 326, 357, 200, 414, 377, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 170, 184, 277, + 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 170, 184, - 277, 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 172, 173, 185, 193, 203, 215, 230, 238, 248, + 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, + 294, 310, 311, 312, 315, 318, 319, 322, 324, 325, + 328, 334, 335, 336, 337, 338, 340, 347, 351, 359, + 360, 361, 362, 363, 365, 366, 370, 371, 372, 373, + 381, 385, 401, 402, 413, 425, 430, 249, 409, 431, + 0, 285, 0, 0, 287, 234, 252, 262, 0, 420, + 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, + 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, + 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 317, + 0, 1221, 0, 0, 0, 0, 0, 0, 224, 0, + 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, + 0, 369, 209, 284, 282, 398, 235, 227, 223, 208, + 259, 290, 329, 387, 323, 0, 279, 0, 0, 378, + 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 265, 207, 175, 314, + 379, 239, 0, 0, 0, 167, 168, 169, 0, 0, + 0, 0, 0, 0, 0, 0, 198, 0, 205, 0, + 0, 0, 0, 219, 263, 226, 218, 395, 0, 0, + 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 172, 173, 185, 193, 203, 215, 230, 238, - 248, 253, 256, 260, 261, 264, 269, 286, 291, 292, - 293, 294, 310, 311, 312, 315, 318, 319, 322, 324, - 325, 328, 334, 335, 336, 337, 338, 340, 347, 351, - 359, 360, 361, 362, 363, 365, 366, 370, 371, 372, - 373, 381, 385, 401, 402, 413, 425, 430, 249, 409, - 431, 0, 285, 0, 0, 287, 234, 252, 262, 0, - 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, - 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, - 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 317, 0, 1217, 0, 0, 0, 0, 0, 0, 224, - 0, 0, 0, 0, 275, 221, 0, 0, 331, 0, - 176, 0, 369, 209, 284, 282, 398, 235, 227, 223, - 208, 259, 290, 329, 387, 323, 0, 279, 0, 0, - 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 265, 207, 175, - 314, 379, 239, 0, 0, 0, 167, 168, 169, 0, - 0, 0, 0, 0, 0, 0, 0, 198, 0, 205, - 0, 0, 0, 0, 219, 263, 226, 218, 395, 0, - 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 247, 0, 303, 0, + 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, + 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, + 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, + 237, 349, 332, 354, 0, 0, 355, 280, 400, 344, + 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, + 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, + 245, 174, 278, 436, 186, 364, 202, 179, 386, 408, + 199, 367, 0, 0, 441, 181, 406, 383, 297, 267, + 268, 180, 0, 348, 222, 243, 212, 316, 403, 404, + 211, 442, 190, 423, 183, 0, 422, 309, 399, 407, + 298, 289, 182, 405, 296, 288, 273, 233, 254, 342, + 283, 343, 255, 305, 304, 306, 0, 177, 0, 380, + 416, 443, 195, 196, 197, 0, 232, 236, 242, 244, + 250, 251, 258, 276, 320, 341, 339, 345, 0, 394, + 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, + 257, 376, 272, 281, 0, 0, 326, 357, 200, 414, + 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 170, 184, 277, 0, 346, 240, 440, 421, 417, + 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 247, 0, 303, - 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, - 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, - 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, - 194, 237, 349, 332, 354, 0, 0, 355, 280, 400, - 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, - 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, - 374, 245, 174, 278, 436, 186, 364, 202, 179, 386, - 408, 199, 367, 0, 0, 441, 181, 406, 383, 297, - 267, 268, 180, 0, 348, 222, 243, 212, 316, 403, - 404, 211, 442, 190, 423, 183, 0, 422, 309, 399, - 407, 298, 289, 182, 405, 296, 288, 273, 233, 254, - 342, 283, 343, 255, 305, 304, 306, 0, 177, 0, - 380, 416, 443, 195, 196, 197, 0, 232, 236, 242, - 244, 250, 251, 258, 276, 320, 341, 339, 345, 0, - 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, - 308, 257, 376, 272, 281, 0, 0, 326, 357, 200, - 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 172, 173, 185, 193, 203, + 215, 230, 238, 248, 253, 256, 260, 261, 264, 269, + 286, 291, 292, 293, 294, 310, 311, 312, 315, 318, + 319, 322, 324, 325, 328, 334, 335, 336, 337, 338, + 340, 347, 351, 359, 360, 361, 362, 363, 365, 366, + 370, 371, 372, 373, 381, 385, 401, 402, 413, 425, + 430, 249, 409, 431, 0, 285, 0, 0, 287, 234, + 252, 262, 0, 420, 382, 189, 353, 241, 178, 206, + 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, + 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, + 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 317, 0, 1219, 0, 0, 0, 0, + 0, 0, 224, 0, 0, 0, 0, 275, 221, 0, + 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, + 235, 227, 223, 208, 259, 290, 329, 387, 323, 0, + 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 170, 184, 277, 0, 346, 240, 440, 421, - 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, + 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, + 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, + 198, 0, 205, 0, 0, 0, 0, 219, 263, 226, + 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 172, 173, 185, 193, - 203, 215, 230, 238, 248, 253, 256, 260, 261, 264, - 269, 286, 291, 292, 293, 294, 310, 311, 312, 315, - 318, 319, 322, 324, 325, 328, 334, 335, 336, 337, - 338, 340, 347, 351, 359, 360, 361, 362, 363, 365, - 366, 370, 371, 372, 373, 381, 385, 401, 402, 413, - 425, 430, 249, 409, 431, 0, 285, 0, 0, 287, - 234, 252, 262, 0, 420, 382, 189, 353, 241, 178, - 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, - 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, - 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 317, 0, 0, 0, 0, 0, - 0, 0, 0, 224, 0, 0, 0, 0, 275, 221, - 0, 0, 331, 0, 176, 0, 369, 209, 284, 282, - 398, 235, 227, 223, 208, 259, 290, 329, 387, 323, - 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 265, 207, 175, 314, 379, 239, 1192, 0, 0, - 167, 168, 169, 0, 0, 0, 0, 0, 0, 0, - 0, 198, 0, 205, 0, 0, 0, 0, 219, 263, - 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 247, 0, 303, 0, 0, 0, 0, 427, 0, 0, + 0, 0, 0, 0, 0, 274, 0, 271, 171, 187, + 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, + 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, + 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, + 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, + 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, + 202, 179, 386, 408, 199, 367, 0, 0, 441, 181, + 406, 383, 297, 267, 268, 180, 0, 348, 222, 243, + 212, 316, 403, 404, 211, 442, 190, 423, 183, 0, + 422, 309, 399, 407, 298, 289, 182, 405, 296, 288, + 273, 233, 254, 342, 283, 343, 255, 305, 304, 306, + 0, 177, 0, 380, 416, 443, 195, 196, 197, 0, + 232, 236, 242, 244, 250, 251, 258, 276, 320, 341, + 339, 345, 0, 394, 411, 419, 426, 432, 433, 437, + 434, 435, 438, 308, 257, 376, 272, 281, 0, 0, + 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 170, 184, 277, 0, 346, + 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 247, 0, 303, 0, 0, 0, 0, 427, 0, - 0, 0, 0, 0, 0, 0, 274, 0, 271, 171, - 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, - 0, 356, 327, 412, 194, 237, 349, 332, 354, 0, - 0, 355, 280, 400, 344, 410, 428, 429, 217, 307, - 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, - 300, 396, 397, 270, 374, 245, 174, 278, 436, 186, - 364, 202, 179, 386, 408, 199, 367, 0, 0, 441, - 181, 406, 383, 297, 267, 268, 180, 0, 348, 222, - 243, 212, 316, 403, 404, 211, 442, 190, 423, 183, - 0, 422, 309, 399, 407, 298, 289, 182, 405, 296, - 288, 273, 233, 254, 342, 283, 343, 255, 305, 304, - 306, 0, 177, 0, 380, 416, 443, 195, 196, 197, - 0, 232, 236, 242, 244, 250, 251, 258, 276, 320, - 341, 339, 345, 0, 394, 411, 419, 426, 432, 433, - 437, 434, 435, 438, 308, 257, 376, 272, 281, 0, - 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, + 173, 185, 193, 203, 215, 230, 238, 248, 253, 256, + 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, + 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, + 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, + 362, 363, 365, 366, 370, 371, 372, 373, 381, 385, + 401, 402, 413, 425, 430, 249, 409, 431, 0, 285, + 0, 0, 287, 234, 252, 262, 0, 420, 382, 189, + 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, + 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, + 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 317, 0, 0, + 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, + 0, 275, 221, 0, 0, 331, 0, 176, 0, 369, + 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, + 329, 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 170, 184, 277, 0, - 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, + 0, 0, 0, 0, 265, 207, 175, 314, 379, 239, + 1194, 0, 0, 167, 168, 169, 0, 0, 0, 0, + 0, 0, 0, 0, 198, 0, 205, 0, 0, 0, + 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 172, 173, 185, 193, 203, 215, 230, 238, 248, 253, - 256, 260, 261, 264, 269, 286, 291, 292, 293, 294, - 310, 311, 312, 315, 318, 319, 322, 324, 325, 328, - 334, 335, 336, 337, 338, 340, 347, 351, 359, 360, - 361, 362, 363, 365, 366, 370, 371, 372, 373, 381, - 385, 401, 402, 413, 425, 430, 249, 409, 431, 0, - 285, 0, 0, 287, 234, 252, 262, 0, 420, 382, - 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, - 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, - 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, - 0, 1093, 0, 0, 0, 0, 0, 0, 317, 0, - 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, - 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, - 369, 209, 284, 282, 398, 235, 227, 223, 208, 259, - 290, 329, 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 265, 207, 175, 314, 379, - 239, 0, 0, 0, 167, 168, 169, 0, 0, 0, - 0, 0, 0, 0, 0, 198, 0, 205, 0, 0, - 0, 0, 219, 263, 226, 218, 395, 0, 0, 0, - 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 247, 0, 303, 0, 0, 0, + 0, 427, 0, 0, 0, 0, 0, 0, 0, 274, + 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, + 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, + 332, 354, 0, 0, 355, 280, 400, 344, 410, 428, + 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, + 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, + 278, 436, 186, 364, 202, 179, 386, 408, 199, 367, + 0, 0, 441, 181, 406, 383, 297, 267, 268, 180, + 0, 348, 222, 243, 212, 316, 403, 404, 211, 442, + 190, 423, 183, 0, 422, 309, 399, 407, 298, 289, + 182, 405, 296, 288, 273, 233, 254, 342, 283, 343, + 255, 305, 304, 306, 0, 177, 0, 380, 416, 443, + 195, 196, 197, 0, 232, 236, 242, 244, 250, 251, + 258, 276, 320, 341, 339, 345, 0, 394, 411, 419, + 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, + 272, 281, 0, 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, + 184, 277, 0, 346, 240, 440, 421, 417, 0, 0, + 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 247, 0, 303, 0, 0, - 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, - 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, - 0, 0, 0, 210, 0, 356, 327, 412, 194, 237, - 349, 332, 354, 0, 0, 355, 280, 400, 344, 410, - 428, 429, 217, 307, 418, 391, 424, 439, 188, 214, - 321, 384, 415, 375, 300, 396, 397, 270, 374, 245, - 174, 278, 436, 186, 364, 202, 179, 386, 408, 199, - 367, 0, 0, 441, 181, 406, 383, 297, 267, 268, - 180, 0, 348, 222, 243, 212, 316, 403, 404, 211, - 442, 190, 423, 183, 0, 422, 309, 399, 407, 298, - 289, 182, 405, 296, 288, 273, 233, 254, 342, 283, - 343, 255, 305, 304, 306, 0, 177, 0, 380, 416, - 443, 195, 196, 197, 0, 232, 236, 242, 244, 250, - 251, 258, 276, 320, 341, 339, 345, 0, 394, 411, - 419, 426, 432, 433, 437, 434, 435, 438, 308, 257, - 376, 272, 281, 0, 0, 326, 357, 200, 414, 377, + 0, 0, 0, 172, 173, 185, 193, 203, 215, 230, + 238, 248, 253, 256, 260, 261, 264, 269, 286, 291, + 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, + 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, + 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, + 372, 373, 381, 385, 401, 402, 413, 425, 430, 249, + 409, 431, 0, 285, 0, 0, 287, 234, 252, 262, + 0, 420, 382, 189, 353, 241, 178, 206, 192, 213, + 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, + 350, 201, 368, 388, 389, 390, 392, 299, 220, 393, + 0, 0, 0, 0, 1095, 0, 0, 0, 0, 0, + 0, 317, 0, 0, 0, 0, 0, 0, 0, 0, + 224, 0, 0, 0, 0, 275, 221, 0, 0, 331, + 0, 176, 0, 369, 209, 284, 282, 398, 235, 227, + 223, 208, 259, 290, 329, 387, 323, 0, 279, 0, + 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 265, 207, + 175, 314, 379, 239, 0, 0, 0, 167, 168, 169, + 0, 0, 0, 0, 0, 0, 0, 0, 198, 0, + 205, 0, 0, 0, 0, 219, 263, 226, 218, 395, + 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 170, 184, 277, 0, 346, 240, 440, 421, 417, 0, - 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 172, 173, 185, 193, 203, 215, - 230, 238, 248, 253, 256, 260, 261, 264, 269, 286, - 291, 292, 293, 294, 310, 311, 312, 315, 318, 319, - 322, 324, 325, 328, 334, 335, 336, 337, 338, 340, - 347, 351, 359, 360, 361, 362, 363, 365, 366, 370, - 371, 372, 373, 381, 385, 401, 402, 413, 425, 430, - 249, 409, 431, 0, 285, 0, 0, 287, 234, 252, - 262, 0, 420, 382, 189, 353, 241, 178, 206, 192, - 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, - 204, 350, 201, 368, 388, 389, 390, 392, 299, 220, - 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 317, 0, 0, 0, 0, 0, 0, 0, - 1084, 224, 0, 0, 0, 0, 275, 221, 0, 0, - 331, 0, 176, 0, 369, 209, 284, 282, 398, 235, - 227, 223, 208, 259, 290, 329, 387, 323, 0, 279, - 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 265, - 207, 175, 314, 379, 239, 0, 0, 0, 167, 168, - 169, 0, 0, 0, 0, 0, 0, 0, 0, 198, - 0, 205, 0, 0, 0, 0, 219, 263, 226, 218, - 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, + 303, 0, 0, 0, 0, 427, 0, 0, 0, 0, + 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, + 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, + 412, 194, 237, 349, 332, 354, 0, 0, 355, 280, + 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, + 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, + 270, 374, 245, 174, 278, 436, 186, 364, 202, 179, + 386, 408, 199, 367, 0, 0, 441, 181, 406, 383, + 297, 267, 268, 180, 0, 348, 222, 243, 212, 316, + 403, 404, 211, 442, 190, 423, 183, 0, 422, 309, + 399, 407, 298, 289, 182, 405, 296, 288, 273, 233, + 254, 342, 283, 343, 255, 305, 304, 306, 0, 177, + 0, 380, 416, 443, 195, 196, 197, 0, 232, 236, + 242, 244, 250, 251, 258, 276, 320, 341, 339, 345, + 0, 394, 411, 419, 426, 432, 433, 437, 434, 435, + 438, 308, 257, 376, 272, 281, 0, 0, 326, 357, + 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 170, 184, 277, 0, 346, 240, 440, + 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 172, 173, 185, + 193, 203, 215, 230, 238, 248, 253, 256, 260, 261, + 264, 269, 286, 291, 292, 293, 294, 310, 311, 312, + 315, 318, 319, 322, 324, 325, 328, 334, 335, 336, + 337, 338, 340, 347, 351, 359, 360, 361, 362, 363, + 365, 366, 370, 371, 372, 373, 381, 385, 401, 402, + 413, 425, 430, 249, 409, 431, 0, 285, 0, 0, + 287, 234, 252, 262, 0, 420, 382, 189, 353, 241, + 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, + 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, + 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 317, 0, 0, 0, 0, + 0, 0, 0, 1086, 224, 0, 0, 0, 0, 275, + 221, 0, 0, 331, 0, 176, 0, 369, 209, 284, + 282, 398, 235, 227, 223, 208, 259, 290, 329, 387, + 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, - 0, 303, 0, 0, 0, 0, 427, 0, 0, 0, - 0, 0, 0, 0, 274, 0, 271, 171, 187, 0, - 0, 313, 352, 358, 0, 0, 0, 210, 0, 356, - 327, 412, 194, 237, 349, 332, 354, 0, 0, 355, - 280, 400, 344, 410, 428, 429, 217, 307, 418, 391, - 424, 439, 188, 214, 321, 384, 415, 375, 300, 396, - 397, 270, 374, 245, 174, 278, 436, 186, 364, 202, - 179, 386, 408, 199, 367, 0, 0, 441, 181, 406, - 383, 297, 267, 268, 180, 0, 348, 222, 243, 212, - 316, 403, 404, 211, 442, 190, 423, 183, 0, 422, - 309, 399, 407, 298, 289, 182, 405, 296, 288, 273, - 233, 254, 342, 283, 343, 255, 305, 304, 306, 0, - 177, 0, 380, 416, 443, 195, 196, 197, 0, 232, - 236, 242, 244, 250, 251, 258, 276, 320, 341, 339, - 345, 0, 394, 411, 419, 426, 432, 433, 437, 434, - 435, 438, 308, 257, 376, 272, 281, 0, 0, 326, - 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, + 0, 0, 265, 207, 175, 314, 379, 239, 0, 0, + 0, 167, 168, 169, 0, 0, 0, 0, 0, 0, + 0, 0, 198, 0, 205, 0, 0, 0, 0, 219, + 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 170, 184, 277, 0, 346, 240, - 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, + 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 172, 173, - 185, 193, 203, 215, 230, 238, 248, 253, 256, 260, - 261, 264, 269, 286, 291, 292, 293, 294, 310, 311, - 312, 315, 318, 319, 322, 324, 325, 328, 334, 335, - 336, 337, 338, 340, 347, 351, 359, 360, 361, 362, - 363, 365, 366, 370, 371, 372, 373, 381, 385, 401, - 402, 413, 425, 430, 249, 409, 431, 0, 285, 0, - 0, 287, 234, 252, 262, 0, 420, 382, 189, 353, - 241, 178, 206, 192, 213, 228, 231, 266, 295, 301, - 330, 333, 246, 225, 204, 350, 201, 368, 388, 389, - 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, - 0, 0, 0, 0, 0, 224, 0, 0, 0, 0, - 275, 221, 0, 0, 331, 0, 176, 0, 369, 209, - 284, 282, 398, 235, 227, 223, 208, 259, 290, 329, - 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 265, 207, 175, 314, 379, 239, 0, - 0, 0, 167, 168, 169, 0, 940, 0, 0, 0, - 0, 0, 0, 198, 0, 205, 0, 0, 0, 0, - 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 247, 0, 303, 0, 0, 0, 0, 427, + 0, 0, 0, 0, 0, 0, 0, 274, 0, 271, + 171, 187, 0, 0, 313, 352, 358, 0, 0, 0, + 210, 0, 356, 327, 412, 194, 237, 349, 332, 354, + 0, 0, 355, 280, 400, 344, 410, 428, 429, 217, + 307, 418, 391, 424, 439, 188, 214, 321, 384, 415, + 375, 300, 396, 397, 270, 374, 245, 174, 278, 436, + 186, 364, 202, 179, 386, 408, 199, 367, 0, 0, + 441, 181, 406, 383, 297, 267, 268, 180, 0, 348, + 222, 243, 212, 316, 403, 404, 211, 442, 190, 423, + 183, 0, 422, 309, 399, 407, 298, 289, 182, 405, + 296, 288, 273, 233, 254, 342, 283, 343, 255, 305, + 304, 306, 0, 177, 0, 380, 416, 443, 195, 196, + 197, 0, 232, 236, 242, 244, 250, 251, 258, 276, + 320, 341, 339, 345, 0, 394, 411, 419, 426, 432, + 433, 437, 434, 435, 438, 308, 257, 376, 272, 281, + 0, 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 170, 184, 277, + 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 247, 0, 303, 0, 0, 0, 0, - 427, 0, 0, 0, 0, 0, 0, 0, 274, 0, - 271, 171, 187, 0, 0, 313, 352, 358, 0, 0, - 0, 210, 0, 356, 327, 412, 194, 237, 349, 332, - 354, 0, 0, 355, 280, 400, 344, 410, 428, 429, - 217, 307, 418, 391, 424, 439, 188, 214, 321, 384, - 415, 375, 300, 396, 397, 270, 374, 245, 174, 278, - 436, 186, 364, 202, 179, 386, 408, 199, 367, 0, - 0, 441, 181, 406, 383, 297, 267, 268, 180, 0, - 348, 222, 243, 212, 316, 403, 404, 211, 442, 190, - 423, 183, 0, 422, 309, 399, 407, 298, 289, 182, - 405, 296, 288, 273, 233, 254, 342, 283, 343, 255, - 305, 304, 306, 0, 177, 0, 380, 416, 443, 195, - 196, 197, 0, 232, 236, 242, 244, 250, 251, 258, - 276, 320, 341, 339, 345, 0, 394, 411, 419, 426, - 432, 433, 437, 434, 435, 438, 308, 257, 376, 272, - 281, 0, 0, 326, 357, 200, 414, 377, 0, 0, + 0, 172, 173, 185, 193, 203, 215, 230, 238, 248, + 253, 256, 260, 261, 264, 269, 286, 291, 292, 293, + 294, 310, 311, 312, 315, 318, 319, 322, 324, 325, + 328, 334, 335, 336, 337, 338, 340, 347, 351, 359, + 360, 361, 362, 363, 365, 366, 370, 371, 372, 373, + 381, 385, 401, 402, 413, 425, 430, 249, 409, 431, + 0, 285, 0, 0, 287, 234, 252, 262, 0, 420, + 382, 189, 353, 241, 178, 206, 192, 213, 228, 231, + 266, 295, 301, 330, 333, 246, 225, 204, 350, 201, + 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 317, + 0, 0, 0, 0, 0, 0, 0, 0, 224, 0, + 0, 0, 0, 275, 221, 0, 0, 331, 0, 176, + 0, 369, 209, 284, 282, 398, 235, 227, 223, 208, + 259, 290, 329, 387, 323, 0, 279, 0, 0, 378, + 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 265, 207, 175, 314, + 379, 239, 0, 0, 0, 167, 168, 169, 0, 942, + 0, 0, 0, 0, 0, 0, 198, 0, 205, 0, + 0, 0, 0, 219, 263, 226, 218, 395, 0, 0, + 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 170, 184, - 277, 0, 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 172, 173, 185, 193, 203, 215, 230, 238, - 248, 253, 256, 260, 261, 264, 269, 286, 291, 292, - 293, 294, 310, 311, 312, 315, 318, 319, 322, 324, - 325, 328, 334, 335, 336, 337, 338, 340, 347, 351, - 359, 360, 361, 362, 363, 365, 366, 370, 371, 372, - 373, 381, 385, 401, 402, 413, 425, 430, 249, 409, - 431, 0, 285, 0, 0, 287, 234, 252, 262, 0, - 420, 382, 189, 353, 241, 178, 206, 192, 213, 228, - 231, 266, 295, 301, 330, 333, 246, 225, 204, 350, - 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, + 0, 0, 0, 0, 0, 0, 247, 0, 303, 0, + 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, + 0, 274, 0, 271, 171, 187, 0, 0, 313, 352, + 358, 0, 0, 0, 210, 0, 356, 327, 412, 194, + 237, 349, 332, 354, 0, 0, 355, 280, 400, 344, + 410, 428, 429, 217, 307, 418, 391, 424, 439, 188, + 214, 321, 384, 415, 375, 300, 396, 397, 270, 374, + 245, 174, 278, 436, 186, 364, 202, 179, 386, 408, + 199, 367, 0, 0, 441, 181, 406, 383, 297, 267, + 268, 180, 0, 348, 222, 243, 212, 316, 403, 404, + 211, 442, 190, 423, 183, 0, 422, 309, 399, 407, + 298, 289, 182, 405, 296, 288, 273, 233, 254, 342, + 283, 343, 255, 305, 304, 306, 0, 177, 0, 380, + 416, 443, 195, 196, 197, 0, 232, 236, 242, 244, + 250, 251, 258, 276, 320, 341, 339, 345, 0, 394, + 411, 419, 426, 432, 433, 437, 434, 435, 438, 308, + 257, 376, 272, 281, 0, 0, 326, 357, 200, 414, + 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 317, 0, 0, 0, 0, 0, 0, 0, 0, 224, - 0, 0, 0, 0, 275, 221, 0, 0, 331, 0, - 176, 0, 369, 209, 284, 282, 398, 235, 227, 223, - 208, 259, 290, 329, 387, 323, 0, 279, 0, 0, - 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 265, 207, 175, - 314, 379, 239, 0, 0, 0, 167, 168, 169, 0, - 0, 0, 0, 0, 0, 0, 0, 198, 0, 205, - 0, 0, 0, 0, 219, 263, 226, 218, 395, 0, - 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, + 0, 170, 184, 277, 0, 346, 240, 440, 421, 417, + 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 172, 173, 185, 193, 203, + 215, 230, 238, 248, 253, 256, 260, 261, 264, 269, + 286, 291, 292, 293, 294, 310, 311, 312, 315, 318, + 319, 322, 324, 325, 328, 334, 335, 336, 337, 338, + 340, 347, 351, 359, 360, 361, 362, 363, 365, 366, + 370, 371, 372, 373, 381, 385, 401, 402, 413, 425, + 430, 249, 409, 431, 0, 285, 0, 0, 287, 234, + 252, 262, 0, 420, 382, 189, 353, 241, 178, 206, + 192, 213, 228, 231, 266, 295, 301, 330, 333, 246, + 225, 204, 350, 201, 368, 388, 389, 390, 392, 299, + 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 317, 0, 0, 0, 0, 0, 0, + 0, 0, 224, 0, 0, 0, 0, 275, 221, 0, + 0, 331, 0, 176, 0, 369, 209, 284, 282, 398, + 235, 227, 223, 208, 259, 290, 329, 387, 323, 0, + 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 265, 207, 175, 314, 379, 239, 0, 0, 0, 167, + 168, 169, 0, 0, 0, 0, 0, 0, 0, 0, + 198, 0, 205, 0, 0, 0, 0, 219, 263, 226, + 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 497, 0, 247, 0, 303, - 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, - 0, 0, 274, 0, 271, 171, 187, 0, 0, 313, - 352, 358, 0, 0, 0, 210, 0, 356, 327, 412, - 194, 237, 349, 332, 354, 0, 0, 355, 280, 400, - 344, 410, 428, 429, 217, 307, 418, 391, 424, 439, - 188, 214, 321, 384, 415, 375, 300, 396, 397, 270, - 374, 245, 174, 278, 436, 186, 364, 202, 179, 386, - 408, 199, 367, 0, 0, 441, 181, 406, 383, 297, - 267, 268, 180, 0, 348, 222, 243, 212, 316, 403, - 404, 211, 442, 190, 423, 183, 0, 422, 309, 399, - 407, 298, 289, 182, 405, 296, 288, 273, 233, 254, - 342, 283, 343, 255, 305, 304, 306, 0, 177, 0, - 380, 416, 443, 195, 196, 197, 0, 232, 236, 242, - 244, 250, 251, 258, 276, 320, 341, 339, 345, 0, - 394, 411, 419, 426, 432, 433, 437, 434, 435, 438, - 308, 257, 376, 272, 281, 0, 0, 326, 357, 200, - 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 170, 184, 277, 0, 346, 240, 440, 421, - 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 172, 173, 185, 193, - 203, 215, 230, 238, 248, 253, 256, 260, 261, 264, - 269, 286, 291, 292, 293, 294, 310, 311, 312, 315, - 318, 319, 322, 324, 325, 328, 334, 335, 336, 337, - 338, 340, 347, 351, 359, 360, 361, 362, 363, 365, - 366, 370, 371, 372, 373, 381, 385, 401, 402, 413, - 425, 430, 496, 409, 431, 0, 285, 0, 0, 287, - 234, 252, 262, 0, 420, 382, 189, 353, 241, 178, - 206, 192, 213, 228, 231, 266, 295, 301, 330, 333, - 246, 225, 204, 350, 201, 368, 388, 389, 390, 392, - 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 317, 0, 0, 0, 0, 0, - 0, 0, 0, 224, 0, 0, 0, 0, 275, 221, - 0, 0, 331, 0, 176, 0, 369, 209, 284, 282, - 398, 235, 227, 223, 208, 259, 290, 329, 387, 323, - 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 498, 0, + 247, 0, 303, 0, 0, 0, 0, 427, 0, 0, + 0, 0, 0, 0, 0, 274, 0, 271, 171, 187, + 0, 0, 313, 352, 358, 0, 0, 0, 210, 0, + 356, 327, 412, 194, 237, 349, 332, 354, 0, 0, + 355, 280, 400, 344, 410, 428, 429, 217, 307, 418, + 391, 424, 439, 188, 214, 321, 384, 415, 375, 300, + 396, 397, 270, 374, 245, 174, 278, 436, 186, 364, + 202, 179, 386, 408, 199, 367, 0, 0, 441, 181, + 406, 383, 297, 267, 268, 180, 0, 348, 222, 243, + 212, 316, 403, 404, 211, 442, 190, 423, 183, 0, + 422, 309, 399, 407, 298, 289, 182, 405, 296, 288, + 273, 233, 254, 342, 283, 343, 255, 305, 304, 306, + 0, 177, 0, 380, 416, 443, 195, 196, 197, 0, + 232, 236, 242, 244, 250, 251, 258, 276, 320, 341, + 339, 345, 0, 394, 411, 419, 426, 432, 433, 437, + 434, 435, 438, 308, 257, 376, 272, 281, 0, 0, + 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 265, 207, 175, 314, 379, 239, 0, 0, 0, - 167, 168, 169, 0, 0, 0, 0, 0, 0, 0, - 0, 198, 0, 205, 0, 0, 0, 0, 219, 263, - 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 229, + 0, 0, 0, 0, 0, 170, 184, 277, 0, 346, + 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, + 173, 185, 193, 203, 215, 230, 238, 248, 253, 256, + 260, 261, 264, 269, 286, 291, 292, 293, 294, 310, + 311, 312, 315, 318, 319, 322, 324, 325, 328, 334, + 335, 336, 337, 338, 340, 347, 351, 359, 360, 361, + 362, 363, 365, 366, 370, 371, 372, 373, 381, 385, + 401, 402, 413, 425, 430, 497, 409, 431, 0, 285, + 0, 0, 287, 234, 252, 262, 0, 420, 382, 189, + 353, 241, 178, 206, 192, 213, 228, 231, 266, 295, + 301, 330, 333, 246, 225, 204, 350, 201, 368, 388, + 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 317, 0, 0, + 0, 0, 0, 0, 0, 0, 224, 0, 0, 0, + 0, 275, 221, 0, 0, 331, 0, 176, 0, 369, + 209, 284, 282, 398, 235, 227, 223, 208, 259, 290, + 329, 387, 323, 0, 279, 0, 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 265, 207, 175, 314, 379, 239, + 0, 0, 0, 167, 168, 169, 0, 0, 0, 0, + 0, 0, 0, 0, 198, 0, 205, 0, 0, 0, + 0, 219, 263, 226, 218, 395, 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 247, 0, 303, 0, 0, 446, 0, 427, 0, - 0, 0, 0, 0, 0, 0, 274, 0, 271, 171, - 187, 0, 0, 313, 352, 358, 0, 0, 0, 210, - 0, 356, 327, 412, 194, 237, 349, 332, 354, 0, - 0, 355, 280, 400, 344, 410, 428, 429, 217, 307, - 418, 391, 424, 439, 188, 214, 321, 384, 415, 375, - 300, 396, 397, 270, 374, 245, 174, 278, 436, 186, - 364, 202, 179, 386, 408, 199, 367, 0, 0, 441, - 181, 406, 383, 297, 267, 268, 180, 0, 348, 222, - 243, 212, 316, 403, 404, 211, 442, 190, 423, 183, - 0, 422, 309, 399, 407, 298, 289, 182, 405, 296, - 288, 273, 233, 254, 342, 283, 343, 255, 305, 304, - 306, 0, 177, 0, 380, 416, 443, 195, 196, 197, - 0, 232, 236, 242, 244, 250, 251, 258, 276, 320, - 341, 339, 345, 0, 394, 411, 419, 426, 432, 433, - 437, 434, 435, 438, 308, 257, 376, 272, 281, 0, - 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 170, 184, 277, 0, - 346, 240, 440, 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 247, 0, 303, 0, 0, 446, + 0, 427, 0, 0, 0, 0, 0, 0, 0, 274, + 0, 271, 171, 187, 0, 0, 313, 352, 358, 0, + 0, 0, 210, 0, 356, 327, 412, 194, 237, 349, + 332, 354, 0, 0, 355, 280, 400, 344, 410, 428, + 429, 217, 307, 418, 391, 424, 439, 188, 214, 321, + 384, 415, 375, 300, 396, 397, 270, 374, 245, 174, + 278, 436, 186, 364, 202, 179, 386, 408, 199, 367, + 0, 0, 441, 181, 406, 383, 297, 267, 268, 180, + 0, 348, 222, 243, 212, 316, 403, 404, 211, 442, + 190, 423, 183, 0, 422, 309, 399, 407, 298, 289, + 182, 405, 296, 288, 273, 233, 254, 342, 283, 343, + 255, 305, 304, 306, 0, 177, 0, 380, 416, 443, + 195, 196, 197, 0, 232, 236, 242, 244, 250, 251, + 258, 276, 320, 341, 339, 345, 0, 394, 411, 419, + 426, 432, 433, 437, 434, 435, 438, 308, 257, 376, + 272, 281, 0, 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 172, 173, 185, 193, 203, 215, 230, 238, 248, 253, - 256, 260, 261, 264, 269, 286, 291, 292, 293, 294, - 310, 311, 312, 315, 318, 319, 322, 324, 325, 328, - 334, 335, 336, 337, 338, 340, 347, 351, 359, 360, - 361, 362, 363, 365, 366, 370, 371, 372, 373, 381, - 385, 401, 402, 413, 425, 430, 249, 409, 431, 0, - 285, 0, 0, 287, 234, 252, 262, 0, 420, 382, - 189, 353, 241, 178, 206, 192, 213, 228, 231, 266, - 295, 301, 330, 333, 246, 225, 204, 350, 201, 368, - 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 317, 0, - 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, - 0, 0, 275, 221, 0, 0, 331, 0, 176, 0, - 369, 209, 284, 282, 398, 235, 227, 223, 208, 259, - 290, 329, 387, 323, 0, 279, 0, 0, 378, 302, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, + 184, 277, 0, 346, 240, 440, 421, 417, 0, 0, + 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 265, 207, 175, 314, 379, - 239, 0, 0, 0, 167, 168, 169, 0, 0, 0, - 0, 0, 0, 0, 0, 198, 0, 205, 0, 0, - 0, 0, 219, 263, 226, 218, 395, 0, 0, 0, - 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 172, 173, 185, 193, 203, 215, 230, + 238, 248, 253, 256, 260, 261, 264, 269, 286, 291, + 292, 293, 294, 310, 311, 312, 315, 318, 319, 322, + 324, 325, 328, 334, 335, 336, 337, 338, 340, 347, + 351, 359, 360, 361, 362, 363, 365, 366, 370, 371, + 372, 373, 381, 385, 401, 402, 413, 425, 430, 249, + 409, 431, 0, 285, 0, 0, 287, 234, 252, 262, + 0, 420, 382, 189, 353, 241, 178, 206, 192, 213, + 228, 231, 266, 295, 301, 330, 333, 246, 225, 204, + 350, 201, 368, 388, 389, 390, 392, 299, 220, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 317, 0, 0, 0, 0, 0, 0, 0, 0, + 224, 0, 0, 0, 0, 275, 221, 0, 0, 331, + 0, 176, 0, 369, 209, 284, 282, 398, 235, 227, + 223, 208, 259, 290, 329, 387, 323, 0, 279, 0, + 0, 378, 302, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 265, 207, + 175, 314, 379, 239, 0, 0, 0, 167, 168, 169, + 0, 0, 0, 0, 0, 0, 0, 0, 198, 0, + 205, 0, 0, 0, 0, 219, 263, 226, 218, 395, + 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 247, 0, 303, 0, 0, - 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, - 274, 0, 271, 171, 187, 0, 0, 313, 352, 358, - 0, 0, 0, 210, 0, 356, 327, 412, 194, 237, - 349, 332, 354, 0, 0, 355, 280, 400, 344, 410, - 428, 429, 217, 307, 418, 391, 424, 439, 188, 214, - 321, 384, 415, 375, 300, 396, 397, 270, 374, 245, - 174, 278, 436, 186, 364, 202, 179, 386, 408, 199, - 367, 0, 0, 441, 181, 406, 383, 297, 267, 268, - 180, 0, 348, 222, 243, 212, 316, 403, 404, 211, - 442, 190, 423, 183, 0, 422, 309, 399, 407, 298, - 289, 182, 405, 296, 288, 273, 233, 254, 342, 283, - 343, 255, 305, 304, 306, 0, 177, 0, 380, 416, - 443, 195, 196, 197, 0, 232, 236, 242, 244, 250, - 251, 258, 276, 320, 341, 339, 345, 0, 394, 411, - 419, 426, 432, 433, 437, 434, 435, 438, 308, 257, - 376, 272, 281, 0, 0, 326, 357, 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 247, 0, + 303, 0, 0, 0, 0, 427, 0, 0, 0, 0, + 0, 0, 0, 274, 0, 271, 171, 187, 0, 0, + 313, 352, 358, 0, 0, 0, 210, 0, 356, 327, + 412, 194, 237, 349, 332, 354, 0, 0, 355, 280, + 400, 344, 410, 428, 429, 217, 307, 418, 391, 424, + 439, 188, 214, 321, 384, 415, 375, 300, 396, 397, + 270, 374, 245, 174, 278, 436, 186, 364, 202, 179, + 386, 408, 199, 367, 0, 0, 441, 181, 406, 383, + 297, 267, 268, 180, 0, 348, 222, 243, 212, 316, + 403, 404, 211, 442, 190, 423, 183, 0, 422, 309, + 399, 407, 298, 289, 182, 405, 296, 288, 273, 233, + 254, 342, 283, 343, 255, 305, 304, 306, 0, 177, + 0, 380, 416, 443, 195, 196, 197, 0, 232, 236, + 242, 244, 250, 251, 258, 276, 320, 341, 339, 345, + 0, 394, 411, 419, 426, 432, 433, 437, 434, 435, + 438, 308, 257, 376, 272, 281, 0, 0, 326, 357, + 200, 414, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 170, 184, 277, 0, 346, 240, 440, 421, 417, 0, - 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 170, 184, 277, 0, 346, 240, 440, + 421, 417, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 172, 173, 185, 193, 203, 215, - 230, 238, 248, 253, 256, 260, 261, 264, 269, 286, - 291, 292, 293, 294, 310, 311, 312, 315, 318, 319, - 322, 324, 325, 328, 334, 335, 336, 337, 338, 340, - 347, 351, 359, 360, 361, 362, 363, 365, 366, 370, - 371, 372, 373, 381, 385, 401, 402, 413, 425, 430, - 249, 409, 431, 0, 285, 0, 0, 287, 234, 252, - 262, 0, 420, 382, 189, 353, 241, 178, 206, 192, - 213, 228, 231, 266, 295, 301, 330, 333, 246, 225, - 204, 350, 201, 368, 388, 389, 390, 392, 299, 220, + 0, 0, 0, 0, 0, 0, 0, 172, 173, 185, + 193, 203, 215, 230, 238, 248, 253, 256, 260, 261, + 264, 269, 286, 291, 292, 293, 294, 310, 311, 312, + 315, 318, 319, 322, 324, 325, 328, 334, 335, 336, + 337, 338, 340, 347, 351, 359, 360, 361, 362, 363, + 365, 366, 370, 371, 372, 373, 381, 385, 401, 402, + 413, 425, 430, 249, 409, 431, 0, 285, 0, 0, + 287, 234, 252, 262, 0, 420, 382, 189, 353, 241, + 178, 206, 192, 213, 228, 231, 266, 295, 301, 330, + 333, 246, 225, 204, 350, 201, 368, 388, 389, 390, + 392, 299, 220, } var yyPact = [...]int{ - 4154, -1000, -344, 1699, -1000, -1000, -1000, -1000, -1000, -1000, + 2386, -1000, -340, 1626, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 1578, 1212, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 619, 1276, -1000, 1513, 4081, -1000, 29662, 383, + -1000, 29188, 370, 2201, 29662, -1000, 94, -1000, 83, 29662, + 96, 28714, -1000, -1000, -283, 13070, 1464, -4, -7, 29662, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1249, + 1539, 1546, 1588, 1063, 1582, -1000, 11173, 11173, 300, 300, + 300, 9277, -1000, -1000, 17337, 29662, 29662, 194, -1000, 1513, + -1000, -1000, 237, -1000, 240, 1219, -1000, 1213, -1000, 585, + 385, 236, 311, 309, 233, 232, 230, 229, 228, 227, + 225, 224, 242, -1000, 543, 543, -174, -175, 3053, 288, + 288, 288, 329, 1492, 1490, -1000, 553, -1000, 543, 543, + 215, 543, 543, 543, 543, 198, 193, 543, 543, 543, + 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, + 543, 543, 207, 1513, 165, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 1662, 1188, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 650, 1341, -1000, 1572, 2334, -1000, 29179, 418, - -1000, 28705, 412, 61, 29179, -1000, 97, -1000, 88, 29179, - 93, 28231, -1000, -1000, -270, 12587, 1511, 1, -1, 29179, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1319, - 1632, 1646, 1660, 1094, 1630, -1000, 10690, 10690, 360, 360, - 360, 8794, -1000, -1000, 16854, 29179, 29179, 215, -1000, 1572, - -1000, -1000, 275, -1000, 294, 1290, -1000, 1287, -1000, 398, - 345, 291, 341, 337, 279, 270, 269, 266, 265, 264, - 260, 257, 297, -1000, 651, 651, -141, -142, 292, 350, - 350, 350, 374, 1529, 1525, -1000, 507, -1000, 651, 651, - 239, 651, 651, 651, 651, 222, 221, 651, 651, 651, - 651, 651, 651, 651, 651, 651, 651, 651, 651, 651, - 651, 651, 213, 1572, 186, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -4125,28 +4176,27 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 29662, 110, 29662, -1000, 460, 29662, + 626, 626, 5, 626, 626, 626, 626, 101, 443, -16, + -1000, 91, 187, 84, 152, 611, 125, 63, -1000, -1000, + 159, 611, 973, 80, -1000, 626, 7373, 7373, 7373, -1000, + 1506, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 325, + -1000, -1000, -1000, -1000, 29662, 28240, 258, 578, -1000, -1000, + -1000, 79, -1000, -1000, 1127, 563, -1000, 13070, 1250, 1134, + 1134, -1000, -1000, 411, -1000, -1000, 14492, 14492, 14492, 14492, + 14492, 14492, 14492, 14492, 14492, 14492, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 1134, 441, -1000, 12596, 1134, 1134, 1134, 1134, 1134, 1134, + 1134, 1134, 13070, 1134, 1134, 1134, 1134, 1134, 1134, 1134, + 1134, 1134, 1134, 1134, 1134, 1134, 1134, 1134, 1134, 1134, + -1000, -1000, -1000, 29662, -1000, 1134, 108, 1578, -1000, 1212, + -1000, -1000, -1000, 1508, 13070, 13070, 1578, -1000, 1411, 11173, + -1000, -1000, 1436, -1000, -1000, -1000, -1000, -1000, 749, 1605, + -1000, 15914, 438, 1604, 27766, -1000, 21130, 27292, 1209, 8801, + -47, -1000, -1000, -1000, 575, 19708, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 29179, 104, 29179, -1000, 538, 29179, - 727, 727, 4, 727, 727, 727, 727, 101, 492, -4, - -1000, 99, 181, 90, 187, 700, 131, 70, -1000, -1000, - 183, 700, 110, -1000, 727, 6890, 6890, 6890, -1000, 1556, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 369, -1000, - -1000, -1000, -1000, 29179, 27757, 290, 669, -1000, -1000, -1000, - 3, -1000, -1000, 1207, 1010, -1000, 12587, 1291, 1251, 1251, - -1000, -1000, 460, -1000, -1000, 14009, 14009, 14009, 14009, 14009, - 14009, 14009, 14009, 14009, 14009, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1251, - 537, -1000, 12113, 1251, 1251, 1251, 1251, 1251, 1251, 1251, - 1251, 12587, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, - 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, -1000, - -1000, -1000, 29179, -1000, 1251, 105, 1662, -1000, 1188, -1000, - -1000, -1000, 1560, 12587, 12587, 1662, -1000, 1465, 10690, -1000, - -1000, 1597, -1000, -1000, -1000, -1000, -1000, 768, 1686, -1000, - 15431, 536, 1685, 27283, -1000, 20647, 26809, 1284, 8318, -37, - -1000, -1000, -1000, 662, 19225, -1000, -1000, -1000, -1000, -1000, + -1000, 1506, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 1556, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -4158,196 +4208,196 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1201, - 29179, -1000, -1000, 2672, 1001, -1000, 1333, -1000, 1199, -1000, - 1299, 1302, 410, 1001, 397, 392, 391, -1000, -82, -1000, - -1000, -1000, -1000, -1000, 651, 651, 296, 2334, 3561, -1000, - -1000, -1000, 26335, 1331, 1001, -1000, 1330, -1000, 718, 437, - 449, 449, 1001, -1000, -1000, 29179, 1001, 716, 715, 29179, - 29179, -1000, 25861, -1000, 25387, 24913, 970, 29179, 24439, 23965, - 23491, 23017, 22543, -1000, 1437, -1000, 1303, -1000, -1000, -1000, - 29179, 29179, 29179, 207, -1000, -1000, 29179, 1001, -1000, -1000, - 952, 914, 651, 651, 907, 1030, 1029, 1028, 651, 651, - 905, 1027, 21121, 249, 896, 878, 877, 1032, 1026, 122, - 1020, 879, 869, 29179, 1329, 29179, -1000, 150, 617, 248, - 661, 1572, 1510, 1283, 367, 404, 1001, 353, 353, -1000, - 7366, -1000, -1000, 1024, 12587, -1000, 724, 700, 700, -1000, - -1000, -1000, -1000, -1000, -1000, 727, 29179, 724, -1000, -1000, - -1000, 700, 727, 29179, 727, 727, 727, 727, 700, 700, - 700, 727, 29179, 29179, 29179, 29179, 29179, 29179, 29179, 29179, - 29179, 6890, 6890, 6890, 598, 727, -1000, 1401, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 91, -1000, -1000, -1000, - -1000, -1000, 1699, -1000, -1000, -1000, -98, 1282, 22069, -1000, - -274, -282, -285, -286, -1000, -1000, -1000, -287, -295, -1000, - -1000, -1000, 12587, 12587, 12587, 12587, 1038, 606, 14009, 868, - 656, 14009, 14009, 14009, 14009, 14009, 14009, 14009, 14009, 14009, - 14009, 14009, 14009, 14009, 14009, 14009, 658, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 1001, -1000, 1682, 1143, 1143, - 560, 560, 560, 560, 560, 560, 560, 560, 560, 14483, - 9268, 7366, 1094, 1178, 1662, 10690, 10690, 12587, 12587, 11638, - 11164, 10690, 1578, 660, 1010, 29179, -1000, 1025, -1000, -1000, - 13535, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 29179, 29179, 10690, 10690, 10690, 10690, 10690, - -1000, 1281, -1000, -166, 16380, 12587, 1023, 1646, 1094, 1597, - 1588, 1693, 594, 938, 1255, -1000, 909, 1646, 18751, 1276, - -1000, 1597, -1000, -1000, -1000, 29179, -1000, -1000, 21595, -1000, - -1000, 6414, 29179, 256, 29179, -1000, 1246, 1564, -1000, -1000, - -1000, 1619, 18277, 29179, 1248, 1247, -1000, -1000, 525, 7842, - -37, -1000, 7842, 1233, -1000, -29, -43, 9742, 559, -1000, - -1000, -1000, 292, 14957, 1080, 1517, 34, -1000, -1000, -1000, - 1299, -1000, 1299, 1299, 1299, 1299, 207, 207, 207, 207, - -1000, -1000, -1000, -1000, -1000, 1325, 1323, -1000, 1299, 1299, - 1299, 1299, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1322, - 1322, 1322, 1316, 1316, 339, -1000, 12587, 172, 29179, 1587, - 865, 150, 358, 1384, 1001, 1001, 1001, 358, -1000, 930, - 922, -1000, 1254, -1000, -1000, 1659, -1000, -1000, 555, 764, - 758, 520, 29179, 121, 255, -1000, 321, -1000, 29179, 1001, - 712, 449, 1001, -1000, 1001, -1000, -1000, -1000, -1000, 523, - -1000, -1000, 1001, 1252, -1000, 1214, 799, 732, 749, 710, - 1252, -1000, -1000, -111, 1252, -1000, 1252, -1000, 1252, -1000, - 1252, -1000, 1252, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 630, 29179, 121, 658, -1000, 364, -1000, -1000, 658, - 658, -1000, -1000, -1000, -1000, 1013, 1012, -1000, -1000, -1000, + 1109, 29662, -1000, -1000, 3437, 919, -1000, 1274, -1000, 1106, + -1000, 1233, 1259, 353, 919, 349, 348, 345, -1000, -85, + -1000, -1000, -1000, -1000, -1000, 543, 543, 223, 4081, 4344, + -1000, -1000, -1000, 26818, 1273, 919, -1000, 1272, -1000, 680, + 376, 406, 406, 919, -1000, -1000, 29662, 919, 679, 676, + 29662, 29662, -1000, 26344, -1000, 25870, 25396, 879, 29662, 24922, + 24448, 23974, 23500, 23026, -1000, 1372, -1000, 1255, -1000, -1000, + -1000, 29662, 29662, 29662, 202, -1000, -1000, 29662, 919, -1000, + -1000, 872, 868, 543, 543, 867, 972, 963, 962, 543, + 543, 857, 961, 21604, 191, 845, 843, 838, 873, 959, + 115, 871, 822, 805, 29662, 1268, 29662, -1000, 151, 505, + 248, 572, 1513, 1453, 1208, 323, 352, 919, 295, 295, + -1000, 7849, -1000, -1000, 956, 13070, -1000, 621, 611, 611, + -1000, -1000, -1000, -1000, -1000, -1000, 626, 29662, 621, -1000, + -1000, -1000, 611, 626, 29662, 626, 626, 626, 626, 611, + 611, 611, 626, 29662, 29662, 29662, 29662, 29662, 29662, 29662, + 29662, 29662, 7373, 7373, 7373, 501, 626, -287, -1000, 1361, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 90, -1000, + -1000, -1000, -1000, -1000, 1626, -1000, -1000, -1000, -113, 1195, + 22552, -1000, -288, -289, -290, -291, -1000, -1000, -1000, -292, + -293, -1000, -1000, -1000, 13070, 13070, 13070, 13070, 894, 523, + 14492, 758, 635, 14492, 14492, 14492, 14492, 14492, 14492, 14492, + 14492, 14492, 14492, 14492, 14492, 14492, 14492, 14492, 551, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 919, -1000, 1623, + 1252, 1252, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 14966, 9751, 7849, 1063, 1101, 1578, 11173, 11173, 13070, + 13070, 12121, 11647, 11173, 1495, 583, 563, 29662, -1000, 965, + -1000, -1000, 14018, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 29662, 29662, 11173, 11173, 11173, + 11173, 11173, -1000, 1190, -1000, -173, 16863, 13070, 955, 1546, + 1063, 1436, 1510, 1613, 492, 960, 1188, -1000, 748, 1546, + 19234, 1210, -1000, 1436, -1000, -1000, -1000, 29662, -1000, -1000, + 22078, -1000, -1000, 6897, 29662, 222, 29662, -1000, 1178, 1373, + -1000, -1000, -1000, 1533, 18760, 29662, 1176, 1175, -1000, -1000, + 436, 8325, -47, -1000, 8325, 1147, -1000, -33, -54, 10225, + 444, -1000, -1000, -1000, 3053, 15440, 1033, 1475, 29, -1000, + -1000, -1000, 1233, -1000, 1233, 1233, 1233, 1233, 202, 202, + 202, 202, -1000, -1000, -1000, -1000, -1000, 1257, 1251, -1000, + 1233, 1233, 1233, 1233, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 1247, 1247, 1247, 1234, 1234, 279, -1000, 13070, 158, + 29662, 1520, 804, 151, 298, 1307, 919, 919, 919, 298, + -1000, 933, 928, -1000, 1180, -1000, -1000, 1585, -1000, -1000, + 663, 708, 706, 484, 29662, 112, 219, -1000, 278, -1000, + 29662, 919, 647, 406, 919, -1000, 919, -1000, -1000, -1000, + -1000, 435, -1000, -1000, 919, 1177, -1000, 1128, 723, 700, + 720, 688, 1177, -1000, -1000, -104, 1177, -1000, 1177, -1000, + 1177, -1000, 1177, -1000, 1177, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 534, 29662, 112, 551, -1000, 316, -1000, + -1000, 551, 551, -1000, -1000, -1000, -1000, 952, 951, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -339, 29179, -1000, 141, 659, 229, - 272, 209, 29179, 188, 1622, 204, 217, 29179, 29179, 353, - 1399, 29179, 1602, 29179, -1000, -1000, -1000, -1000, 1010, 29179, - -1000, -1000, 727, 727, -1000, -1000, 29179, 727, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 727, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 1007, -1000, 29179, 29179, -1000, -1000, -1000, -1000, -1000, - 37, -31, 205, -1000, -1000, -1000, -1000, 1625, -1000, 1010, - 606, 648, 614, -1000, -1000, 830, -1000, -1000, 2931, -1000, - -1000, -1000, -1000, 868, 14009, 14009, 14009, 578, 2931, 3060, - 889, 3074, 560, 655, 655, 558, 558, 558, 558, 558, - 797, 797, -1000, -1000, -1000, -1000, 1025, -1000, -1000, -1000, - 1025, 10690, 10690, 1241, 1251, 513, -1000, 1319, -1000, -1000, - 1646, 1163, 1163, 795, 949, 612, 1684, 1163, 590, 1678, - 1163, 1163, 10690, -1000, -1000, 685, -1000, 12587, 1025, -1000, - 704, 1237, 1236, 1163, 1025, 1025, 1163, 1163, 29179, -1000, - -263, -1000, -65, 524, 1251, -1000, 21121, 1025, 1207, -1000, - 1560, -1000, -1000, 1508, -1000, 1462, 12587, 12587, 12587, -1000, - -1000, -1000, 1560, 1649, -1000, 1478, 1474, 1672, 10690, 20647, - 1597, -1000, -1000, -1000, 506, 1672, 1257, 1251, -1000, 29179, - 20647, 20647, 20647, 20647, 20647, -1000, 1432, 1428, -1000, 1455, - 1438, 1412, 29179, -1000, 1173, 1094, 18277, 256, 1121, 20647, - 29179, -1000, -1000, 20647, 29179, 5938, -1000, 1233, -37, -46, - -1000, -1000, -1000, -1000, 1010, -1000, 903, -1000, 2546, -1000, - 319, -1000, -1000, -1000, -1000, 756, 1618, 1515, 25, -1000, - -1000, -1000, 207, 207, -1000, -1000, 559, 807, 559, 559, - 559, 1006, 1006, -1000, -1000, -1000, -1000, -1000, 862, -1000, - -1000, -1000, 796, -1000, -1000, 991, 1409, 172, -1000, -1000, - 651, 1003, 1520, 29179, -1000, -1000, 1074, 141, 29179, 679, - 1397, -1000, 1384, 1384, 1384, 29179, -1000, -1000, -1000, -1000, - 3521, 29179, 1171, -1000, 111, 29179, 1066, 29179, -1000, 1169, - 1321, 1001, 1001, -1000, -1000, 7366, -1000, 29179, 1251, -1000, - -1000, -1000, -1000, 401, 1567, 1566, 121, 111, 559, 1001, - -1000, -1000, -1000, -1000, -1000, -337, 1165, 379, 129, 182, - 29179, 29179, 29179, 29179, 29179, 461, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 190, 362, -1000, 29179, 29179, 488, -1000, - -1000, -1000, 700, -1000, -1000, 700, -1000, -1000, -1000, -1000, - -1000, -1000, 1554, -32, -312, -1000, -305, -1000, -1000, -1000, - -1000, 578, 2931, 3023, -1000, 14009, 14009, -1000, -1000, 1163, - 1163, 10690, 7366, 1662, 1560, -1000, -1000, 298, 658, 298, - 14009, 14009, -1000, 14009, 14009, -1000, -99, 1213, 615, -1000, - 12587, 773, -1000, -1000, 14009, 14009, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 385, 383, 381, 29179, -1000, - -1000, -1000, 933, 1002, 1460, 1010, 1010, -1000, -1000, 29179, - -1000, -1000, -1000, -1000, 1670, 12587, -1000, 1230, -1000, 5462, - 1646, 1395, 29179, 1251, 1699, 15906, 29179, 1185, -1000, 653, - 1564, 1370, 1391, 1683, -1000, -1000, -1000, -1000, 1422, -1000, - 1416, -1000, -1000, -1000, -1000, -1000, 1094, 1672, 20647, 1161, - -1000, 1161, -1000, 505, -1000, -1000, -1000, -51, -39, -1000, - -1000, -1000, 292, -1000, -1000, -1000, -1000, 776, 14009, 1692, - -1000, 1000, -1000, -1000, 711, 701, -1000, 29179, 1320, -1000, - -1000, -1000, 559, 559, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 1155, -1000, 1139, 1222, 1131, 89, -1000, 1148, 1552, - 651, 651, -1000, 793, -1000, 1001, -1000, -1000, 378, -1000, - 1596, 29179, 1390, 1389, 1388, -1000, 1657, 1209, -1000, 29179, - -1000, -1000, 29179, -1000, -1000, 1473, 172, 29179, -1000, -1000, - -1000, -1000, 255, 29179, -1000, 1143, 111, -1000, -1000, -1000, - -1000, -1000, -1000, 29179, 132, -1000, 1317, 994, -1000, 1367, - -1000, -1000, -1000, -1000, 109, 227, -1000, 29179, 426, 1409, - 29179, -1000, -1000, -1000, 727, 727, -1000, 1539, -1000, 1001, - -1000, 14009, 2931, 2931, -1000, -1000, 1025, -1000, 1646, -1000, - 1025, 1299, 1299, -1000, 1299, 1316, -1000, 1299, 81, 1299, - 78, 1025, 1025, 3006, 2637, 2307, 1210, 1251, -90, -1000, - 1010, 12587, 2254, 1894, 1251, 1251, 1251, 1125, 993, 207, - -1000, -1000, -1000, 1665, 1655, 1010, -1000, -1000, -1000, 1561, - 1144, 1123, -1000, -1000, 10216, 1127, 1472, 485, 1125, 1662, - 29179, 12587, -1000, -1000, 12587, 1293, -1000, 12587, -1000, -1000, - -1000, 1662, 1662, 1161, -1000, -1000, 569, -1000, -1000, -1000, - -1000, -1000, 2931, -94, -1000, -1000, -1000, 1292, 14009, -1000, - -1000, 207, 988, 207, 790, -1000, 782, -1000, -1000, -184, - -1000, -1000, 1298, 1414, -1000, -1000, 29179, -1000, -1000, 29179, - 29179, 29179, 29179, 29179, -1000, -1000, 219, -1000, 1118, 1107, - -1000, -131, -1000, -1000, 1260, -1000, -1000, -1000, 1059, -1000, - -116, 1001, 29179, 29179, 29179, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 2931, -1000, 1560, -1000, -1000, 262, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 14009, 14009, 14009, - 14009, 14009, 1646, 985, 1010, 14009, 14009, 17802, 20173, 20173, - 17328, 207, 20, -1000, 12587, 12587, 699, -1000, 1251, -1000, - 1259, 29179, 1251, 29179, -1000, 1646, -1000, 1010, 1010, 29179, - 1010, 1646, -1000, -1000, 29179, 1250, 559, -1000, 559, 1056, - 1036, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1260, - -1000, -1000, -1000, 1209, -1000, 212, 278, -1000, 255, -1000, - -147, -150, 1617, 29179, -1000, -1000, 7366, -1000, -1000, 1258, - 1371, -1000, -1000, -1000, -1000, 704, 704, 704, 704, 271, - 1025, -1000, 704, 704, 1101, -1000, -1000, -1000, 1101, 1101, - 524, -237, -1000, 1506, 1480, 1010, 1207, 1690, -1000, 1251, - 1699, 470, 1123, -1000, -1000, 1083, -1000, 1065, -1000, -1000, - -1000, -1000, -1000, 1613, 1251, -1000, -1000, -1000, -1000, 1188, - 1062, 1141, -1000, 647, 29179, 29179, -1000, -1000, -1000, -1000, - 1025, 185, -121, -1000, -1000, -1000, 19699, -1000, -1000, -1000, - -1000, 20, 276, -1000, 1494, 1480, -1000, 1654, 1502, 1653, - -1000, 29179, 1123, 29179, -1000, 1387, 1048, 1188, 13061, 228, - -1000, 7366, 4986, 1044, -1000, -1000, 1449, -105, -129, -1000, - -1000, 1490, 1493, 1493, 1494, -1000, 1650, 1648, -1000, 984, - 1633, 983, 1099, -1000, 1386, -1000, 1676, -1000, -1000, -1000, - 735, 978, -1000, -1000, -1000, 228, 704, 1025, -1000, -40, - -1000, -1000, -1000, -1000, -1000, 1367, -1000, 1439, -1000, 1485, - 805, -1000, -1000, -1000, -1000, 977, 973, -1000, 904, -1000, - -1000, 1689, 486, 486, -1000, -1000, -1000, -1000, -1000, 338, - -1000, -1000, -116, -119, -1000, 800, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 318, 847, -1000, 147, -1000, -127, - -1000, -1000, -1000, -1000, -1000, -1000, -138, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -336, 29662, -1000, 134, + 568, 189, 220, 178, 29662, 127, 1536, 172, 192, 29662, + 29662, 295, 1359, 29662, 1527, 29662, -1000, -1000, -1000, -1000, + 563, 29662, -1000, -1000, 626, 626, -1000, -1000, 29662, 626, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 626, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 950, -1000, -1000, 29662, 29662, -1000, -1000, + -1000, -1000, -1000, 95, -38, 214, -1000, -1000, -1000, -1000, + 1542, -1000, 563, 523, 544, 694, -1000, -1000, 756, -1000, + -1000, 2512, -1000, -1000, -1000, -1000, 758, 14492, 14492, 14492, + 641, 2512, 2531, 998, 1550, 450, 655, 655, 471, 471, + 471, 471, 471, 886, 886, -1000, -1000, -1000, -1000, 965, + -1000, -1000, -1000, 965, 11173, 11173, 1173, 1134, 426, -1000, + 1249, -1000, -1000, 1546, 1068, 1068, 754, 869, 570, 1603, + 1068, 561, 1602, 1068, 1068, 11173, -1000, -1000, 632, -1000, + 13070, 965, -1000, 1096, 1171, 1161, 1068, 965, 965, 1068, + 1068, 29662, -1000, -278, -1000, -51, 437, 1134, -1000, 21604, + 965, 1127, -1000, 1508, -1000, -1000, 1470, -1000, 1408, 13070, + 13070, 13070, -1000, -1000, -1000, 1508, 1577, -1000, 1426, 1422, + 1595, 11173, 21130, 1436, -1000, -1000, -1000, 424, 1595, 1194, + 1134, -1000, 29662, 21130, 21130, 21130, 21130, 21130, -1000, 1399, + 1396, -1000, 1387, 1383, 1395, 29662, -1000, 1089, 1063, 18760, + 222, 1111, 21130, 29662, -1000, -1000, 21130, 29662, 6421, -1000, + 1147, -47, -36, -1000, -1000, -1000, -1000, 563, -1000, 853, + -1000, 274, -1000, 287, -1000, -1000, -1000, -1000, 388, 1532, + 1473, 18, -1000, -1000, -1000, 202, 202, -1000, -1000, 444, + 658, 444, 444, 444, 949, 949, -1000, -1000, -1000, -1000, + -1000, 793, -1000, -1000, -1000, 791, -1000, -1000, 876, 1331, + 158, -1000, -1000, 543, 948, 1479, 29662, -1000, -1000, 1023, + 134, 29662, 600, 1358, -1000, 1307, 1307, 1307, 29662, -1000, + -1000, -1000, -1000, 247, 29662, 1083, -1000, 113, 29662, 1009, + 29662, -1000, 1081, 1243, 919, 919, -1000, -1000, 7849, -1000, + 29662, 1134, -1000, -1000, -1000, -1000, 351, 1511, 1509, 112, + 113, 444, 919, -1000, -1000, -1000, -1000, -1000, -343, 1075, + 331, 117, 181, 29662, 29662, 29662, 29662, 29662, 394, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 168, 307, -1000, 29662, + 29662, 381, -1000, -1000, -1000, 611, -1000, -1000, 611, -1000, + -1000, -1000, -1000, -1000, -1000, 1503, -40, -311, -1000, -308, + -1000, -1000, -1000, -1000, 641, 2512, 2494, -1000, 14492, 14492, + -1000, -1000, 1068, 1068, 11173, 7849, 1578, 1508, -1000, -1000, + 196, 551, 196, 14492, 14492, -1000, 14492, 14492, -1000, -98, + 1085, 545, -1000, 13070, 856, -1000, -1000, 14492, 14492, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 343, 335, + 334, 29662, -1000, -1000, -1000, 908, 936, 1406, 563, 563, + -1000, -1000, 29662, -1000, -1000, -1000, -1000, 1593, 13070, -1000, + 1146, -1000, 5945, 1546, 1345, 29662, 1134, 1626, 16389, 29662, + 1121, -1000, 565, 1373, 1298, 1344, 1340, -1000, -1000, -1000, + -1000, 1391, -1000, 1389, -1000, -1000, -1000, -1000, -1000, 1063, + 1595, 21130, 1098, -1000, 1098, -1000, 423, -1000, -1000, -1000, + -43, -68, -1000, -1000, -1000, 3053, -1000, -1000, -1000, -1000, + 732, 14492, 1612, -1000, 934, -1000, -1000, 645, 617, -1000, + 29662, 1242, -1000, -1000, -1000, 444, 444, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 1046, -1000, 1042, 1144, 1040, 62, + -1000, 1199, 1501, 543, 543, -1000, 789, -1000, 919, -1000, + -1000, 310, -1000, 1523, 29662, 1343, 1339, 1328, -1000, 1581, + 1142, -1000, 29662, -1000, -1000, 29662, -1000, -1000, 1419, 158, + 29662, -1000, -1000, -1000, -1000, 219, 29662, -1000, 1252, 113, + -1000, -1000, -1000, -1000, -1000, -1000, 29662, 147, -1000, 1236, + 979, -1000, 1286, -1000, -1000, -1000, -1000, 111, 183, -1000, + 29662, 365, 1331, 29662, -1000, -1000, -1000, 626, 626, -1000, + 1499, -1000, 919, -1000, 14492, 2512, 2512, -1000, -1000, 965, + -1000, 1546, -1000, 965, 1233, 1233, -1000, 1233, 1234, -1000, + 1233, 74, 1233, 73, 965, 965, 2394, 2304, 2191, 1808, + 1134, -88, -1000, 563, 13070, 1781, 1753, 1134, 1134, 1134, + 1030, 932, 202, -1000, -1000, -1000, 1591, 1576, 563, -1000, + -1000, -1000, 1515, 1123, 1087, -1000, -1000, 10699, 1038, 1416, + 410, 1030, 1578, 29662, 13070, -1000, -1000, 13070, 1231, -1000, + 13070, -1000, -1000, -1000, 1578, 1578, 1098, -1000, -1000, 477, + -1000, -1000, -1000, -1000, -1000, 2512, -91, -1000, -1000, -1000, + 1229, 14492, -1000, -1000, 202, 921, 202, 787, -1000, 769, + -1000, -1000, -215, -1000, -1000, 1133, 1369, -1000, -1000, 29662, + -1000, -1000, 29662, 29662, 29662, 29662, 29662, -1000, -1000, 206, + -1000, 1020, 1016, -1000, -143, -1000, -1000, 1226, -1000, -1000, + -1000, 1006, -1000, -116, 919, 29662, 29662, 29662, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 2512, -1000, 1508, -1000, + -1000, 273, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 14492, 14492, 14492, 14492, 14492, 1546, 914, 563, 14492, 14492, + 18285, 20656, 20656, 17811, 202, 16, -1000, 13070, 13070, 613, + -1000, 1134, -1000, 1215, 29662, 1134, 29662, -1000, 1546, -1000, + 563, 563, 29662, 563, 1546, -1000, -1000, 29662, 1284, 444, + -1000, 444, 995, 993, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 1226, -1000, -1000, -1000, 1142, -1000, 199, 260, + -1000, 219, -1000, -176, -177, 1531, 29662, -1000, -1000, 7849, + -1000, -1000, 1221, 1299, -1000, -1000, -1000, -1000, 1096, 1096, + 1096, 1096, 507, 965, -1000, 1096, 1096, 1014, -1000, -1000, + -1000, 1014, 1014, 437, -273, -1000, 1450, 1424, 563, 1127, + 1611, -1000, 1134, 1626, 403, 1087, -1000, -1000, 1005, -1000, + 1000, -1000, -1000, -1000, -1000, -1000, 1529, 1134, -1000, -1000, + -1000, -1000, 1212, 989, 1116, -1000, 539, 29662, 29662, -1000, + -1000, -1000, -1000, 965, 184, -123, -1000, -1000, -1000, 20182, + -1000, -1000, -1000, -1000, 16, 272, -1000, 1437, 1424, -1000, + 1575, 1446, 1566, -1000, 29662, 1087, 29662, -1000, 1325, 776, + 1212, 13544, 221, -1000, 7849, 5469, 983, -1000, -1000, 1405, + -112, -163, -1000, -1000, 1432, 1439, 1439, 1437, -1000, 1556, + 1554, -1000, 910, 1552, 898, 1066, -1000, 1285, -1000, 1601, + -1000, -1000, -1000, 729, 897, -1000, -1000, -1000, 221, 1096, + 965, -1000, -53, -1000, -1000, -1000, -1000, -1000, 1286, -1000, + 1376, -1000, 1427, 751, -1000, -1000, -1000, -1000, 893, 891, + -1000, 884, -1000, -1000, 1610, 440, 440, -1000, -1000, -1000, + -1000, -1000, 277, -1000, -1000, -116, -142, -1000, 744, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 267, 837, -1000, + 148, -1000, -140, -1000, -1000, -1000, -1000, -1000, -1000, -164, + -1000, } var yyPgo = [...]int{ - 0, 1999, 1997, 11, 134, 86, 1995, 1988, 1985, 1984, - 136, 133, 132, 1983, 1982, 1981, 1980, 1976, 1975, 1974, - 1972, 1970, 1968, 1967, 1966, 68, 140, 45, 48, 138, - 1965, 1964, 32, 1962, 1961, 1959, 131, 129, 598, 1958, - 122, 1957, 1956, 1955, 1954, 1953, 1951, 1950, 1949, 1948, - 1946, 1944, 1943, 1941, 1938, 224, 1937, 1936, 4, 1935, - 34, 1932, 1931, 1930, 1929, 1928, 107, 1922, 1921, 1920, - 123, 1919, 1900, 53, 113, 50, 77, 1899, 1898, 80, - 127, 1896, 71, 103, 1894, 1893, 960, 1892, 61, 82, - 126, 1891, 51, 1890, 1889, 57, 1888, 1887, 1886, 87, - 1885, 1882, 2989, 1879, 76, 93, 19, 42, 1878, 1877, - 1866, 1864, 38, 932, 1862, 1858, 25, 1856, 1848, 144, - 1847, 94, 22, 1846, 17, 35, 24, 1843, 98, 1842, - 30, 56, 36, 1841, 85, 1840, 1837, 1836, 1835, 33, - 1834, 81, 111, 63, 1833, 1832, 1831, 7, 15, 1829, - 1828, 1827, 1825, 1823, 1821, 14, 1819, 5, 1818, 26, - 1817, 27, 20, 43, 79, 160, 29, 13, 1815, 117, - 1814, 28, 121, 75, 115, 1812, 1811, 1810, 956, 152, - 1809, 1808, 58, 1807, 106, 102, 1806, 215, 1805, 1801, - 72, 1266, 2571, 8, 118, 1799, 1798, 2274, 59, 83, - 23, 1797, 89, 1796, 1787, 1785, 141, 135, 44, 948, - 46, 1783, 1782, 1781, 1779, 1778, 1775, 1774, 47, 149, - 66, 110, 31, 1772, 1771, 1770, 74, 65, 1766, 114, - 105, 78, 99, 1765, 120, 101, 64, 1764, 41, 1762, - 1755, 1745, 1741, 40, 1740, 1739, 1734, 1733, 104, 108, - 69, 39, 1731, 37, 73, 112, 109, 1729, 18, 124, - 10, 1728, 2, 0, 1727, 3, 130, 176, 119, 1725, - 1724, 1, 1719, 6, 1718, 1717, 84, 1714, 1712, 1710, - 16, 21, 9, 1708, 1706, 90, 355, 116, 1705, 128, + 0, 1936, 1935, 11, 91, 94, 1934, 1933, 1932, 1930, + 134, 132, 125, 1914, 1913, 1912, 1911, 1910, 1909, 1907, + 1906, 1904, 1902, 1901, 1887, 68, 140, 43, 47, 143, + 1885, 1881, 32, 1872, 1869, 1867, 129, 127, 552, 1866, + 123, 1865, 1863, 1858, 1855, 1852, 1851, 1850, 1849, 1848, + 1846, 1845, 1844, 1843, 1840, 180, 1839, 1838, 4, 1837, + 36, 1835, 1834, 1832, 1829, 1826, 100, 1823, 1822, 1821, + 120, 1820, 1816, 61, 109, 69, 86, 1815, 1814, 79, + 133, 1813, 64, 113, 1812, 1811, 88, 1810, 56, 103, + 80, 1809, 57, 1808, 1802, 58, 1801, 1800, 1798, 89, + 1797, 1790, 3120, 1788, 78, 84, 19, 42, 1786, 1785, + 1781, 1778, 33, 2295, 1775, 1774, 22, 1773, 1769, 131, + 1768, 99, 24, 1767, 20, 35, 31, 1766, 98, 1765, + 41, 63, 38, 1761, 93, 1760, 1758, 1757, 1754, 25, + 1753, 82, 107, 50, 1752, 1750, 1749, 8, 14, 1748, + 1742, 1741, 1738, 1737, 1736, 7, 1735, 6, 1734, 26, + 1732, 27, 18, 51, 81, 87, 29, 15, 1731, 121, + 1730, 28, 118, 76, 116, 1729, 1727, 1725, 876, 153, + 1724, 1722, 37, 1721, 101, 106, 1720, 178, 1719, 1717, + 66, 1268, 2221, 10, 122, 1710, 1709, 2152, 72, 83, + 23, 1708, 65, 1707, 1706, 1705, 145, 135, 74, 860, + 45, 1703, 1701, 1699, 1685, 1684, 1683, 1681, 139, 44, + 34, 126, 30, 1680, 1679, 1678, 73, 53, 1677, 115, + 112, 75, 128, 1675, 117, 110, 67, 1674, 46, 1672, + 1670, 1669, 1668, 48, 1667, 1666, 1664, 1661, 114, 104, + 71, 39, 1660, 40, 77, 111, 108, 1659, 16, 138, + 13, 1658, 1, 0, 1657, 3, 130, 165, 105, 1656, + 1651, 2, 1650, 5, 1648, 1642, 85, 1639, 1638, 1637, + 17, 21, 9, 1636, 1634, 3289, 355, 119, 1633, 124, } -//line sql.y:5326 +//line sql.y:5330 type yySymType struct { union interface{} empty struct{} @@ -4843,57 +4893,57 @@ var yyR1 = [...]int{ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 274, 274, 180, - 180, 188, 188, 179, 179, 202, 202, 202, 182, 182, - 182, 183, 183, 278, 278, 278, 43, 43, 45, 45, - 46, 47, 47, 204, 204, 205, 205, 48, 49, 61, - 61, 61, 61, 61, 61, 63, 63, 63, 7, 7, - 7, 7, 57, 57, 57, 6, 6, 44, 44, 51, - 275, 275, 276, 277, 277, 277, 277, 52, 54, 20, - 20, 20, 20, 20, 20, 78, 78, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 66, 72, - 72, 72, 67, 67, 288, 55, 56, 56, 70, 70, - 70, 64, 64, 64, 69, 69, 69, 75, 75, 77, - 77, 77, 77, 77, 79, 79, 79, 79, 79, 79, - 79, 74, 74, 76, 76, 76, 76, 195, 195, 195, - 194, 194, 87, 87, 88, 88, 89, 89, 90, 90, - 90, 129, 105, 105, 162, 162, 161, 161, 163, 163, - 163, 163, 165, 165, 91, 91, 91, 91, 92, 92, - 93, 93, 94, 94, 203, 203, 200, 200, 200, 199, - 199, 98, 98, 98, 100, 99, 99, 99, 99, 101, - 101, 103, 103, 102, 102, 104, 106, 106, 106, 106, - 106, 107, 107, 86, 86, 86, 86, 86, 86, 86, - 86, 177, 177, 109, 109, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 120, 120, 120, 120, 120, - 120, 110, 110, 110, 110, 110, 110, 110, 73, 73, - 121, 121, 121, 128, 122, 122, 113, 113, 113, 113, + 42, 42, 42, 42, 42, 42, 42, 42, 274, 274, + 180, 180, 188, 188, 179, 179, 202, 202, 202, 182, + 182, 182, 183, 183, 278, 278, 278, 43, 43, 45, + 45, 46, 47, 47, 204, 204, 205, 205, 48, 49, + 61, 61, 61, 61, 61, 61, 63, 63, 63, 7, + 7, 7, 7, 57, 57, 57, 6, 6, 44, 44, + 51, 275, 275, 276, 277, 277, 277, 277, 52, 54, + 20, 20, 20, 20, 20, 20, 78, 78, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 72, 72, 72, 67, 67, 288, 55, 56, 56, 70, + 70, 70, 64, 64, 64, 69, 69, 69, 75, 75, + 77, 77, 77, 77, 77, 79, 79, 79, 79, 79, + 79, 79, 74, 74, 76, 76, 76, 76, 195, 195, + 195, 194, 194, 87, 87, 88, 88, 89, 89, 90, + 90, 90, 129, 105, 105, 162, 162, 161, 161, 163, + 163, 163, 163, 165, 165, 91, 91, 91, 91, 92, + 92, 93, 93, 94, 94, 203, 203, 200, 200, 200, + 199, 199, 98, 98, 98, 100, 99, 99, 99, 99, + 101, 101, 103, 103, 102, 102, 104, 106, 106, 106, + 106, 106, 107, 107, 86, 86, 86, 86, 86, 86, + 86, 86, 177, 177, 109, 109, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 120, 120, 120, 120, + 120, 120, 110, 110, 110, 110, 110, 110, 110, 73, + 73, 121, 121, 121, 128, 122, 122, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, - 117, 117, 117, 117, 115, 115, 115, 115, 115, 115, - 115, 115, 115, 115, 115, 115, 115, 115, 116, 116, + 113, 117, 117, 117, 117, 115, 115, 115, 115, 115, + 115, 115, 115, 115, 115, 115, 115, 115, 115, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 289, 289, 119, 118, 118, 118, - 118, 118, 118, 118, 68, 68, 68, 68, 68, 208, - 208, 208, 210, 210, 210, 210, 210, 210, 210, 210, - 210, 210, 210, 210, 210, 135, 135, 65, 65, 133, - 133, 134, 136, 136, 130, 130, 130, 112, 112, 112, - 112, 112, 112, 112, 112, 114, 114, 114, 137, 137, - 138, 138, 139, 139, 140, 140, 141, 142, 142, 142, - 143, 143, 143, 143, 32, 32, 32, 32, 32, 27, - 27, 27, 27, 28, 28, 28, 80, 80, 80, 80, - 82, 82, 81, 81, 58, 58, 59, 59, 59, 83, - 83, 84, 84, 84, 84, 159, 159, 159, 144, 144, - 144, 144, 151, 151, 151, 147, 147, 149, 149, 149, - 150, 150, 150, 148, 156, 156, 158, 158, 157, 157, - 153, 153, 154, 154, 155, 155, 155, 152, 152, 111, - 111, 111, 111, 111, 160, 160, 160, 160, 166, 166, - 124, 124, 126, 126, 125, 127, 167, 167, 171, 168, - 168, 172, 172, 172, 172, 172, 169, 169, 170, 170, - 196, 196, 196, 176, 176, 187, 187, 184, 184, 185, - 185, 178, 178, 189, 189, 189, 53, 123, 123, 254, - 254, 251, 192, 192, 193, 193, 197, 197, 201, 201, - 198, 198, 190, 190, 190, 190, 190, 190, 190, 190, + 116, 116, 116, 116, 116, 289, 289, 119, 118, 118, + 118, 118, 118, 118, 118, 68, 68, 68, 68, 68, + 208, 208, 208, 210, 210, 210, 210, 210, 210, 210, + 210, 210, 210, 210, 210, 210, 135, 135, 65, 65, + 133, 133, 134, 136, 136, 130, 130, 130, 112, 112, + 112, 112, 112, 112, 112, 112, 114, 114, 114, 137, + 137, 138, 138, 139, 139, 140, 140, 141, 142, 142, + 142, 143, 143, 143, 143, 32, 32, 32, 32, 32, + 27, 27, 27, 27, 28, 28, 28, 80, 80, 80, + 80, 82, 82, 81, 81, 58, 58, 59, 59, 59, + 83, 83, 84, 84, 84, 84, 159, 159, 159, 144, + 144, 144, 144, 151, 151, 151, 147, 147, 149, 149, + 149, 150, 150, 150, 148, 156, 156, 158, 158, 157, + 157, 153, 153, 154, 154, 155, 155, 155, 152, 152, + 111, 111, 111, 111, 111, 160, 160, 160, 160, 166, + 166, 124, 124, 126, 126, 125, 127, 167, 167, 171, + 168, 168, 172, 172, 172, 172, 172, 169, 169, 170, + 170, 196, 196, 196, 176, 176, 187, 187, 184, 184, + 185, 185, 178, 178, 189, 189, 189, 53, 123, 123, + 254, 254, 251, 192, 192, 193, 193, 197, 197, 201, + 201, 198, 198, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, @@ -4907,7 +4957,7 @@ var yyR1 = [...]int{ 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, - 190, 191, 191, 191, 191, 191, 191, 191, 191, 191, + 190, 190, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, @@ -4934,8 +4984,8 @@ var yyR1 = [...]int{ 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, - 191, 191, 191, 191, 191, 285, 286, 206, 207, 207, - 207, + 191, 191, 191, 191, 191, 191, 285, 286, 206, 207, + 207, 207, } var yyR2 = [...]int{ @@ -4986,57 +5036,57 @@ var yyR2 = [...]int{ 3, 3, 3, 7, 3, 3, 3, 3, 4, 7, 5, 2, 4, 4, 4, 4, 4, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 2, 4, 2, 4, 5, 4, 4, 4, 4, 3, - 3, 5, 2, 3, 3, 3, 3, 1, 1, 0, - 1, 0, 1, 1, 1, 0, 2, 2, 0, 2, - 2, 0, 2, 0, 1, 1, 2, 1, 1, 2, - 1, 1, 5, 0, 1, 0, 1, 2, 3, 0, - 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 1, 1, 3, 3, 2, 2, 3, - 1, 3, 2, 1, 2, 1, 2, 2, 4, 3, - 3, 6, 4, 7, 6, 1, 3, 2, 2, 2, - 2, 1, 1, 1, 3, 2, 1, 1, 1, 0, - 1, 1, 0, 3, 0, 2, 0, 2, 1, 2, - 2, 0, 1, 1, 0, 1, 1, 0, 1, 0, - 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, - 1, 1, 3, 1, 2, 3, 5, 0, 1, 2, - 1, 1, 0, 2, 1, 3, 1, 1, 1, 3, - 3, 3, 3, 7, 0, 3, 1, 3, 1, 1, - 3, 3, 1, 3, 4, 4, 4, 3, 2, 4, - 0, 1, 0, 2, 0, 1, 0, 1, 2, 1, - 1, 1, 2, 2, 1, 2, 3, 2, 3, 2, - 2, 2, 1, 1, 3, 3, 0, 5, 4, 5, - 5, 0, 2, 1, 3, 3, 3, 2, 3, 1, - 2, 0, 3, 1, 1, 3, 3, 4, 4, 5, - 3, 4, 5, 6, 2, 1, 2, 1, 2, 1, - 2, 1, 1, 1, 1, 1, 1, 1, 0, 2, - 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, - 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, - 4, 5, 5, 6, 4, 4, 6, 6, 6, 8, - 8, 8, 8, 9, 8, 5, 4, 2, 2, 2, + 2, 4, 2, 4, 5, 4, 4, 4, 4, 4, + 3, 3, 5, 2, 3, 3, 3, 3, 1, 1, + 0, 1, 0, 1, 1, 1, 0, 2, 2, 0, + 2, 2, 0, 2, 0, 1, 1, 2, 1, 1, + 2, 1, 1, 5, 0, 1, 0, 1, 2, 3, + 0, 3, 3, 3, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 3, 3, 2, 2, + 3, 1, 3, 2, 1, 2, 1, 2, 2, 4, + 3, 3, 6, 4, 7, 6, 1, 3, 2, 2, + 2, 2, 1, 1, 1, 3, 2, 1, 1, 1, + 0, 1, 1, 0, 3, 0, 2, 0, 2, 1, + 2, 2, 0, 1, 1, 0, 1, 1, 0, 1, + 0, 1, 2, 3, 4, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 1, 2, 3, 5, 0, 1, + 2, 1, 1, 0, 2, 1, 3, 1, 1, 1, + 3, 3, 3, 3, 7, 0, 3, 1, 3, 1, + 1, 3, 3, 1, 3, 4, 4, 4, 3, 2, + 4, 0, 1, 0, 2, 0, 1, 0, 1, 2, + 1, 1, 1, 2, 2, 1, 2, 3, 2, 3, + 2, 2, 2, 1, 1, 3, 3, 0, 5, 4, + 5, 5, 0, 2, 1, 3, 3, 3, 2, 3, + 1, 2, 0, 3, 1, 1, 3, 3, 4, 4, + 5, 3, 4, 5, 6, 2, 1, 2, 1, 2, + 1, 2, 1, 1, 1, 1, 1, 1, 1, 0, + 2, 1, 1, 1, 3, 1, 3, 1, 1, 1, + 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 1, 1, 1, + 1, 4, 5, 5, 6, 4, 4, 6, 6, 6, + 8, 8, 8, 8, 9, 8, 5, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 8, 8, 0, 2, 3, 4, 4, 4, - 4, 4, 4, 4, 0, 3, 4, 7, 3, 1, - 1, 1, 2, 3, 3, 1, 2, 2, 1, 2, - 1, 2, 2, 1, 2, 0, 1, 0, 2, 1, - 2, 4, 0, 2, 1, 3, 5, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 2, 0, 3, - 0, 2, 0, 3, 1, 3, 2, 0, 1, 1, - 0, 2, 4, 4, 0, 2, 2, 1, 1, 3, - 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, - 0, 3, 1, 1, 0, 4, 0, 1, 1, 0, - 3, 1, 3, 2, 1, 0, 2, 4, 0, 9, - 3, 5, 0, 3, 3, 0, 1, 0, 2, 2, - 0, 2, 2, 2, 0, 2, 1, 2, 3, 3, - 0, 2, 1, 2, 3, 4, 3, 0, 1, 2, - 1, 5, 4, 4, 1, 3, 3, 5, 0, 5, - 1, 3, 1, 2, 3, 1, 1, 3, 3, 1, - 3, 3, 3, 3, 3, 2, 1, 2, 1, 1, - 1, 1, 1, 1, 1, 0, 1, 0, 2, 0, - 3, 0, 1, 0, 1, 1, 5, 0, 1, 0, - 1, 2, 1, 1, 1, 1, 1, 1, 0, 1, + 2, 2, 2, 8, 8, 0, 2, 3, 4, 4, + 4, 4, 4, 4, 4, 0, 3, 4, 7, 3, + 1, 1, 1, 2, 3, 3, 1, 2, 2, 1, + 2, 1, 2, 2, 1, 2, 0, 1, 0, 2, + 1, 2, 4, 0, 2, 1, 3, 5, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, + 3, 0, 2, 0, 3, 1, 3, 2, 0, 1, + 1, 0, 2, 4, 4, 0, 2, 2, 1, 1, + 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, + 3, 0, 3, 1, 1, 0, 4, 0, 1, 1, + 0, 3, 1, 3, 2, 1, 0, 2, 4, 0, + 9, 3, 5, 0, 3, 3, 0, 1, 0, 2, + 2, 0, 2, 2, 2, 0, 2, 1, 2, 3, + 3, 0, 2, 1, 2, 3, 4, 3, 0, 1, + 2, 1, 5, 4, 4, 1, 3, 3, 5, 0, + 5, 1, 3, 1, 2, 3, 1, 1, 3, 3, + 1, 3, 3, 3, 3, 3, 2, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 0, 1, 0, 2, + 0, 3, 0, 1, 0, 1, 1, 5, 0, 1, + 0, 1, 2, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -5078,8 +5128,8 @@ var yyR2 = [...]int{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, - 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, } var yyChk = [...]int{ @@ -5130,254 +5180,255 @@ var yyChk = [...]int{ 357, 244, 261, 291, 171, -55, 171, -102, -197, 171, -169, 293, -188, 295, 308, 303, 313, 301, -180, 304, 306, 209, -278, 320, 171, 310, 160, 151, 296, 305, - 314, 315, 318, 218, -274, -263, 463, 478, 111, 265, - 300, 298, 321, 445, 317, 316, -197, 239, -204, 244, - -192, -263, -191, 242, -102, -61, 441, 164, -206, -206, - -72, 445, 447, -122, -86, -108, 117, -113, 29, 24, - -112, -109, -130, -127, -128, 151, 152, 154, 153, 155, - 140, 141, 148, 118, 156, -117, -115, -116, -118, 89, - 88, 97, 90, 91, 92, 93, 99, 100, 101, -192, - -197, -125, -285, 66, 67, 342, 343, 344, 345, 350, - 346, 120, 55, 337, 331, 340, 339, 338, 335, 336, - 333, 334, 348, 349, 176, 332, 170, 146, 341, -263, - -191, 42, 309, 309, -102, -55, -5, -4, -285, 6, - 21, 22, -143, 18, 17, -286, 84, -64, -77, 61, - 62, -79, 22, 36, 65, 63, 21, -56, -76, 142, - -86, -197, -76, -178, 175, -178, -178, -168, -209, 239, - -172, 321, 320, -193, -170, -192, -190, -169, 319, 165, - 360, 116, 23, 25, 119, 151, 17, 120, 35, 167, - 265, 182, 150, 178, 342, 160, 70, 361, 333, 334, - 331, 337, 344, 345, 332, 295, 29, 11, 363, 26, - 192, 22, 36, 144, 162, 123, 195, 24, 193, 101, - 366, 20, 73, 187, 12, 180, 38, 14, 367, 368, - 15, 176, 175, 135, 172, 68, 9, 156, 27, 132, - 64, 369, 113, 370, 371, 372, 373, 66, 133, 18, - 335, 336, 31, 446, 374, 350, 204, 146, 71, 57, - 447, 117, 375, 376, 99, 377, 102, 74, 452, 114, - 16, 69, 40, 378, 205, 379, 177, 380, 324, 381, - 134, 163, 341, 67, 382, 170, 308, 6, 347, 30, - 191, 179, 109, 65, 383, 171, 122, 348, 349, 174, - 100, 5, 112, 32, 10, 72, 75, 338, 339, 340, - 55, 108, 354, 121, 13, 384, 325, 115, 111, -240, - 133, -227, -231, -192, 186, -256, 182, -102, -249, -248, - -192, -71, -187, 172, 180, 179, 112, -267, 114, 226, - 332, 170, -36, -37, -169, 150, 203, 83, 83, -231, - -230, -229, -268, 205, 186, -255, -247, 178, 187, -237, - 179, 180, -232, 172, 113, -268, -232, 177, 187, 205, - 205, 107, 205, 107, 205, 205, 205, 205, 205, 205, - 205, 205, 205, 202, -238, 125, -238, 358, 358, -243, - -268, -268, -268, 174, 33, 33, -189, -232, 174, 23, - -238, -238, -169, 150, -238, -238, -238, -238, 213, 213, - -238, -238, -238, -238, -238, -238, -238, -238, -238, -238, - -238, -238, -238, -238, -238, 171, -267, -80, 318, 233, - 78, -38, 215, -22, -102, -187, 172, 173, -267, -102, - 157, -102, -182, 133, 13, -182, -179, 309, 307, 294, - 299, -182, -182, -182, -182, 216, 292, -233, 172, 33, - 183, 309, 216, 292, 216, 217, 216, 217, 302, 312, - 216, -202, 12, 135, 332, 297, 301, 209, 171, 210, - 173, 311, -263, 448, 217, -202, 309, 212, -182, -207, - -285, -193, 265, -207, -207, 30, 174, -192, -57, -192, - 89, -7, -3, -11, -10, -12, 125, -78, 309, -66, - 151, 463, 449, 450, 451, 448, 306, 456, 454, 452, - 216, 453, 83, 116, 114, 115, 132, -86, -110, 135, - 117, 133, 134, 119, 137, 136, 147, 140, 141, 142, - 143, 144, 145, 146, 138, 139, 150, 125, 126, 127, - 128, 129, 130, 131, -177, -285, -128, -285, 158, 159, - -113, -113, -113, -113, -113, -113, -113, -113, -113, -113, - -285, 157, -2, -122, -4, -285, -285, -285, -285, -285, - -285, -285, -285, -135, -86, -285, -289, -285, -289, -119, - -285, -289, -119, -289, -119, -289, -289, -119, -289, -119, - -289, -289, -119, -285, -285, -285, -285, -285, -285, -285, - -206, -275, -276, -105, -102, -285, 233, -139, -3, -55, - -159, 20, 31, -86, -140, -141, -86, -139, 57, -74, - -76, -79, 61, 62, 95, 12, -195, -194, 23, -192, - 89, 157, 12, -103, 27, -102, -88, -89, -90, -91, - -105, -129, -285, 12, -95, -96, -102, -104, -197, 83, - 239, -172, -209, -174, -173, 322, 324, 125, -196, -192, - 89, 29, 84, 83, -102, -211, -214, -216, -215, -217, - -212, -213, 262, 263, 151, 266, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 277, 30, 194, 258, 259, - 260, 261, 278, 279, 280, 281, 282, 283, 284, 285, - 245, 264, 352, 246, 247, 248, 249, 250, 251, 253, - 254, 255, 256, 257, -266, -263, 82, 84, 83, -218, - 82, -80, 171, -263, 172, 172, 172, -55, 341, -238, - -238, 202, -29, -26, -259, 16, -25, -26, 165, 103, - 104, 162, 82, -227, 82, -236, -266, -263, 82, 113, - 177, 112, -235, -232, -235, -236, -263, -130, -192, -197, - -263, 113, 113, -165, -192, -165, -165, 21, -165, 21, - -165, 21, 90, -192, -165, 21, -165, 21, -165, 21, - -165, 21, -165, 21, 29, 76, 77, 29, 79, 80, - 81, -130, -130, -227, -169, -102, -263, 90, 90, -238, - -238, 90, 89, 89, 89, -238, -238, 90, 89, -199, - -197, 89, -269, 188, 230, 232, 90, 90, 90, 90, - 29, 89, -270, 29, 470, 469, 471, 472, 473, 90, - 29, 90, 29, 90, -192, 82, -102, -83, 220, 160, - 162, 165, 74, 89, 234, 125, 42, 83, 174, 171, - -263, -184, 176, -184, -198, -197, -190, 89, -86, -234, - 12, 135, -202, -202, -182, -102, -234, -202, -182, -102, - -182, -182, -182, -182, -202, -202, -202, -182, -197, -197, - -102, -102, -102, -102, -102, -102, -102, -207, -207, -207, - -183, 133, -182, 74, -205, 242, 276, 442, 443, 444, - 83, 354, -95, 448, 448, 448, 448, 448, 448, -86, - -86, -86, -86, -120, 99, 117, 100, 101, -113, -121, - -125, -128, 94, 135, 133, 134, 119, -113, -113, -113, + 314, 315, 233, 318, 218, -274, -263, 463, 478, 111, + 265, 300, 298, 321, 445, 317, 316, -197, 239, -204, + 244, -192, -263, -191, 242, -102, -61, 441, 164, -206, + -206, -72, 445, 447, -122, -86, -108, 117, -113, 29, + 24, -112, -109, -130, -127, -128, 151, 152, 154, 153, + 155, 140, 141, 148, 118, 156, -117, -115, -116, -118, + 89, 88, 97, 90, 91, 92, 93, 99, 100, 101, + -192, -197, -125, -285, 66, 67, 342, 343, 344, 345, + 350, 346, 120, 55, 337, 331, 340, 339, 338, 335, + 336, 333, 334, 348, 349, 176, 332, 170, 146, 341, + -263, -191, 42, 309, 309, -102, -55, -5, -4, -285, + 6, 21, 22, -143, 18, 17, -286, 84, -64, -77, + 61, 62, -79, 22, 36, 65, 63, 21, -56, -76, + 142, -86, -197, -76, -178, 175, -178, -178, -168, -209, + 239, -172, 321, 320, -193, -170, -192, -190, -169, 319, + 165, 360, 116, 23, 25, 119, 151, 17, 120, 35, + 167, 265, 182, 150, 178, 342, 160, 70, 361, 333, + 334, 331, 337, 344, 345, 332, 295, 29, 11, 363, + 26, 192, 22, 36, 144, 162, 123, 195, 24, 193, + 101, 366, 20, 73, 187, 12, 180, 38, 14, 367, + 368, 15, 176, 175, 135, 172, 68, 9, 156, 27, + 132, 64, 369, 113, 370, 371, 372, 373, 66, 133, + 18, 335, 336, 31, 446, 374, 350, 204, 146, 71, + 57, 447, 117, 375, 376, 99, 377, 102, 74, 452, + 114, 16, 69, 40, 378, 205, 379, 177, 380, 324, + 381, 134, 163, 341, 67, 382, 170, 308, 6, 347, + 30, 191, 179, 109, 65, 383, 171, 122, 348, 349, + 174, 100, 5, 112, 32, 10, 72, 75, 338, 339, + 340, 55, 108, 354, 121, 13, 384, 325, 115, 111, + -240, 133, -227, -231, -192, 186, -256, 182, -102, -249, + -248, -192, -71, -187, 172, 180, 179, 112, -267, 114, + 226, 332, 170, -36, -37, -169, 150, 203, 83, 83, + -231, -230, -229, -268, 205, 186, -255, -247, 178, 187, + -237, 179, 180, -232, 172, 113, -268, -232, 177, 187, + 205, 205, 107, 205, 107, 205, 205, 205, 205, 205, + 205, 205, 205, 205, 202, -238, 125, -238, 358, 358, + -243, -268, -268, -268, 174, 33, 33, -189, -232, 174, + 23, -238, -238, -169, 150, -238, -238, -238, -238, 213, + 213, -238, -238, -238, -238, -238, -238, -238, -238, -238, + -238, -238, -238, -238, -238, -238, 171, -267, -80, 318, + 233, 78, -38, 215, -22, -102, -187, 172, 173, -267, + -102, 157, -102, -182, 133, 13, -182, -179, 309, 307, + 294, 299, -182, -182, -182, -182, 216, 292, -233, 172, + 33, 183, 309, 216, 292, 216, 217, 216, 217, 302, + 312, 216, -202, 12, 135, 332, 297, 301, 209, 171, + 210, 173, 311, -263, 448, 217, -202, 89, 309, 212, + -182, -207, -285, -193, 265, -207, -207, 30, 174, -192, + -57, -192, 89, -7, -3, -11, -10, -12, 125, -78, + 309, -66, 151, 463, 449, 450, 451, 448, 306, 456, + 454, 452, 216, 453, 83, 116, 114, 115, 132, -86, + -110, 135, 117, 133, 134, 119, 137, 136, 147, 140, + 141, 142, 143, 144, 145, 146, 138, 139, 150, 125, + 126, 127, 128, 129, 130, 131, -177, -285, -128, -285, + 158, 159, -113, -113, -113, -113, -113, -113, -113, -113, + -113, -113, -285, 157, -2, -122, -4, -285, -285, -285, + -285, -285, -285, -285, -285, -135, -86, -285, -289, -285, + -289, -119, -285, -289, -119, -289, -119, -289, -289, -119, + -289, -119, -289, -289, -119, -285, -285, -285, -285, -285, + -285, -285, -206, -275, -276, -105, -102, -285, 233, -139, + -3, -55, -159, 20, 31, -86, -140, -141, -86, -139, + 57, -74, -76, -79, 61, 62, 95, 12, -195, -194, + 23, -192, 89, 157, 12, -103, 27, -102, -88, -89, + -90, -91, -105, -129, -285, 12, -95, -96, -102, -104, + -197, 83, 239, -172, -209, -174, -173, 322, 324, 125, + -196, -192, 89, 29, 84, 83, -102, -211, -214, -216, + -215, -217, -212, -213, 262, 263, 151, 266, 268, 269, + 270, 271, 272, 273, 274, 275, 276, 277, 30, 194, + 258, 259, 260, 261, 278, 279, 280, 281, 282, 283, + 284, 285, 245, 264, 352, 246, 247, 248, 249, 250, + 251, 253, 254, 255, 256, 257, -266, -263, 82, 84, + 83, -218, 82, -80, 171, -263, 172, 172, 172, -55, + 341, -238, -238, 202, -29, -26, -259, 16, -25, -26, + 165, 103, 104, 162, 82, -227, 82, -236, -266, -263, + 82, 113, 177, 112, -235, -232, -235, -236, -263, -130, + -192, -197, -263, 113, 113, -165, -192, -165, -165, 21, + -165, 21, -165, 21, 90, -192, -165, 21, -165, 21, + -165, 21, -165, 21, -165, 21, 29, 76, 77, 29, + 79, 80, 81, -130, -130, -227, -169, -102, -263, 90, + 90, -238, -238, 90, 89, 89, 89, -238, -238, 90, + 89, -199, -197, 89, -269, 188, 230, 232, 90, 90, + 90, 90, 29, 89, -270, 29, 470, 469, 471, 472, + 473, 90, 29, 90, 29, 90, -192, 82, -102, -83, + 220, 160, 162, 165, 74, 89, 234, 125, 42, 83, + 174, 171, -263, -184, 176, -184, -198, -197, -190, 89, + -86, -234, 12, 135, -202, -202, -182, -102, -234, -202, + -182, -102, -182, -182, -182, -182, -202, -202, -202, -182, + -197, -197, -102, -102, -102, -102, -102, -102, -102, -207, + -207, -207, -183, 133, -182, 448, 74, -205, 242, 276, + 442, 443, 444, 83, 354, -95, 448, 448, 448, 448, + 448, 448, -86, -86, -86, -86, -120, 99, 117, 100, + 101, -113, -121, -125, -128, 94, 135, 133, 134, 119, -113, -113, -113, -113, -113, -113, -113, -113, -113, -113, - -113, -113, -208, -263, 89, 151, -263, -112, -112, -192, - -75, 22, 36, -74, -193, -198, -190, -70, -286, -286, - -139, -74, -74, -86, -86, -130, 89, -74, -130, 89, - -74, -74, -69, 22, 36, -133, -134, 121, -130, -286, - -113, -192, -192, -74, -75, -75, -74, -74, 83, -277, - 324, 325, 446, -200, 205, -199, 23, -123, -122, 89, - -143, -286, -144, 27, 10, 135, 83, 19, 83, -142, - 25, 26, -143, -114, -192, 90, 93, -87, 83, 12, - -79, -102, -194, 142, -198, -102, -164, 205, -102, 30, - 83, -98, -100, -99, -101, 64, 68, 70, 65, 66, - 67, 71, -203, 23, -88, -3, -285, -102, -95, -287, - 83, 12, 75, -287, 83, 157, -172, -174, 83, 323, - 325, 326, 74, 102, -86, -220, 150, -245, -244, -243, - -227, -229, -230, -231, 84, -145, -85, 38, -223, 290, - 289, -218, -218, -218, -218, -218, -219, -169, -219, -219, - -219, 82, 82, -218, -218, -218, -218, -221, 82, -221, - -221, -222, 82, -222, -256, -86, -253, -252, -250, -251, - 181, 96, 354, 75, -248, -142, 90, -83, -185, 176, - -254, -251, -263, -263, -263, -185, -263, 89, -263, 89, - 83, 17, -228, -227, -131, 230, -258, 205, -255, -249, - -236, 113, -235, -236, -236, 157, -263, 83, 27, 107, - 107, 107, 107, 354, 162, 30, -227, -131, -208, 174, - -208, -208, 89, 89, -181, 478, -95, -82, 222, 125, - 211, 211, 171, 171, 224, -102, 235, 236, 234, 21, - 223, 225, 227, 213, -102, -102, -184, 74, -97, -102, - 24, -197, -102, -182, -182, -102, -182, -182, 89, -102, - -192, -66, 324, 354, 20, -67, 20, 99, 100, 101, - -121, -113, -113, -113, -73, 195, 116, -286, -286, -74, - -74, -285, 157, -5, -143, -286, -286, 83, 75, 23, - 12, 12, -286, 12, 12, -286, -286, -74, -136, -134, - 123, -86, -286, -286, 83, 83, -286, -286, -286, -286, - -286, -276, 445, 325, -106, 72, 175, 73, -285, -199, - -286, -159, 40, 48, 59, -86, -86, -141, -159, -176, - 20, 12, 55, 55, -107, 13, -76, -88, -79, 157, - -107, -111, 30, 55, -3, -285, -285, -167, -171, -130, - -89, -90, -90, -89, -90, 64, 64, 64, 69, 64, - 69, 64, -99, -197, -286, -286, -3, -164, 75, -88, - -102, -88, -104, -197, 142, -173, -175, 327, 324, 330, - -263, 89, 83, -243, -231, -282, 99, 117, 29, 74, - 287, 96, -280, -281, 177, 112, 113, 189, 23, 39, - -224, 291, -219, -219, -220, -263, 89, 151, -220, -220, - -220, -226, 89, -226, 90, 90, 84, -32, -27, -28, - 31, 78, -250, -238, 89, 37, -192, 84, -82, -102, - 117, 74, -254, -254, -254, -197, 16, -161, -192, 83, - 84, -132, 231, -130, 84, -192, 84, 82, -236, -236, - -193, -192, -285, 171, 29, 29, -131, -132, -220, -263, - 480, 479, 84, 173, 229, -84, 337, 89, 85, -102, - -102, -102, -102, -102, 165, 162, 214, 174, -95, -102, - 83, -60, 190, 185, -202, -202, 31, 324, 457, 455, - -73, 116, -113, -113, -286, -286, -75, -193, -139, -159, - -210, 151, 262, 194, 260, 256, 276, 267, 289, 258, - 290, -208, -210, -113, -113, -113, -113, 351, -139, 124, - -86, 122, -113, -113, 172, 172, 172, -165, 41, 89, - 89, 60, -102, -137, 14, -86, 142, -143, -166, 74, - -167, -124, -126, -125, -285, -160, -286, -192, -165, -107, - 83, 125, -93, -92, 74, 75, -94, 74, -92, 64, - 64, -286, -107, -88, -107, -107, 157, 324, 328, 329, - -243, 99, -113, 10, 89, 113, 113, -102, 82, -220, - -220, 84, 83, 84, 83, 84, 83, -186, 391, 117, - -28, -27, -238, -238, 90, -263, 173, 24, -102, 74, - 74, 74, 17, 83, -227, -130, 55, -253, -161, -257, - -258, -102, -112, -132, -102, -81, 220, 228, 82, 86, - -265, 75, 211, 287, 211, -102, -60, -32, -102, -182, - -182, 31, -263, -113, -286, -143, -286, -218, -218, -218, - -222, -218, 250, -218, 250, -286, -286, 20, 20, 20, - 20, -285, -65, 347, -86, 83, 83, -285, -285, -285, - -286, 89, -219, -138, 15, 17, 28, -166, 83, -286, - -286, 83, 55, 157, -286, -139, -171, -86, -86, 82, - -86, -139, -107, -116, 82, -113, -219, 89, -219, 90, - 90, 391, 29, 79, 80, 81, 29, 76, 77, -102, - -102, -102, -102, -161, -192, 207, 84, -286, 83, -225, - 354, 357, -162, 82, 84, -262, 354, -264, -263, -192, - -192, -192, -159, -219, -263, -113, -113, -113, -113, -113, - -143, 89, -113, -113, -163, -286, -192, 177, -163, -163, - -200, -219, -148, -153, -179, -86, -122, 113, -126, 55, - -3, -192, -124, -192, -143, -161, -143, -161, 84, -220, - -220, 84, 84, -162, 208, -281, -258, 358, 358, 23, - -161, -261, -260, -193, 82, 75, -286, -286, -286, -286, - -68, 135, 354, -286, -286, -286, 83, -286, -286, -286, - -106, -151, 441, -156, 44, -154, -155, 45, -152, 46, - 54, 10, -124, 157, 84, 84, -146, 23, -285, -3, - 84, 83, 125, -161, -102, -286, 352, 71, 355, -192, - 177, -148, 49, 268, -158, -157, 53, 45, -155, 17, - 47, 17, -167, -192, -272, -273, 74, -282, -279, 99, - 117, 96, -280, 108, 109, -3, -113, 204, -58, 354, - -260, -242, -193, 89, 90, 84, 60, 353, 356, -149, - 51, -147, 50, -147, -157, 17, 17, 89, 17, 89, - -273, 74, 11, 10, 99, 89, -58, -286, -286, -59, - 219, 445, -265, 60, -150, 52, 74, 102, 89, 89, - 89, -271, 190, 185, 188, 30, -271, 182, -262, 354, - 74, 102, 184, 29, 99, 221, 355, 356, + -113, -113, -113, -113, -113, -208, -263, 89, 151, -263, + -112, -112, -192, -75, 22, 36, -74, -193, -198, -190, + -70, -286, -286, -139, -74, -74, -86, -86, -130, 89, + -74, -130, 89, -74, -74, -69, 22, 36, -133, -134, + 121, -130, -286, -113, -192, -192, -74, -75, -75, -74, + -74, 83, -277, 324, 325, 446, -200, 205, -199, 23, + -123, -122, 89, -143, -286, -144, 27, 10, 135, 83, + 19, 83, -142, 25, 26, -143, -114, -192, 90, 93, + -87, 83, 12, -79, -102, -194, 142, -198, -102, -164, + 205, -102, 30, 83, -98, -100, -99, -101, 64, 68, + 70, 65, 66, 67, 71, -203, 23, -88, -3, -285, + -102, -95, -287, 83, 12, 75, -287, 83, 157, -172, + -174, 83, 323, 325, 326, 74, 102, -86, -220, 150, + -245, -244, -243, -227, -229, -230, -231, 84, -145, -85, + 38, -223, 290, 289, -218, -218, -218, -218, -218, -219, + -169, -219, -219, -219, 82, 82, -218, -218, -218, -218, + -221, 82, -221, -221, -222, 82, -222, -256, -86, -253, + -252, -250, -251, 181, 96, 354, 75, -248, -142, 90, + -83, -185, 176, -254, -251, -263, -263, -263, -185, -263, + 89, -263, 89, 83, 17, -228, -227, -131, 230, -258, + 205, -255, -249, -236, 113, -235, -236, -236, 157, -263, + 83, 27, 107, 107, 107, 107, 354, 162, 30, -227, + -131, -208, 174, -208, -208, 89, 89, -181, 478, -95, + -82, 222, 125, 211, 211, 171, 171, 224, -102, 235, + 236, 234, 21, 223, 225, 227, 213, -102, -102, -184, + 74, -97, -102, 24, -197, -102, -182, -182, -102, -182, + -182, 89, -102, -192, -66, 324, 354, 20, -67, 20, + 99, 100, 101, -121, -113, -113, -113, -73, 195, 116, + -286, -286, -74, -74, -285, 157, -5, -143, -286, -286, + 83, 75, 23, 12, 12, -286, 12, 12, -286, -286, + -74, -136, -134, 123, -86, -286, -286, 83, 83, -286, + -286, -286, -286, -286, -276, 445, 325, -106, 72, 175, + 73, -285, -199, -286, -159, 40, 48, 59, -86, -86, + -141, -159, -176, 20, 12, 55, 55, -107, 13, -76, + -88, -79, 157, -107, -111, 30, 55, -3, -285, -285, + -167, -171, -130, -89, -90, -90, -89, -90, 64, 64, + 64, 69, 64, 69, 64, -99, -197, -286, -286, -3, + -164, 75, -88, -102, -88, -104, -197, 142, -173, -175, + 327, 324, 330, -263, 89, 83, -243, -231, -282, 99, + 117, 29, 74, 287, 96, -280, -281, 177, 112, 113, + 189, 23, 39, -224, 291, -219, -219, -220, -263, 89, + 151, -220, -220, -220, -226, 89, -226, 90, 90, 84, + -32, -27, -28, 31, 78, -250, -238, 89, 37, -192, + 84, -82, -102, 117, 74, -254, -254, -254, -197, 16, + -161, -192, 83, 84, -132, 231, -130, 84, -192, 84, + 82, -236, -236, -193, -192, -285, 171, 29, 29, -131, + -132, -220, -263, 480, 479, 84, 173, 229, -84, 337, + 89, 85, -102, -102, -102, -102, -102, 165, 162, 214, + 174, -95, -102, 83, -60, 190, 185, -202, -202, 31, + 324, 457, 455, -73, 116, -113, -113, -286, -286, -75, + -193, -139, -159, -210, 151, 262, 194, 260, 256, 276, + 267, 289, 258, 290, -208, -210, -113, -113, -113, -113, + 351, -139, 124, -86, 122, -113, -113, 172, 172, 172, + -165, 41, 89, 89, 60, -102, -137, 14, -86, 142, + -143, -166, 74, -167, -124, -126, -125, -285, -160, -286, + -192, -165, -107, 83, 125, -93, -92, 74, 75, -94, + 74, -92, 64, 64, -286, -107, -88, -107, -107, 157, + 324, 328, 329, -243, 99, -113, 10, 89, 113, 113, + -102, 82, -220, -220, 84, 83, 84, 83, 84, 83, + -186, 391, 117, -28, -27, -238, -238, 90, -263, 173, + 24, -102, 74, 74, 74, 17, 83, -227, -130, 55, + -253, -161, -257, -258, -102, -112, -132, -102, -81, 220, + 228, 82, 86, -265, 75, 211, 287, 211, -102, -60, + -32, -102, -182, -182, 31, -263, -113, -286, -143, -286, + -218, -218, -218, -222, -218, 250, -218, 250, -286, -286, + 20, 20, 20, 20, -285, -65, 347, -86, 83, 83, + -285, -285, -285, -286, 89, -219, -138, 15, 17, 28, + -166, 83, -286, -286, 83, 55, 157, -286, -139, -171, + -86, -86, 82, -86, -139, -107, -116, 82, -113, -219, + 89, -219, 90, 90, 391, 29, 79, 80, 81, 29, + 76, 77, -102, -102, -102, -102, -161, -192, 207, 84, + -286, 83, -225, 354, 357, -162, 82, 84, -262, 354, + -264, -263, -192, -192, -192, -159, -219, -263, -113, -113, + -113, -113, -113, -143, 89, -113, -113, -163, -286, -192, + 177, -163, -163, -200, -219, -148, -153, -179, -86, -122, + 113, -126, 55, -3, -192, -124, -192, -143, -161, -143, + -161, 84, -220, -220, 84, 84, -162, 208, -281, -258, + 358, 358, 23, -161, -261, -260, -193, 82, 75, -286, + -286, -286, -286, -68, 135, 354, -286, -286, -286, 83, + -286, -286, -286, -106, -151, 441, -156, 44, -154, -155, + 45, -152, 46, 54, 10, -124, 157, 84, 84, -146, + 23, -285, -3, 84, 83, 125, -161, -102, -286, 352, + 71, 355, -192, 177, -148, 49, 268, -158, -157, 53, + 45, -155, 17, 47, 17, -167, -192, -272, -273, 74, + -282, -279, 99, 117, 96, -280, 108, 109, -3, -113, + 204, -58, 354, -260, -242, -193, 89, 90, 84, 60, + 353, 356, -149, 51, -147, 50, -147, -157, 17, 17, + 89, 17, 89, -273, 74, 11, 10, 99, 89, -58, + -286, -286, -59, 219, 445, -265, 60, -150, 52, 74, + 102, 89, 89, 89, -271, 190, 185, 188, 30, -271, + 182, -262, 354, 74, 102, 184, 29, 99, 221, 355, + 356, } var yyDef = [...]int{ 34, -2, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 842, 0, 574, 574, 574, 574, 574, - 574, 574, 0, 0, 574, -2, -2, 574, 978, 0, - 574, 0, 0, -2, 507, 508, 0, 510, -2, 0, - 0, 519, 1397, 1397, 569, 0, 0, 0, 0, 0, - 574, 1395, 55, 56, 525, 526, 527, 1, 3, 0, - 578, 850, 0, 0, -2, 576, 0, 0, 961, 961, - 961, 0, 86, 87, 0, 0, 0, -2, 90, -2, + 31, 32, 33, 843, 0, 575, 575, 575, 575, 575, + 575, 575, 0, 0, 575, -2, -2, 575, 979, 0, + 575, 0, 0, -2, 508, 509, 0, 511, -2, 0, + 0, 520, 1398, 1398, 570, 0, 0, 0, 0, 0, + 575, 1396, 55, 56, 526, 527, 528, 1, 3, 0, + 579, 851, 0, 0, -2, 577, 0, 0, 962, 962, + 962, 0, 86, 87, 0, 0, 0, -2, 90, -2, 114, 115, 0, 119, 383, 344, 386, 342, 372, -2, 335, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 347, 237, 237, 0, 0, -2, 335, - 335, 335, 0, 0, 0, 369, 963, 290, 237, 237, + 335, 335, 0, 0, 0, 369, 964, 290, 237, 237, 0, 237, 237, 237, 237, 0, 0, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, - 237, 237, 866, 118, 979, 976, 977, 35, 36, 37, - 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, - 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, - 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, - 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, - 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, - 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, - 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, - 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, - 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210, - 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, - 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, - 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, - 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, - 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1260, - 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270, - 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, - 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, - 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, 1300, - 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, - 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, - 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, - 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, - 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, - 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, - 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, - 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, - 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, - 1391, 1392, 1393, 1394, 0, 955, 0, 439, 663, 0, - 498, 498, 0, 498, 498, 498, 498, 0, 0, 0, - 451, 0, 0, 0, 0, 495, 0, 0, 470, 472, - 0, 495, 0, 482, 498, 1398, 1398, 1398, 946, 0, - 492, 490, 504, 505, 487, 488, 506, 509, 0, 514, - 517, 972, 973, 0, 532, 0, 1200, 524, 537, 538, - 0, 570, 571, 40, 714, 673, 0, 679, 681, 0, - 716, 717, 718, 719, 720, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 746, 747, 748, 749, 827, - 828, 829, 830, 831, 832, 833, 834, 683, 684, 824, - 0, 935, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 815, 0, 784, 784, 784, 784, 784, 784, 784, - 784, 784, 0, 0, 0, 0, 0, 0, 0, -2, - -2, 1397, 0, 547, 0, 0, 842, 51, 0, 574, - 579, 580, 885, 0, 0, 842, 1396, 0, 0, -2, - -2, 590, 596, 597, 598, 599, 600, 575, 0, 603, - 607, 0, 0, 0, 962, 0, 0, 72, 0, 1359, - 939, -2, -2, 0, 0, 974, 975, 948, -2, 982, + 237, 237, 867, 118, 980, 977, 978, 35, 36, 37, + 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, + 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, + 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, + 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, + 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, + 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, + 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, + 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, + 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210, 1211, + 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, + 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, + 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, + 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, 1251, + 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1260, 1261, + 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, + 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, + 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, + 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, 1300, 1301, + 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311, + 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, + 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, + 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, + 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, + 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, + 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, 1371, + 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, + 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, + 1392, 1393, 1394, 1395, 0, 956, 0, 439, 664, 0, + 499, 499, 0, 499, 499, 499, 499, 0, 0, 0, + 451, 0, 0, 0, 0, 496, 0, 0, 470, 472, + 0, 496, 0, 0, 483, 499, 1399, 1399, 1399, 947, + 0, 493, 491, 505, 506, 488, 489, 507, 510, 0, + 515, 518, 973, 974, 0, 533, 0, 1201, 525, 538, + 539, 0, 571, 572, 40, 715, 674, 0, 680, 682, + 0, 717, 718, 719, 720, 721, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 747, 748, 749, 750, + 828, 829, 830, 831, 832, 833, 834, 835, 684, 685, + 825, 0, 936, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 816, 0, 785, 785, 785, 785, 785, 785, + 785, 785, 785, 0, 0, 0, 0, 0, 0, 0, + -2, -2, 1398, 0, 548, 0, 0, 843, 51, 0, + 575, 580, 581, 886, 0, 0, 843, 1397, 0, 0, + -2, -2, 591, 597, 598, 599, 600, 601, 576, 0, + 604, 608, 0, 0, 0, 963, 0, 0, 72, 0, + 1360, 940, -2, -2, 0, 0, 975, 976, 949, -2, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, @@ -5391,161 +5442,162 @@ var yyDef = [...]int{ 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, - 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, -2, 0, - 0, 128, 129, 0, 38, 263, 0, 124, 0, 257, - 209, 866, 0, 0, 0, 0, 0, 574, 0, 956, - 109, 110, 116, 117, 237, 237, 0, 118, 118, 351, - 352, 353, 0, 0, -2, 261, 0, 336, 0, 0, - 251, 251, 255, 253, 254, 0, 0, 0, 0, 0, - 0, 363, 0, 364, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 423, 0, 238, 0, 381, 382, 291, - 0, 0, 0, 0, 361, 362, 0, 0, 964, 965, - 0, 0, 237, 237, 0, 0, 0, 0, 237, 237, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 108, 879, 0, 0, - 0, -2, 0, 431, 0, 0, 0, 957, 957, 438, - 0, 440, 441, 0, 0, 442, 0, 495, 495, 493, - 494, 444, 445, 446, 447, 498, 0, 0, 246, 247, - 248, 495, 498, 0, 498, 498, 498, 498, 495, 495, - 495, 498, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1398, 1398, 1398, 501, 498, 479, 480, 483, 484, - 1399, 1400, 993, 485, 486, 947, 515, 518, 535, 533, - 534, 536, 528, 529, 530, 531, 0, 549, 550, 555, - 0, 0, 0, 0, 561, 562, 563, 0, 0, 566, - 567, 568, 0, 0, 0, 0, 0, 677, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 701, 702, 703, - 704, 705, 706, 707, 680, 0, 694, 0, 0, 0, - 736, 737, 738, 739, 740, 741, 742, 743, 744, 0, - 587, 0, 0, 0, 842, 0, 0, 0, 0, 0, - 0, 0, 584, 0, 816, 0, 767, 0, 768, 776, - 0, 769, 777, 770, 778, 771, 772, 779, 773, 780, - 774, 775, 781, 0, 0, 0, 587, 587, 0, 0, - 41, 539, 540, 0, 646, 967, 0, 850, 0, 589, - 888, 0, 0, 851, 843, 844, 847, 850, 0, 612, - 601, 591, 594, 595, 577, 0, 604, 608, 0, 610, - 611, 0, 0, 70, 0, 662, 0, 614, 616, 617, - 618, 644, 0, 0, 0, 0, 66, 68, 663, 0, - 1359, 945, 0, 74, 75, 0, 0, 0, 225, 950, - 951, 952, -2, 244, 0, -2, 216, 160, 161, 162, - 209, 164, 209, 209, 209, 209, 221, 221, 221, 221, - 192, 193, 194, 195, 196, 0, 0, 179, 209, 209, - 209, 209, 199, 200, 201, 202, 203, 204, 205, 206, - 165, 166, 167, 168, 169, 170, 171, 172, 173, 211, - 211, 211, 213, 213, 0, 39, 0, 229, 0, 847, - 0, 879, 959, 969, 0, 0, 0, 959, 92, 0, - 0, 384, 345, 373, 385, 0, 348, 349, -2, 0, - 0, 335, 0, 337, 0, 245, 0, -2, 0, 255, - 0, 251, 255, 252, 255, 243, 256, 365, 824, 0, - 366, 367, 0, 403, 632, 0, 0, 0, 0, 0, - 409, 410, 411, 0, 413, 414, 415, 416, 417, 418, - 419, 420, 421, 422, 374, 375, 376, 377, 378, 379, - 380, 0, 0, 337, 0, 370, 0, 292, 293, 0, - 0, 296, 297, 298, 299, 0, 0, 302, 303, 304, - 649, 650, 305, 329, 330, 331, 306, 307, 308, 309, - 310, 311, 312, 323, 324, 325, 326, 327, 328, 313, - 314, 315, 316, 317, 320, 0, 102, 870, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 957, - 0, 0, 0, 0, 664, 980, 981, 499, 500, 0, - 249, 250, 498, 498, 448, 471, 0, 498, 452, 473, - 453, 455, 454, 456, 475, 476, 498, 459, 496, 497, - 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, - 477, 0, 478, 0, 0, 516, 520, 521, 522, 523, - 0, 0, 552, 557, 558, 559, 560, 572, 565, 715, - 674, 675, 676, 678, 695, 0, 697, 699, 685, 686, - 710, 711, 712, 0, 0, 0, 0, 708, 690, 0, - 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, - 731, 732, 735, 799, 800, 801, 0, 733, 734, 745, - 0, 0, 0, 588, 825, 0, -2, 0, 713, 934, - 850, 0, 0, 0, 0, 718, 827, 0, 718, 827, - 0, 0, 0, 585, 586, 822, 819, 0, 0, 785, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 542, - 543, 545, 0, 666, 0, 647, 0, 0, 968, 548, - 885, 52, 42, 0, 886, 0, 0, 0, 0, 846, - 848, 849, 885, 0, 835, 0, 0, 671, 0, 0, - 592, 48, 609, 605, 0, 671, 0, 0, 661, 0, - 0, 0, 0, 0, 0, 651, 0, 0, 654, 0, - 0, 0, 0, 645, 0, 0, 0, -2, 0, 0, - 0, 62, 63, 0, 0, 0, 940, 73, 0, 0, - 78, 79, 941, 942, 943, 944, 0, 111, -2, 287, - 130, 132, 133, 134, 125, 269, 0, 0, 219, 217, - 218, 163, 221, 221, 186, 187, 225, 0, 225, 225, - 225, 0, 0, 180, 181, 182, 183, 174, 0, 175, - 176, 177, 0, 178, 262, 0, 854, 230, 231, 233, - 237, 0, 0, 0, 258, 259, 0, 870, 0, 0, - 0, 970, 969, 969, 969, 0, 120, 121, 122, 123, - 118, 0, 0, 126, 339, 0, 0, 0, 260, 0, - 0, 255, 255, 240, 241, 0, 368, 0, 0, 405, - 406, 407, 408, 0, 0, 0, 337, 339, 225, 0, - 294, 295, 300, 301, 318, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 398, 399, 400, 401, - 867, 868, 869, 0, 0, 432, 0, 0, 279, 64, - 958, 437, 495, 458, 474, 495, 450, 457, 502, 481, - 512, 556, 0, 0, 0, 564, 0, 696, 698, 700, - 687, 708, 691, 0, 688, 0, 0, 682, 750, 0, - 0, 587, 0, 842, 885, 754, 755, 0, 0, 0, - 0, 0, 792, 0, 0, 793, 0, 842, 0, 820, - 0, 0, 766, 786, 0, 0, 787, 788, 789, 790, - 791, 541, 544, 546, 622, 0, 0, 0, 0, 648, - 966, 44, 0, 0, 0, 852, 853, 845, 43, 0, - 953, 954, 836, 837, 838, 0, 602, 613, 593, 0, - 850, 928, 0, 0, 920, 0, 0, 671, 936, 0, - 615, 640, 642, 0, 637, 652, 653, 655, 0, 657, - 0, 659, 660, 619, 620, 621, 0, 671, 0, 671, - 67, 671, 69, 0, 665, 76, 77, 0, 0, 83, - 226, 227, 118, 289, 131, 135, 140, 0, 0, 0, - 144, 0, 146, 270, 0, 156, 158, 0, 0, 138, - 159, 220, 225, 225, 188, 222, 223, 224, 189, 190, - 191, 0, 207, 0, 0, 0, 282, 88, 858, 857, - 237, 237, 232, 0, 235, 0, 971, 210, 0, 101, - 0, 0, 0, 0, 0, 107, 0, 343, 626, 0, - 354, 355, 0, 338, 402, 0, 229, 0, 239, 242, - 825, 633, 0, 0, 356, 0, 339, 359, 360, 371, - 321, 322, 319, 0, 0, 880, 881, 0, 884, 93, - 391, 393, 392, 396, 0, 0, 389, 0, 279, 854, - 0, 436, 280, 281, 498, 498, 551, 0, 554, 0, - 689, 0, 709, 692, 751, 752, 0, 826, 850, 46, - 0, 209, 209, 805, 209, 213, 808, 209, 810, 209, - 813, 0, 0, 0, 0, 0, 0, 0, 817, 765, - 823, 0, 0, 0, 0, 0, 0, 0, 0, 221, - 890, 887, 45, 840, 0, 672, 606, 49, 53, 0, - 928, 919, 930, 932, 0, 0, 0, 924, 0, 842, - 0, 0, 634, 641, 0, 0, 635, 0, 636, 656, - 658, -2, 842, 671, 60, 61, 0, 80, 81, 82, - 288, 141, 142, 0, 145, 155, 157, 0, 0, 184, - 185, 221, 0, 221, 0, 214, 0, 271, 283, 0, - 855, 856, 0, 0, 234, 236, 0, 960, 103, 0, - 0, 0, 0, 0, 127, 340, 0, 228, 0, 0, - 427, 424, 357, 358, 624, 871, 872, 873, 0, 883, - 96, 0, 0, 0, 0, 433, 434, 435, 65, 443, - 449, 553, 573, 693, 753, 885, 756, 802, 221, 806, - 807, 809, 811, 812, 814, 758, 757, 0, 0, 0, - 0, 0, 850, 0, 821, 0, 0, 0, 0, 0, - 646, 221, 910, 50, 0, 0, 0, 54, 0, 933, - 0, 0, 0, 0, 71, 850, 937, 938, 638, 0, - 643, 850, 59, 143, 0, 0, 225, 208, 225, 0, - 0, 284, 859, 860, 861, 862, 863, 864, 865, 624, - 104, 105, 106, 346, 627, 0, 0, 404, 0, 412, - 0, 0, 0, 0, 882, 390, 0, 94, 95, 0, - 0, 395, 47, 803, 804, 0, 0, 0, 0, 794, - 0, 818, 0, 0, 0, 668, 628, 629, 0, 0, - 666, 892, 891, 904, 917, 841, 839, 0, 931, 0, - 923, 926, 922, 925, 57, 0, 58, 0, 149, 197, - 198, 212, 215, 0, 0, 264, 428, 425, 426, 0, - 0, 97, 98, 0, 0, 0, 759, 761, 760, 762, - 0, 0, 0, 764, 782, 783, 0, 667, 669, 670, - 623, 910, 0, 903, 0, -2, 912, 0, 0, 0, - 918, 0, 921, 0, 639, 265, 269, 0, 0, 874, - 625, 0, 0, 0, 397, 763, 0, 0, 0, 630, - 631, 897, 895, 895, 905, 906, 0, 0, 913, 0, - 0, 0, 929, 927, 266, 267, 0, 136, 150, 151, - 0, 0, 154, 147, 148, 874, 0, 0, 387, 876, - 99, 100, 332, 333, 334, 93, 795, 0, 798, 900, - 0, 893, 896, 894, 907, 0, 0, 914, 0, 916, - 268, 0, 0, 0, 152, 153, 89, 429, 430, 0, - 877, 878, 96, 796, 889, 0, 898, 899, 908, 909, - 915, 272, 274, 275, 0, 0, 273, 0, 394, 0, - 901, 902, 276, 277, 278, 875, 0, 797, + 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, -2, + 0, 0, 128, 129, 0, 38, 263, 0, 124, 0, + 257, 209, 867, 0, 0, 0, 0, 0, 575, 0, + 957, 109, 110, 116, 117, 237, 237, 0, 118, 118, + 351, 352, 353, 0, 0, -2, 261, 0, 336, 0, + 0, 251, 251, 255, 253, 254, 0, 0, 0, 0, + 0, 0, 363, 0, 364, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 423, 0, 238, 0, 381, 382, + 291, 0, 0, 0, 0, 361, 362, 0, 0, 965, + 966, 0, 0, 237, 237, 0, 0, 0, 0, 237, + 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 108, 880, 0, + 0, 0, -2, 0, 431, 0, 0, 0, 958, 958, + 438, 0, 440, 441, 0, 0, 442, 0, 496, 496, + 494, 495, 444, 445, 446, 447, 499, 0, 0, 246, + 247, 248, 496, 499, 0, 499, 499, 499, 499, 496, + 496, 496, 499, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1399, 1399, 1399, 502, 499, 0, 480, 481, + 484, 485, 1400, 1401, 994, 486, 487, 948, 516, 519, + 536, 534, 535, 537, 529, 530, 531, 532, 0, 550, + 551, 556, 0, 0, 0, 0, 562, 563, 564, 0, + 0, 567, 568, 569, 0, 0, 0, 0, 0, 678, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 702, + 703, 704, 705, 706, 707, 708, 681, 0, 695, 0, + 0, 0, 737, 738, 739, 740, 741, 742, 743, 744, + 745, 0, 588, 0, 0, 0, 843, 0, 0, 0, + 0, 0, 0, 0, 585, 0, 817, 0, 768, 0, + 769, 777, 0, 770, 778, 771, 779, 772, 773, 780, + 774, 781, 775, 776, 782, 0, 0, 0, 588, 588, + 0, 0, 41, 540, 541, 0, 647, 968, 0, 851, + 0, 590, 889, 0, 0, 852, 844, 845, 848, 851, + 0, 613, 602, 592, 595, 596, 578, 0, 605, 609, + 0, 611, 612, 0, 0, 70, 0, 663, 0, 615, + 617, 618, 619, 645, 0, 0, 0, 0, 66, 68, + 664, 0, 1360, 946, 0, 74, 75, 0, 0, 0, + 225, 951, 952, 953, -2, 244, 0, -2, 216, 160, + 161, 162, 209, 164, 209, 209, 209, 209, 221, 221, + 221, 221, 192, 193, 194, 195, 196, 0, 0, 179, + 209, 209, 209, 209, 199, 200, 201, 202, 203, 204, + 205, 206, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 211, 211, 211, 213, 213, 0, 39, 0, 229, + 0, 848, 0, 880, 960, 970, 0, 0, 0, 960, + 92, 0, 0, 384, 345, 373, 385, 0, 348, 349, + -2, 0, 0, 335, 0, 337, 0, 245, 0, -2, + 0, 255, 0, 251, 255, 252, 255, 243, 256, 365, + 825, 0, 366, 367, 0, 403, 633, 0, 0, 0, + 0, 0, 409, 410, 411, 0, 413, 414, 415, 416, + 417, 418, 419, 420, 421, 422, 374, 375, 376, 377, + 378, 379, 380, 0, 0, 337, 0, 370, 0, 292, + 293, 0, 0, 296, 297, 298, 299, 0, 0, 302, + 303, 304, 650, 651, 305, 329, 330, 331, 306, 307, + 308, 309, 310, 311, 312, 323, 324, 325, 326, 327, + 328, 313, 314, 315, 316, 317, 320, 0, 102, 871, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 958, 0, 0, 0, 0, 665, 981, 982, 500, + 501, 0, 249, 250, 499, 499, 448, 471, 0, 499, + 452, 473, 453, 455, 454, 456, 475, 476, 499, 459, + 497, 498, 460, 461, 462, 463, 464, 465, 466, 467, + 468, 469, 477, 0, 478, 479, 0, 0, 517, 521, + 522, 523, 524, 0, 0, 553, 558, 559, 560, 561, + 573, 566, 716, 675, 676, 677, 679, 696, 0, 698, + 700, 686, 687, 711, 712, 713, 0, 0, 0, 0, + 709, 691, 0, 722, 723, 724, 725, 726, 727, 728, + 729, 730, 731, 732, 733, 736, 800, 801, 802, 0, + 734, 735, 746, 0, 0, 0, 589, 826, 0, -2, + 0, 714, 935, 851, 0, 0, 0, 0, 719, 828, + 0, 719, 828, 0, 0, 0, 586, 587, 823, 820, + 0, 0, 786, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 543, 544, 546, 0, 667, 0, 648, 0, + 0, 969, 549, 886, 52, 42, 0, 887, 0, 0, + 0, 0, 847, 849, 850, 886, 0, 836, 0, 0, + 672, 0, 0, 593, 48, 610, 606, 0, 672, 0, + 0, 662, 0, 0, 0, 0, 0, 0, 652, 0, + 0, 655, 0, 0, 0, 0, 646, 0, 0, 0, + -2, 0, 0, 0, 62, 63, 0, 0, 0, 941, + 73, 0, 0, 78, 79, 942, 943, 944, 945, 0, + 111, -2, 287, 130, 132, 133, 134, 125, 269, 0, + 0, 219, 217, 218, 163, 221, 221, 186, 187, 225, + 0, 225, 225, 225, 0, 0, 180, 181, 182, 183, + 174, 0, 175, 176, 177, 0, 178, 262, 0, 855, + 230, 231, 233, 237, 0, 0, 0, 258, 259, 0, + 871, 0, 0, 0, 971, 970, 970, 970, 0, 120, + 121, 122, 123, 118, 0, 0, 126, 339, 0, 0, + 0, 260, 0, 0, 255, 255, 240, 241, 0, 368, + 0, 0, 405, 406, 407, 408, 0, 0, 0, 337, + 339, 225, 0, 294, 295, 300, 301, 318, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 398, + 399, 400, 401, 868, 869, 870, 0, 0, 432, 0, + 0, 279, 64, 959, 437, 496, 458, 474, 496, 450, + 457, 503, 482, 513, 557, 0, 0, 0, 565, 0, + 697, 699, 701, 688, 709, 692, 0, 689, 0, 0, + 683, 751, 0, 0, 588, 0, 843, 886, 755, 756, + 0, 0, 0, 0, 0, 793, 0, 0, 794, 0, + 843, 0, 821, 0, 0, 767, 787, 0, 0, 788, + 789, 790, 791, 792, 542, 545, 547, 623, 0, 0, + 0, 0, 649, 967, 44, 0, 0, 0, 853, 854, + 846, 43, 0, 954, 955, 837, 838, 839, 0, 603, + 614, 594, 0, 851, 929, 0, 0, 921, 0, 0, + 672, 937, 0, 616, 641, 643, 0, 638, 653, 654, + 656, 0, 658, 0, 660, 661, 620, 621, 622, 0, + 672, 0, 672, 67, 672, 69, 0, 666, 76, 77, + 0, 0, 83, 226, 227, 118, 289, 131, 135, 140, + 0, 0, 0, 144, 0, 146, 270, 0, 156, 158, + 0, 0, 138, 159, 220, 225, 225, 188, 222, 223, + 224, 189, 190, 191, 0, 207, 0, 0, 0, 282, + 88, 859, 858, 237, 237, 232, 0, 235, 0, 972, + 210, 0, 101, 0, 0, 0, 0, 0, 107, 0, + 343, 627, 0, 354, 355, 0, 338, 402, 0, 229, + 0, 239, 242, 826, 634, 0, 0, 356, 0, 339, + 359, 360, 371, 321, 322, 319, 0, 0, 881, 882, + 0, 885, 93, 391, 393, 392, 396, 0, 0, 389, + 0, 279, 855, 0, 436, 280, 281, 499, 499, 552, + 0, 555, 0, 690, 0, 710, 693, 752, 753, 0, + 827, 851, 46, 0, 209, 209, 806, 209, 213, 809, + 209, 811, 209, 814, 0, 0, 0, 0, 0, 0, + 0, 818, 766, 824, 0, 0, 0, 0, 0, 0, + 0, 0, 221, 891, 888, 45, 841, 0, 673, 607, + 49, 53, 0, 929, 920, 931, 933, 0, 0, 0, + 925, 0, 843, 0, 0, 635, 642, 0, 0, 636, + 0, 637, 657, 659, -2, 843, 672, 60, 61, 0, + 80, 81, 82, 288, 141, 142, 0, 145, 155, 157, + 0, 0, 184, 185, 221, 0, 221, 0, 214, 0, + 271, 283, 0, 856, 857, 0, 0, 234, 236, 0, + 961, 103, 0, 0, 0, 0, 0, 127, 340, 0, + 228, 0, 0, 427, 424, 357, 358, 625, 872, 873, + 874, 0, 884, 96, 0, 0, 0, 0, 433, 434, + 435, 65, 443, 449, 554, 574, 694, 754, 886, 757, + 803, 221, 807, 808, 810, 812, 813, 815, 759, 758, + 0, 0, 0, 0, 0, 851, 0, 822, 0, 0, + 0, 0, 0, 647, 221, 911, 50, 0, 0, 0, + 54, 0, 934, 0, 0, 0, 0, 71, 851, 938, + 939, 639, 0, 644, 851, 59, 143, 0, 0, 225, + 208, 225, 0, 0, 284, 860, 861, 862, 863, 864, + 865, 866, 625, 104, 105, 106, 346, 628, 0, 0, + 404, 0, 412, 0, 0, 0, 0, 883, 390, 0, + 94, 95, 0, 0, 395, 47, 804, 805, 0, 0, + 0, 0, 795, 0, 819, 0, 0, 0, 669, 629, + 630, 0, 0, 667, 893, 892, 905, 918, 842, 840, + 0, 932, 0, 924, 927, 923, 926, 57, 0, 58, + 0, 149, 197, 198, 212, 215, 0, 0, 264, 428, + 425, 426, 0, 0, 97, 98, 0, 0, 0, 760, + 762, 761, 763, 0, 0, 0, 765, 783, 784, 0, + 668, 670, 671, 624, 911, 0, 904, 0, -2, 913, + 0, 0, 0, 919, 0, 922, 0, 640, 265, 269, + 0, 0, 875, 626, 0, 0, 0, 397, 764, 0, + 0, 0, 631, 632, 898, 896, 896, 906, 907, 0, + 0, 914, 0, 0, 0, 930, 928, 266, 267, 0, + 136, 150, 151, 0, 0, 154, 147, 148, 875, 0, + 0, 387, 877, 99, 100, 332, 333, 334, 93, 796, + 0, 799, 901, 0, 894, 897, 895, 908, 0, 0, + 915, 0, 917, 268, 0, 0, 0, 152, 153, 89, + 429, 430, 0, 878, 879, 96, 797, 890, 0, 899, + 900, 909, 910, 916, 272, 274, 275, 0, 0, 273, + 0, 394, 0, 902, 903, 276, 277, 278, 876, 0, + 798, } var yyTok1 = [...]int{ @@ -9374,11 +9426,11 @@ yydefault: } yyVAL.union = yyLOCAL case 479: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL Statement //line sql.y:2607 { - yyLOCAL = &Show{&ShowLegacy{Type: string(yyDollar[2].str) + " " + string(yyDollar[3].str), Scope: ImplicitScope}} + yyLOCAL = &ShowMigrationLogs{UUID: string(yyDollar[3].str)} } yyVAL.union = yyLOCAL case 480: @@ -9390,38 +9442,38 @@ yydefault: } yyVAL.union = yyLOCAL case 481: - yyDollar = yyS[yypt-5 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Statement //line sql.y:2615 { - yyLOCAL = &Show{&ShowLegacy{Type: string(yyDollar[2].str) + " " + string(yyDollar[3].str), OnTable: yyDollar[5].tableName, Scope: ImplicitScope}} + yyLOCAL = &Show{&ShowLegacy{Type: string(yyDollar[2].str) + " " + string(yyDollar[3].str), Scope: ImplicitScope}} } yyVAL.union = yyLOCAL case 482: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL Statement //line sql.y:2619 { - yyLOCAL = &Show{&ShowBasic{Command: Warnings}} + yyLOCAL = &Show{&ShowLegacy{Type: string(yyDollar[2].str) + " " + string(yyDollar[3].str), OnTable: yyDollar[5].tableName, Scope: ImplicitScope}} } yyVAL.union = yyLOCAL case 483: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Statement -//line sql.y:2624 +//line sql.y:2623 { - // This should probably be a different type (ShowVitessTopoOpt), but - // just getting the thing working for now - showTablesOpt := &ShowTablesOpt{Filter: yyDollar[3].showFilterUnion()} - yyLOCAL = &Show{&ShowLegacy{Type: yyDollar[2].str, ShowTablesOpt: showTablesOpt}} + yyLOCAL = &Show{&ShowBasic{Command: Warnings}} } yyVAL.union = yyLOCAL case 484: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Statement -//line sql.y:2638 +//line sql.y:2628 { - yyLOCAL = &Show{&ShowLegacy{Type: string(yyDollar[2].colIdent.String()), Scope: ImplicitScope}} + // This should probably be a different type (ShowVitessTopoOpt), but + // just getting the thing working for now + showTablesOpt := &ShowTablesOpt{Filter: yyDollar[3].showFilterUnion()} + yyLOCAL = &Show{&ShowLegacy{Type: yyDollar[2].str, ShowTablesOpt: showTablesOpt}} } yyVAL.union = yyLOCAL case 485: @@ -9429,7 +9481,7 @@ yydefault: var yyLOCAL Statement //line sql.y:2642 { - yyLOCAL = &Show{&ShowLegacy{Type: string(yyDollar[2].str), Scope: ImplicitScope}} + yyLOCAL = &Show{&ShowLegacy{Type: string(yyDollar[2].colIdent.String()), Scope: ImplicitScope}} } yyVAL.union = yyLOCAL case 486: @@ -9441,11 +9493,13 @@ yydefault: } yyVAL.union = yyLOCAL case 487: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2652 + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL Statement +//line sql.y:2650 { - yyVAL.str = string(yyDollar[1].str) + yyLOCAL = &Show{&ShowLegacy{Type: string(yyDollar[2].str), Scope: ImplicitScope}} } + yyVAL.union = yyLOCAL case 488: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2656 @@ -9453,39 +9507,39 @@ yydefault: yyVAL.str = string(yyDollar[1].str) } case 489: + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:2660 + { + yyVAL.str = string(yyDollar[1].str) + } + case 490: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2662 +//line sql.y:2666 { yyVAL.str = "" } - case 490: + case 491: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2666 +//line sql.y:2670 { yyVAL.str = "extended " } - case 491: + case 492: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL bool -//line sql.y:2672 +//line sql.y:2676 { yyLOCAL = false } yyVAL.union = yyLOCAL - case 492: + case 493: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL bool -//line sql.y:2676 +//line sql.y:2680 { yyLOCAL = true } yyVAL.union = yyLOCAL - case 493: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2682 - { - yyVAL.str = string(yyDollar[1].str) - } case 494: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2686 @@ -9493,16 +9547,16 @@ yydefault: yyVAL.str = string(yyDollar[1].str) } case 495: - yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2692 + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:2690 { - yyVAL.tableIdent = NewTableIdent("") + yyVAL.str = string(yyDollar[1].str) } case 496: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-0 : yypt+1] //line sql.y:2696 { - yyVAL.tableIdent = yyDollar[2].tableIdent + yyVAL.tableIdent = NewTableIdent("") } case 497: yyDollar = yyS[yypt-2 : yypt+1] @@ -9511,53 +9565,53 @@ yydefault: yyVAL.tableIdent = yyDollar[2].tableIdent } case 498: + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2704 + { + yyVAL.tableIdent = yyDollar[2].tableIdent + } + case 499: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL *ShowFilter -//line sql.y:2706 +//line sql.y:2710 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 499: + case 500: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *ShowFilter -//line sql.y:2710 +//line sql.y:2714 { yyLOCAL = &ShowFilter{Like: string(yyDollar[2].str)} } yyVAL.union = yyLOCAL - case 500: + case 501: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *ShowFilter -//line sql.y:2714 +//line sql.y:2718 { yyLOCAL = &ShowFilter{Filter: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL - case 501: + case 502: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL *ShowFilter -//line sql.y:2720 +//line sql.y:2724 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 502: + case 503: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *ShowFilter -//line sql.y:2724 +//line sql.y:2728 { yyLOCAL = &ShowFilter{Like: string(yyDollar[2].str)} } yyVAL.union = yyLOCAL - case 503: - yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2730 - { - yyVAL.empty = struct{}{} - } case 504: - yyDollar = yyS[yypt-1 : yypt+1] + yyDollar = yyS[yypt-0 : yypt+1] //line sql.y:2734 { yyVAL.empty = struct{}{} @@ -9569,115 +9623,113 @@ yydefault: yyVAL.empty = struct{}{} } case 506: + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:2742 + { + yyVAL.empty = struct{}{} + } + case 507: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Statement -//line sql.y:2744 +//line sql.y:2748 { yyLOCAL = &Use{DBName: yyDollar[2].tableIdent} } yyVAL.union = yyLOCAL - case 507: + case 508: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Statement -//line sql.y:2748 +//line sql.y:2752 { yyLOCAL = &Use{DBName: TableIdent{v: ""}} } yyVAL.union = yyLOCAL - case 508: + case 509: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Statement -//line sql.y:2754 +//line sql.y:2758 { yyLOCAL = &Begin{} } yyVAL.union = yyLOCAL - case 509: + case 510: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Statement -//line sql.y:2758 +//line sql.y:2762 { yyLOCAL = &Begin{} } yyVAL.union = yyLOCAL - case 510: + case 511: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Statement -//line sql.y:2764 +//line sql.y:2768 { yyLOCAL = &Commit{} } yyVAL.union = yyLOCAL - case 511: + case 512: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Statement -//line sql.y:2770 +//line sql.y:2774 { yyLOCAL = &Rollback{} } yyVAL.union = yyLOCAL - case 512: + case 513: yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL Statement -//line sql.y:2774 +//line sql.y:2778 { yyLOCAL = &SRollback{Name: yyDollar[5].colIdent} } yyVAL.union = yyLOCAL - case 513: + case 514: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2779 +//line sql.y:2783 { yyVAL.empty = struct{}{} } - case 514: + case 515: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2781 +//line sql.y:2785 { yyVAL.empty = struct{}{} } - case 515: + case 516: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2784 +//line sql.y:2788 { yyVAL.empty = struct{}{} } - case 516: + case 517: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2786 +//line sql.y:2790 { yyVAL.empty = struct{}{} } - case 517: + case 518: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Statement -//line sql.y:2791 +//line sql.y:2795 { yyLOCAL = &Savepoint{Name: yyDollar[2].colIdent} } yyVAL.union = yyLOCAL - case 518: + case 519: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Statement -//line sql.y:2797 +//line sql.y:2801 { yyLOCAL = &Release{Name: yyDollar[3].colIdent} } yyVAL.union = yyLOCAL - case 519: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL ExplainType -//line sql.y:2802 - { - yyLOCAL = EmptyType - } - yyVAL.union = yyLOCAL case 520: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL ExplainType //line sql.y:2806 { - yyLOCAL = JSONType + yyLOCAL = EmptyType } yyVAL.union = yyLOCAL case 521: @@ -9685,7 +9737,7 @@ yydefault: var yyLOCAL ExplainType //line sql.y:2810 { - yyLOCAL = TreeType + yyLOCAL = JSONType } yyVAL.union = yyLOCAL case 522: @@ -9693,7 +9745,7 @@ yydefault: var yyLOCAL ExplainType //line sql.y:2814 { - yyLOCAL = VitessType + yyLOCAL = TreeType } yyVAL.union = yyLOCAL case 523: @@ -9701,23 +9753,25 @@ yydefault: var yyLOCAL ExplainType //line sql.y:2818 { - yyLOCAL = TraditionalType + yyLOCAL = VitessType } yyVAL.union = yyLOCAL case 524: - yyDollar = yyS[yypt-1 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL ExplainType //line sql.y:2822 { - yyLOCAL = AnalyzeType + yyLOCAL = TraditionalType } yyVAL.union = yyLOCAL case 525: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2828 + var yyLOCAL ExplainType +//line sql.y:2826 { - yyVAL.str = yyDollar[1].str + yyLOCAL = AnalyzeType } + yyVAL.union = yyLOCAL case 526: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2832 @@ -9732,18 +9786,16 @@ yydefault: } case 528: yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL Statement -//line sql.y:2842 +//line sql.y:2840 { - yyLOCAL = yyDollar[1].selStmtUnion() + yyVAL.str = yyDollar[1].str } - yyVAL.union = yyLOCAL case 529: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Statement //line sql.y:2846 { - yyLOCAL = yyDollar[1].statementUnion() + yyLOCAL = yyDollar[1].selStmtUnion() } yyVAL.union = yyLOCAL case 530: @@ -9763,200 +9815,202 @@ yydefault: } yyVAL.union = yyLOCAL case 532: - yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2859 + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL Statement +//line sql.y:2858 { - yyVAL.str = "" + yyLOCAL = yyDollar[1].statementUnion() } + yyVAL.union = yyLOCAL case 533: - yyDollar = yyS[yypt-1 : yypt+1] + yyDollar = yyS[yypt-0 : yypt+1] //line sql.y:2863 { - yyVAL.str = yyDollar[1].colIdent.val + yyVAL.str = "" } case 534: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2867 { - yyVAL.str = encodeSQLString(yyDollar[1].str) + yyVAL.str = yyDollar[1].colIdent.val } case 535: + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:2871 + { + yyVAL.str = encodeSQLString(yyDollar[1].str) + } + case 536: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Statement -//line sql.y:2873 +//line sql.y:2877 { yyLOCAL = &ExplainTab{Table: yyDollar[2].tableName, Wild: yyDollar[3].str} } yyVAL.union = yyLOCAL - case 536: + case 537: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Statement -//line sql.y:2877 +//line sql.y:2881 { yyLOCAL = &ExplainStmt{Type: yyDollar[2].explainTypeUnion(), Statement: yyDollar[3].statementUnion()} } yyVAL.union = yyLOCAL - case 537: + case 538: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Statement -//line sql.y:2883 +//line sql.y:2887 { yyLOCAL = &OtherAdmin{} } yyVAL.union = yyLOCAL - case 538: + case 539: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Statement -//line sql.y:2887 +//line sql.y:2891 { yyLOCAL = &OtherAdmin{} } yyVAL.union = yyLOCAL - case 539: + case 540: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Statement -//line sql.y:2893 +//line sql.y:2897 { yyLOCAL = &LockTables{Tables: yyDollar[3].tableAndLockTypesUnion()} } yyVAL.union = yyLOCAL - case 540: + case 541: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL TableAndLockTypes -//line sql.y:2899 +//line sql.y:2903 { yyLOCAL = TableAndLockTypes{yyDollar[1].tableAndLockTypeUnion()} } yyVAL.union = yyLOCAL - case 541: + case 542: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2903 +//line sql.y:2907 { yySLICE := (*TableAndLockTypes)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[3].tableAndLockTypeUnion()) } - case 542: + case 543: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *TableAndLockType -//line sql.y:2909 +//line sql.y:2913 { yyLOCAL = &TableAndLockType{Table: yyDollar[1].aliasedTableNameUnion(), Lock: yyDollar[2].lockTypeUnion()} } yyVAL.union = yyLOCAL - case 543: + case 544: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL LockType -//line sql.y:2915 +//line sql.y:2919 { yyLOCAL = Read } yyVAL.union = yyLOCAL - case 544: + case 545: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL LockType -//line sql.y:2919 +//line sql.y:2923 { yyLOCAL = ReadLocal } yyVAL.union = yyLOCAL - case 545: + case 546: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL LockType -//line sql.y:2923 +//line sql.y:2927 { yyLOCAL = Write } yyVAL.union = yyLOCAL - case 546: + case 547: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL LockType -//line sql.y:2927 +//line sql.y:2931 { yyLOCAL = LowPriorityWrite } yyVAL.union = yyLOCAL - case 547: + case 548: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Statement -//line sql.y:2933 +//line sql.y:2937 { yyLOCAL = &UnlockTables{} } yyVAL.union = yyLOCAL - case 548: + case 549: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL Statement -//line sql.y:2939 +//line sql.y:2943 { yyLOCAL = &RevertMigration{Comments: Comments(yyDollar[2].strs), UUID: string(yyDollar[4].str)} } yyVAL.union = yyLOCAL - case 549: + case 550: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Statement -//line sql.y:2945 +//line sql.y:2949 { yyLOCAL = &Flush{IsLocal: yyDollar[2].booleanUnion(), FlushOptions: yyDollar[3].strs} } yyVAL.union = yyLOCAL - case 550: + case 551: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Statement -//line sql.y:2949 +//line sql.y:2953 { yyLOCAL = &Flush{IsLocal: yyDollar[2].booleanUnion()} } yyVAL.union = yyLOCAL - case 551: + case 552: yyDollar = yyS[yypt-6 : yypt+1] var yyLOCAL Statement -//line sql.y:2953 +//line sql.y:2957 { yyLOCAL = &Flush{IsLocal: yyDollar[2].booleanUnion(), WithLock: true} } yyVAL.union = yyLOCAL - case 552: + case 553: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL Statement -//line sql.y:2957 +//line sql.y:2961 { yyLOCAL = &Flush{IsLocal: yyDollar[2].booleanUnion(), TableNames: yyDollar[4].tableNamesUnion()} } yyVAL.union = yyLOCAL - case 553: + case 554: yyDollar = yyS[yypt-7 : yypt+1] var yyLOCAL Statement -//line sql.y:2961 +//line sql.y:2965 { yyLOCAL = &Flush{IsLocal: yyDollar[2].booleanUnion(), TableNames: yyDollar[4].tableNamesUnion(), WithLock: true} } yyVAL.union = yyLOCAL - case 554: + case 555: yyDollar = yyS[yypt-6 : yypt+1] var yyLOCAL Statement -//line sql.y:2965 +//line sql.y:2969 { yyLOCAL = &Flush{IsLocal: yyDollar[2].booleanUnion(), TableNames: yyDollar[4].tableNamesUnion(), ForExport: true} } yyVAL.union = yyLOCAL - case 555: + case 556: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2971 +//line sql.y:2975 { yyVAL.strs = []string{yyDollar[1].str} } - case 556: + case 557: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2975 +//line sql.y:2979 { yyVAL.strs = append(yyDollar[1].strs, yyDollar[3].str) } - case 557: - yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2981 - { - yyVAL.str = string(yyDollar[1].str) + " " + string(yyDollar[2].str) - } case 558: yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:2985 @@ -9976,10 +10030,10 @@ yydefault: yyVAL.str = string(yyDollar[1].str) + " " + string(yyDollar[2].str) } case 561: - yyDollar = yyS[yypt-1 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:2997 { - yyVAL.str = string(yyDollar[1].str) + yyVAL.str = string(yyDollar[1].str) + " " + string(yyDollar[2].str) } case 562: yyDollar = yyS[yypt-1 : yypt+1] @@ -9994,22 +10048,22 @@ yydefault: yyVAL.str = string(yyDollar[1].str) } case 564: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:3009 { - yyVAL.str = string(yyDollar[1].str) + " " + string(yyDollar[2].str) + yyDollar[3].str + yyVAL.str = string(yyDollar[1].str) } case 565: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:3013 { - yyVAL.str = string(yyDollar[1].str) + " " + string(yyDollar[2].str) + yyVAL.str = string(yyDollar[1].str) + " " + string(yyDollar[2].str) + yyDollar[3].str } case 566: - yyDollar = yyS[yypt-1 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:3017 { - yyVAL.str = string(yyDollar[1].str) + yyVAL.str = string(yyDollar[1].str) + " " + string(yyDollar[2].str) } case 567: yyDollar = yyS[yypt-1 : yypt+1] @@ -10024,195 +10078,195 @@ yydefault: yyVAL.str = string(yyDollar[1].str) } case 569: + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:3029 + { + yyVAL.str = string(yyDollar[1].str) + } + case 570: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL bool -//line sql.y:3030 +//line sql.y:3034 { yyLOCAL = false } yyVAL.union = yyLOCAL - case 570: + case 571: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL bool -//line sql.y:3034 +//line sql.y:3038 { yyLOCAL = true } yyVAL.union = yyLOCAL - case 571: + case 572: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL bool -//line sql.y:3038 +//line sql.y:3042 { yyLOCAL = true } yyVAL.union = yyLOCAL - case 572: + case 573: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3043 +//line sql.y:3047 { yyVAL.str = "" } - case 573: + case 574: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3047 +//line sql.y:3051 { yyVAL.str = " " + string(yyDollar[1].str) + " " + string(yyDollar[2].str) + " " + yyDollar[3].colIdent.String() } - case 574: + case 575: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3052 +//line sql.y:3056 { setAllowComments(yylex, true) } - case 575: + case 576: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3056 +//line sql.y:3060 { yyVAL.strs = yyDollar[2].strs setAllowComments(yylex, false) } - case 576: + case 577: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3062 +//line sql.y:3066 { yyVAL.strs = nil } - case 577: + case 578: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3066 +//line sql.y:3070 { yyVAL.strs = append(yyDollar[1].strs, yyDollar[2].str) } - case 578: + case 579: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL bool -//line sql.y:3072 +//line sql.y:3076 { yyLOCAL = true } yyVAL.union = yyLOCAL - case 579: + case 580: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL bool -//line sql.y:3076 +//line sql.y:3080 { yyLOCAL = false } yyVAL.union = yyLOCAL - case 580: + case 581: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL bool -//line sql.y:3080 +//line sql.y:3084 { yyLOCAL = true } yyVAL.union = yyLOCAL - case 581: + case 582: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3085 +//line sql.y:3089 { yyVAL.str = "" } - case 582: + case 583: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3089 +//line sql.y:3093 { yyVAL.str = SQLNoCacheStr } - case 583: + case 584: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3093 +//line sql.y:3097 { yyVAL.str = SQLCacheStr } - case 584: + case 585: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL bool -//line sql.y:3098 +//line sql.y:3102 { yyLOCAL = false } yyVAL.union = yyLOCAL - case 585: + case 586: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL bool -//line sql.y:3102 +//line sql.y:3106 { yyLOCAL = true } yyVAL.union = yyLOCAL - case 586: + case 587: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL bool -//line sql.y:3106 +//line sql.y:3110 { yyLOCAL = true } yyVAL.union = yyLOCAL - case 587: + case 588: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL SelectExprs -//line sql.y:3111 +//line sql.y:3115 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 588: + case 589: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL SelectExprs -//line sql.y:3115 +//line sql.y:3119 { yyLOCAL = yyDollar[1].selectExprsUnion() } yyVAL.union = yyLOCAL - case 589: + case 590: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3120 +//line sql.y:3124 { yyVAL.strs = nil } - case 590: + case 591: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3124 +//line sql.y:3128 { yyVAL.strs = []string{yyDollar[1].str} } - case 591: + case 592: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3128 +//line sql.y:3132 { // TODO: This is a hack since I couldn't get it to work in a nicer way. I got 'conflicts: 8 shift/reduce' yyVAL.strs = []string{yyDollar[1].str, yyDollar[2].str} } - case 592: + case 593: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3132 +//line sql.y:3136 { yyVAL.strs = []string{yyDollar[1].str, yyDollar[2].str, yyDollar[3].str} } - case 593: + case 594: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:3136 +//line sql.y:3140 { yyVAL.strs = []string{yyDollar[1].str, yyDollar[2].str, yyDollar[3].str, yyDollar[4].str} } - case 594: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3142 - { - yyVAL.str = SQLNoCacheStr - } case 595: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:3146 { - yyVAL.str = SQLCacheStr + yyVAL.str = SQLNoCacheStr } case 596: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:3150 { - yyVAL.str = DistinctStr + yyVAL.str = SQLCacheStr } case 597: yyDollar = yyS[yypt-1 : yypt+1] @@ -10224,426 +10278,432 @@ yydefault: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:3158 { - yyVAL.str = StraightJoinHint + yyVAL.str = DistinctStr } case 599: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:3162 { - yyVAL.str = SQLCalcFoundRowsStr + yyVAL.str = StraightJoinHint } case 600: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:3166 { - yyVAL.str = AllStr // These are not picked up by NewSelect, and so ALL will be dropped. But this is OK, since it's redundant anyway + yyVAL.str = SQLCalcFoundRowsStr } case 601: yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:3170 + { + yyVAL.str = AllStr // These are not picked up by NewSelect, and so ALL will be dropped. But this is OK, since it's redundant anyway + } + case 602: + yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL SelectExprs -//line sql.y:3172 +//line sql.y:3176 { yyLOCAL = SelectExprs{yyDollar[1].selectExprUnion()} } yyVAL.union = yyLOCAL - case 602: + case 603: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3176 +//line sql.y:3180 { yySLICE := (*SelectExprs)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[3].selectExprUnion()) } - case 603: + case 604: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL SelectExpr -//line sql.y:3182 +//line sql.y:3186 { yyLOCAL = &StarExpr{} } yyVAL.union = yyLOCAL - case 604: + case 605: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL SelectExpr -//line sql.y:3186 +//line sql.y:3190 { yyLOCAL = &AliasedExpr{Expr: yyDollar[1].exprUnion(), As: yyDollar[2].colIdent} } yyVAL.union = yyLOCAL - case 605: + case 606: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL SelectExpr -//line sql.y:3190 +//line sql.y:3194 { yyLOCAL = &StarExpr{TableName: TableName{Name: yyDollar[1].tableIdent}} } yyVAL.union = yyLOCAL - case 606: + case 607: yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL SelectExpr -//line sql.y:3194 +//line sql.y:3198 { yyLOCAL = &StarExpr{TableName: TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent}} } yyVAL.union = yyLOCAL - case 607: + case 608: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3199 +//line sql.y:3203 { yyVAL.colIdent = ColIdent{} } - case 608: + case 609: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3203 +//line sql.y:3207 { yyVAL.colIdent = yyDollar[1].colIdent } - case 609: + case 610: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3207 +//line sql.y:3211 { yyVAL.colIdent = yyDollar[2].colIdent } - case 611: + case 612: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3214 +//line sql.y:3218 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].str)) } - case 612: + case 613: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL TableExprs -//line sql.y:3219 +//line sql.y:3223 { yyLOCAL = TableExprs{&AliasedTableExpr{Expr: TableName{Name: NewTableIdent("dual")}}} } yyVAL.union = yyLOCAL - case 613: + case 614: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL TableExprs -//line sql.y:3223 +//line sql.y:3227 { yyLOCAL = yyDollar[2].tableExprsUnion() } yyVAL.union = yyLOCAL - case 614: + case 615: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL TableExprs -//line sql.y:3229 +//line sql.y:3233 { yyLOCAL = TableExprs{yyDollar[1].tableExprUnion()} } yyVAL.union = yyLOCAL - case 615: + case 616: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3233 +//line sql.y:3237 { yySLICE := (*TableExprs)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[3].tableExprUnion()) } - case 618: + case 619: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL TableExpr -//line sql.y:3243 +//line sql.y:3247 { yyLOCAL = yyDollar[1].aliasedTableNameUnion() } yyVAL.union = yyLOCAL - case 619: + case 620: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL TableExpr -//line sql.y:3247 +//line sql.y:3251 { yyLOCAL = &AliasedTableExpr{Expr: yyDollar[1].derivedTableUnion(), As: yyDollar[3].tableIdent} } yyVAL.union = yyLOCAL - case 620: + case 621: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL TableExpr -//line sql.y:3251 +//line sql.y:3255 { yyLOCAL = &ParenTableExpr{Exprs: yyDollar[2].tableExprsUnion()} } yyVAL.union = yyLOCAL - case 621: + case 622: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *DerivedTable -//line sql.y:3257 +//line sql.y:3261 { yyLOCAL = &DerivedTable{yyDollar[2].selStmtUnion()} } yyVAL.union = yyLOCAL - case 622: + case 623: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *AliasedTableExpr -//line sql.y:3263 +//line sql.y:3267 { yyLOCAL = &AliasedTableExpr{Expr: yyDollar[1].tableName, As: yyDollar[2].tableIdent, Hints: yyDollar[3].indexHintsUnion()} } yyVAL.union = yyLOCAL - case 623: + case 624: yyDollar = yyS[yypt-7 : yypt+1] var yyLOCAL *AliasedTableExpr -//line sql.y:3267 +//line sql.y:3271 { yyLOCAL = &AliasedTableExpr{Expr: yyDollar[1].tableName, Partitions: yyDollar[4].partitionsUnion(), As: yyDollar[6].tableIdent, Hints: yyDollar[7].indexHintsUnion()} } yyVAL.union = yyLOCAL - case 624: + case 625: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL Columns -//line sql.y:3272 +//line sql.y:3276 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 625: + case 626: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Columns -//line sql.y:3276 +//line sql.y:3280 { yyLOCAL = yyDollar[2].columnsUnion() } yyVAL.union = yyLOCAL - case 626: + case 627: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Columns -//line sql.y:3282 +//line sql.y:3286 { yyLOCAL = Columns{yyDollar[1].colIdent} } yyVAL.union = yyLOCAL - case 627: + case 628: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3286 +//line sql.y:3290 { yySLICE := (*Columns)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[3].colIdent) } - case 628: + case 629: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Columns -//line sql.y:3292 +//line sql.y:3296 { yyLOCAL = Columns{yyDollar[1].colIdent} } yyVAL.union = yyLOCAL - case 629: + case 630: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Columns -//line sql.y:3296 +//line sql.y:3300 { yyLOCAL = Columns{NewColIdent(string(yyDollar[1].str))} } yyVAL.union = yyLOCAL - case 630: + case 631: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3300 +//line sql.y:3304 { yySLICE := (*Columns)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[3].colIdent) } - case 631: + case 632: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3304 +//line sql.y:3308 { yySLICE := (*Columns)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, NewColIdent(string(yyDollar[3].str))) } - case 632: + case 633: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Partitions -//line sql.y:3310 +//line sql.y:3314 { yyLOCAL = Partitions{yyDollar[1].colIdent} } yyVAL.union = yyLOCAL - case 633: + case 634: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3314 +//line sql.y:3318 { yySLICE := (*Partitions)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[3].colIdent) } - case 634: + case 635: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL TableExpr -//line sql.y:3327 +//line sql.y:3331 { yyLOCAL = &JoinTableExpr{LeftExpr: yyDollar[1].tableExprUnion(), Join: yyDollar[2].joinTypeUnion(), RightExpr: yyDollar[3].tableExprUnion(), Condition: yyDollar[4].joinCondition} } yyVAL.union = yyLOCAL - case 635: + case 636: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL TableExpr -//line sql.y:3331 +//line sql.y:3335 { yyLOCAL = &JoinTableExpr{LeftExpr: yyDollar[1].tableExprUnion(), Join: yyDollar[2].joinTypeUnion(), RightExpr: yyDollar[3].tableExprUnion(), Condition: yyDollar[4].joinCondition} } yyVAL.union = yyLOCAL - case 636: + case 637: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL TableExpr -//line sql.y:3335 +//line sql.y:3339 { yyLOCAL = &JoinTableExpr{LeftExpr: yyDollar[1].tableExprUnion(), Join: yyDollar[2].joinTypeUnion(), RightExpr: yyDollar[3].tableExprUnion(), Condition: yyDollar[4].joinCondition} } yyVAL.union = yyLOCAL - case 637: + case 638: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL TableExpr -//line sql.y:3339 +//line sql.y:3343 { yyLOCAL = &JoinTableExpr{LeftExpr: yyDollar[1].tableExprUnion(), Join: yyDollar[2].joinTypeUnion(), RightExpr: yyDollar[3].tableExprUnion()} } yyVAL.union = yyLOCAL - case 638: + case 639: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3345 +//line sql.y:3349 { yyVAL.joinCondition = JoinCondition{On: yyDollar[2].exprUnion()} } - case 639: + case 640: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:3347 +//line sql.y:3351 { yyVAL.joinCondition = JoinCondition{Using: yyDollar[3].columnsUnion()} } - case 640: + case 641: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3351 +//line sql.y:3355 { yyVAL.joinCondition = JoinCondition{} } - case 641: + case 642: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3353 +//line sql.y:3357 { yyVAL.joinCondition = yyDollar[1].joinCondition } - case 642: + case 643: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3357 +//line sql.y:3361 { yyVAL.joinCondition = JoinCondition{} } - case 643: + case 644: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3359 +//line sql.y:3363 { yyVAL.joinCondition = JoinCondition{On: yyDollar[2].exprUnion()} } - case 644: + case 645: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3362 +//line sql.y:3366 { yyVAL.empty = struct{}{} } - case 645: + case 646: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3364 +//line sql.y:3368 { yyVAL.empty = struct{}{} } - case 646: + case 647: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3367 +//line sql.y:3371 { yyVAL.tableIdent = NewTableIdent("") } - case 647: + case 648: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3371 +//line sql.y:3375 { yyVAL.tableIdent = yyDollar[1].tableIdent } - case 648: + case 649: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3375 +//line sql.y:3379 { yyVAL.tableIdent = yyDollar[2].tableIdent } - case 650: + case 651: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3382 +//line sql.y:3386 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].str)) } - case 651: + case 652: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL JoinType -//line sql.y:3388 +//line sql.y:3392 { yyLOCAL = NormalJoinType } yyVAL.union = yyLOCAL - case 652: + case 653: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL JoinType -//line sql.y:3392 +//line sql.y:3396 { yyLOCAL = NormalJoinType } yyVAL.union = yyLOCAL - case 653: + case 654: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL JoinType -//line sql.y:3396 +//line sql.y:3400 { yyLOCAL = NormalJoinType } yyVAL.union = yyLOCAL - case 654: + case 655: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL JoinType -//line sql.y:3402 +//line sql.y:3406 { yyLOCAL = StraightJoinType } yyVAL.union = yyLOCAL - case 655: + case 656: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL JoinType -//line sql.y:3408 +//line sql.y:3412 { yyLOCAL = LeftJoinType } yyVAL.union = yyLOCAL - case 656: + case 657: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL JoinType -//line sql.y:3412 +//line sql.y:3416 { yyLOCAL = LeftJoinType } yyVAL.union = yyLOCAL - case 657: + case 658: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL JoinType -//line sql.y:3416 +//line sql.y:3420 { yyLOCAL = RightJoinType } yyVAL.union = yyLOCAL - case 658: + case 659: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL JoinType -//line sql.y:3420 +//line sql.y:3424 { yyLOCAL = RightJoinType } yyVAL.union = yyLOCAL - case 659: + case 660: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL JoinType -//line sql.y:3426 +//line sql.y:3430 { yyLOCAL = NaturalJoinType } yyVAL.union = yyLOCAL - case 660: + case 661: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL JoinType -//line sql.y:3430 +//line sql.y:3434 { if yyDollar[2].joinTypeUnion() == LeftJoinType { yyLOCAL = NaturalLeftJoinType @@ -10652,326 +10712,318 @@ yydefault: } } yyVAL.union = yyLOCAL - case 661: + case 662: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3440 +//line sql.y:3444 { yyVAL.tableName = yyDollar[2].tableName } - case 662: + case 663: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3444 +//line sql.y:3448 { yyVAL.tableName = yyDollar[1].tableName } - case 663: + case 664: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3450 +//line sql.y:3454 { yyVAL.tableName = TableName{Name: yyDollar[1].tableIdent} } - case 664: + case 665: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3454 +//line sql.y:3458 { yyVAL.tableName = TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent} } - case 665: + case 666: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3460 +//line sql.y:3464 { yyVAL.tableName = TableName{Name: yyDollar[1].tableIdent} } - case 666: + case 667: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL *IndexHints -//line sql.y:3465 +//line sql.y:3469 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 667: + case 668: yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL *IndexHints -//line sql.y:3469 +//line sql.y:3473 { yyLOCAL = &IndexHints{Type: UseOp, Indexes: yyDollar[4].columnsUnion()} } yyVAL.union = yyLOCAL - case 668: + case 669: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL *IndexHints -//line sql.y:3473 +//line sql.y:3477 { yyLOCAL = &IndexHints{Type: UseOp} } yyVAL.union = yyLOCAL - case 669: + case 670: yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL *IndexHints -//line sql.y:3477 +//line sql.y:3481 { yyLOCAL = &IndexHints{Type: IgnoreOp, Indexes: yyDollar[4].columnsUnion()} } yyVAL.union = yyLOCAL - case 670: + case 671: yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL *IndexHints -//line sql.y:3481 +//line sql.y:3485 { yyLOCAL = &IndexHints{Type: ForceOp, Indexes: yyDollar[4].columnsUnion()} } yyVAL.union = yyLOCAL - case 671: + case 672: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL Expr -//line sql.y:3486 +//line sql.y:3490 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 672: + case 673: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3490 +//line sql.y:3494 { yyLOCAL = yyDollar[2].exprUnion() } yyVAL.union = yyLOCAL - case 673: + case 674: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr -//line sql.y:3496 +//line sql.y:3500 { yyLOCAL = yyDollar[1].exprUnion() } yyVAL.union = yyLOCAL - case 674: + case 675: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Expr -//line sql.y:3500 +//line sql.y:3504 { yyLOCAL = &AndExpr{Left: yyDollar[1].exprUnion(), Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL - case 675: + case 676: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Expr -//line sql.y:3504 +//line sql.y:3508 { yyLOCAL = &OrExpr{Left: yyDollar[1].exprUnion(), Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL - case 676: + case 677: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Expr -//line sql.y:3508 +//line sql.y:3512 { yyLOCAL = &XorExpr{Left: yyDollar[1].exprUnion(), Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL - case 677: + case 678: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3512 +//line sql.y:3516 { yyLOCAL = &NotExpr{Expr: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL - case 678: + case 679: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Expr -//line sql.y:3516 +//line sql.y:3520 { yyLOCAL = &IsExpr{Left: yyDollar[1].exprUnion(), Right: yyDollar[3].isExprOperatorUnion()} } yyVAL.union = yyLOCAL - case 679: + case 680: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr -//line sql.y:3520 +//line sql.y:3524 { yyLOCAL = yyDollar[1].exprUnion() } yyVAL.union = yyLOCAL - case 680: + case 681: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3524 +//line sql.y:3528 { yyLOCAL = &Default{ColName: yyDollar[2].str} } yyVAL.union = yyLOCAL - case 681: + case 682: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3530 +//line sql.y:3534 { yyVAL.str = "" } - case 682: + case 683: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3534 +//line sql.y:3538 { yyVAL.str = string(yyDollar[2].colIdent.String()) } - case 683: + case 684: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL BoolVal -//line sql.y:3540 +//line sql.y:3544 { yyLOCAL = BoolVal(true) } yyVAL.union = yyLOCAL - case 684: + case 685: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL BoolVal -//line sql.y:3544 +//line sql.y:3548 { yyLOCAL = BoolVal(false) } yyVAL.union = yyLOCAL - case 685: + case 686: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Expr -//line sql.y:3550 +//line sql.y:3554 { yyLOCAL = &ComparisonExpr{Left: yyDollar[1].exprUnion(), Operator: yyDollar[2].comparisonExprOperatorUnion(), Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL - case 686: + case 687: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Expr -//line sql.y:3554 +//line sql.y:3558 { yyLOCAL = &ComparisonExpr{Left: yyDollar[1].exprUnion(), Operator: InOp, Right: yyDollar[3].colTupleUnion()} } yyVAL.union = yyLOCAL - case 687: + case 688: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL Expr -//line sql.y:3558 +//line sql.y:3562 { yyLOCAL = &ComparisonExpr{Left: yyDollar[1].exprUnion(), Operator: NotInOp, Right: yyDollar[4].colTupleUnion()} } yyVAL.union = yyLOCAL - case 688: + case 689: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL Expr -//line sql.y:3562 +//line sql.y:3566 { yyLOCAL = &ComparisonExpr{Left: yyDollar[1].exprUnion(), Operator: LikeOp, Right: yyDollar[3].exprUnion(), Escape: yyDollar[4].exprUnion()} } yyVAL.union = yyLOCAL - case 689: + case 690: yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL Expr -//line sql.y:3566 +//line sql.y:3570 { yyLOCAL = &ComparisonExpr{Left: yyDollar[1].exprUnion(), Operator: NotLikeOp, Right: yyDollar[4].exprUnion(), Escape: yyDollar[5].exprUnion()} } yyVAL.union = yyLOCAL - case 690: + case 691: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Expr -//line sql.y:3570 +//line sql.y:3574 { yyLOCAL = &ComparisonExpr{Left: yyDollar[1].exprUnion(), Operator: RegexpOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL - case 691: + case 692: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL Expr -//line sql.y:3574 +//line sql.y:3578 { yyLOCAL = &ComparisonExpr{Left: yyDollar[1].exprUnion(), Operator: NotRegexpOp, Right: yyDollar[4].exprUnion()} } yyVAL.union = yyLOCAL - case 692: + case 693: yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL Expr -//line sql.y:3578 +//line sql.y:3582 { yyLOCAL = &RangeCond{Left: yyDollar[1].exprUnion(), Operator: BetweenOp, From: yyDollar[3].exprUnion(), To: yyDollar[5].exprUnion()} } yyVAL.union = yyLOCAL - case 693: + case 694: yyDollar = yyS[yypt-6 : yypt+1] var yyLOCAL Expr -//line sql.y:3582 +//line sql.y:3586 { yyLOCAL = &RangeCond{Left: yyDollar[1].exprUnion(), Operator: NotBetweenOp, From: yyDollar[4].exprUnion(), To: yyDollar[6].exprUnion()} } yyVAL.union = yyLOCAL - case 694: + case 695: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3586 +//line sql.y:3590 { yyLOCAL = &ExistsExpr{Subquery: yyDollar[2].subqueryUnion()} } yyVAL.union = yyLOCAL - case 695: + case 696: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL IsExprOperator -//line sql.y:3592 +//line sql.y:3596 { yyLOCAL = IsNullOp } yyVAL.union = yyLOCAL - case 696: + case 697: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL IsExprOperator -//line sql.y:3596 +//line sql.y:3600 { yyLOCAL = IsNotNullOp } yyVAL.union = yyLOCAL - case 697: + case 698: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL IsExprOperator -//line sql.y:3600 +//line sql.y:3604 { yyLOCAL = IsTrueOp } yyVAL.union = yyLOCAL - case 698: + case 699: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL IsExprOperator -//line sql.y:3604 +//line sql.y:3608 { yyLOCAL = IsNotTrueOp } yyVAL.union = yyLOCAL - case 699: + case 700: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL IsExprOperator -//line sql.y:3608 +//line sql.y:3612 { yyLOCAL = IsFalseOp } yyVAL.union = yyLOCAL - case 700: + case 701: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL IsExprOperator -//line sql.y:3612 +//line sql.y:3616 { yyLOCAL = IsNotFalseOp } yyVAL.union = yyLOCAL - case 701: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL ComparisonExprOperator -//line sql.y:3618 - { - yyLOCAL = EqualOp - } - yyVAL.union = yyLOCAL case 702: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL ComparisonExprOperator //line sql.y:3622 { - yyLOCAL = LessThanOp + yyLOCAL = EqualOp } yyVAL.union = yyLOCAL case 703: @@ -10979,7 +11031,7 @@ yydefault: var yyLOCAL ComparisonExprOperator //line sql.y:3626 { - yyLOCAL = GreaterThanOp + yyLOCAL = LessThanOp } yyVAL.union = yyLOCAL case 704: @@ -10987,7 +11039,7 @@ yydefault: var yyLOCAL ComparisonExprOperator //line sql.y:3630 { - yyLOCAL = LessEqualOp + yyLOCAL = GreaterThanOp } yyVAL.union = yyLOCAL case 705: @@ -10995,103 +11047,103 @@ yydefault: var yyLOCAL ComparisonExprOperator //line sql.y:3634 { - yyLOCAL = GreaterEqualOp + yyLOCAL = LessEqualOp } yyVAL.union = yyLOCAL case 706: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL ComparisonExprOperator //line sql.y:3638 + { + yyLOCAL = GreaterEqualOp + } + yyVAL.union = yyLOCAL + case 707: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL ComparisonExprOperator +//line sql.y:3642 { yyLOCAL = NotEqualOp } yyVAL.union = yyLOCAL - case 707: + case 708: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL ComparisonExprOperator -//line sql.y:3642 +//line sql.y:3646 { yyLOCAL = NullSafeEqualOp } yyVAL.union = yyLOCAL - case 708: + case 709: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL Expr -//line sql.y:3647 +//line sql.y:3651 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 709: + case 710: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3651 +//line sql.y:3655 { yyLOCAL = yyDollar[2].exprUnion() } yyVAL.union = yyLOCAL - case 710: + case 711: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL ColTuple -//line sql.y:3657 +//line sql.y:3661 { yyLOCAL = yyDollar[1].valTupleUnion() } yyVAL.union = yyLOCAL - case 711: + case 712: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL ColTuple -//line sql.y:3661 +//line sql.y:3665 { yyLOCAL = yyDollar[1].subqueryUnion() } yyVAL.union = yyLOCAL - case 712: + case 713: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL ColTuple -//line sql.y:3665 +//line sql.y:3669 { yyLOCAL = ListArg(yyDollar[1].str[2:]) bindVariable(yylex, yyDollar[1].str[2:]) } yyVAL.union = yyLOCAL - case 713: + case 714: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *Subquery -//line sql.y:3672 +//line sql.y:3676 { yyLOCAL = &Subquery{yyDollar[2].selStmtUnion()} } yyVAL.union = yyLOCAL - case 714: + case 715: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Exprs -//line sql.y:3678 +//line sql.y:3682 { yyLOCAL = Exprs{yyDollar[1].exprUnion()} } yyVAL.union = yyLOCAL - case 715: + case 716: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3682 +//line sql.y:3686 { yySLICE := (*Exprs)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[3].exprUnion()) } - case 716: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL Expr -//line sql.y:3688 - { - yyLOCAL = yyDollar[1].exprUnion() - } - yyVAL.union = yyLOCAL case 717: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr //line sql.y:3692 { - yyLOCAL = yyDollar[1].boolValUnion() + yyLOCAL = yyDollar[1].exprUnion() } yyVAL.union = yyLOCAL case 718: @@ -11099,7 +11151,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3696 { - yyLOCAL = yyDollar[1].colNameUnion() + yyLOCAL = yyDollar[1].boolValUnion() } yyVAL.union = yyLOCAL case 719: @@ -11107,7 +11159,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3700 { - yyLOCAL = yyDollar[1].exprUnion() + yyLOCAL = yyDollar[1].colNameUnion() } yyVAL.union = yyLOCAL case 720: @@ -11115,15 +11167,15 @@ yydefault: var yyLOCAL Expr //line sql.y:3704 { - yyLOCAL = yyDollar[1].subqueryUnion() + yyLOCAL = yyDollar[1].exprUnion() } yyVAL.union = yyLOCAL case 721: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr //line sql.y:3708 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: BitAndOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = yyDollar[1].subqueryUnion() } yyVAL.union = yyLOCAL case 722: @@ -11131,7 +11183,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3712 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: BitOrOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: BitAndOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 723: @@ -11139,7 +11191,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3716 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: BitXorOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: BitOrOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 724: @@ -11147,7 +11199,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3720 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: PlusOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: BitXorOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 725: @@ -11155,7 +11207,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3724 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: MinusOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: PlusOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 726: @@ -11163,7 +11215,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3728 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: MultOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: MinusOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 727: @@ -11171,7 +11223,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3732 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: DivOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: MultOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 728: @@ -11179,7 +11231,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3736 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: IntDivOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: DivOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 729: @@ -11187,7 +11239,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3740 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: ModOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: IntDivOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 730: @@ -11203,7 +11255,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3748 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: ShiftLeftOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: ModOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 732: @@ -11211,7 +11263,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3752 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: ShiftRightOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: ShiftLeftOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 733: @@ -11219,7 +11271,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3756 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].colNameUnion(), Operator: JSONExtractOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].exprUnion(), Operator: ShiftRightOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 734: @@ -11227,7 +11279,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3760 { - yyLOCAL = &BinaryExpr{Left: yyDollar[1].colNameUnion(), Operator: JSONUnquoteExtractOp, Right: yyDollar[3].exprUnion()} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].colNameUnion(), Operator: JSONExtractOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 735: @@ -11235,15 +11287,15 @@ yydefault: var yyLOCAL Expr //line sql.y:3764 { - yyLOCAL = &CollateExpr{Expr: yyDollar[1].exprUnion(), Charset: yyDollar[3].str} + yyLOCAL = &BinaryExpr{Left: yyDollar[1].colNameUnion(), Operator: JSONUnquoteExtractOp, Right: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL case 736: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Expr //line sql.y:3768 { - yyLOCAL = &UnaryExpr{Operator: BinaryOp, Expr: yyDollar[2].exprUnion()} + yyLOCAL = &CollateExpr{Expr: yyDollar[1].exprUnion(), Charset: yyDollar[3].str} } yyVAL.union = yyLOCAL case 737: @@ -11251,7 +11303,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3772 { - yyLOCAL = &UnaryExpr{Operator: UBinaryOp, Expr: yyDollar[2].exprUnion()} + yyLOCAL = &UnaryExpr{Operator: BinaryOp, Expr: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL case 738: @@ -11259,7 +11311,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3776 { - yyLOCAL = &UnaryExpr{Operator: Utf8Op, Expr: yyDollar[2].exprUnion()} + yyLOCAL = &UnaryExpr{Operator: UBinaryOp, Expr: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL case 739: @@ -11267,7 +11319,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3780 { - yyLOCAL = &UnaryExpr{Operator: Utf8mb4Op, Expr: yyDollar[2].exprUnion()} + yyLOCAL = &UnaryExpr{Operator: Utf8Op, Expr: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL case 740: @@ -11275,7 +11327,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3784 { - yyLOCAL = &UnaryExpr{Operator: Latin1Op, Expr: yyDollar[2].exprUnion()} + yyLOCAL = &UnaryExpr{Operator: Utf8mb4Op, Expr: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL case 741: @@ -11283,7 +11335,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3788 { - yyLOCAL = yyDollar[2].exprUnion() + yyLOCAL = &UnaryExpr{Operator: Latin1Op, Expr: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL case 742: @@ -11291,7 +11343,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3792 { - yyLOCAL = handleUnaryMinus(yyDollar[2].exprUnion()) + yyLOCAL = yyDollar[2].exprUnion() } yyVAL.union = yyLOCAL case 743: @@ -11299,7 +11351,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3796 { - yyLOCAL = &UnaryExpr{Operator: TildaOp, Expr: yyDollar[2].exprUnion()} + yyLOCAL = handleUnaryMinus(yyDollar[2].exprUnion()) } yyVAL.union = yyLOCAL case 744: @@ -11307,13 +11359,21 @@ yydefault: var yyLOCAL Expr //line sql.y:3800 { - yyLOCAL = &UnaryExpr{Operator: BangOp, Expr: yyDollar[2].exprUnion()} + yyLOCAL = &UnaryExpr{Operator: TildaOp, Expr: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL case 745: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr //line sql.y:3804 + { + yyLOCAL = &UnaryExpr{Operator: BangOp, Expr: yyDollar[2].exprUnion()} + } + yyVAL.union = yyLOCAL + case 746: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL Expr +//line sql.y:3808 { // This rule prevents the usage of INTERVAL // as a function. If support is needed for that, @@ -11322,20 +11382,12 @@ yydefault: yyLOCAL = &IntervalExpr{Expr: yyDollar[2].exprUnion(), Unit: yyDollar[3].colIdent.String()} } yyVAL.union = yyLOCAL - case 750: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL Expr -//line sql.y:3822 - { - yyLOCAL = &FuncExpr{Name: yyDollar[1].colIdent, Exprs: yyDollar[3].selectExprsUnion()} - } - yyVAL.union = yyLOCAL case 751: - yyDollar = yyS[yypt-5 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL Expr //line sql.y:3826 { - yyLOCAL = &FuncExpr{Name: yyDollar[1].colIdent, Distinct: true, Exprs: yyDollar[4].selectExprsUnion()} + yyLOCAL = &FuncExpr{Name: yyDollar[1].colIdent, Exprs: yyDollar[3].selectExprsUnion()} } yyVAL.union = yyLOCAL case 752: @@ -11347,19 +11399,19 @@ yydefault: } yyVAL.union = yyLOCAL case 753: - yyDollar = yyS[yypt-6 : yypt+1] + yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL Expr //line sql.y:3834 { - yyLOCAL = &FuncExpr{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].colIdent, Exprs: yyDollar[5].selectExprsUnion()} + yyLOCAL = &FuncExpr{Name: yyDollar[1].colIdent, Distinct: true, Exprs: yyDollar[4].selectExprsUnion()} } yyVAL.union = yyLOCAL case 754: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] var yyLOCAL Expr -//line sql.y:3844 +//line sql.y:3838 { - yyLOCAL = &FuncExpr{Name: NewColIdent("left"), Exprs: yyDollar[3].selectExprsUnion()} + yyLOCAL = &FuncExpr{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].colIdent, Exprs: yyDollar[5].selectExprsUnion()} } yyVAL.union = yyLOCAL case 755: @@ -11367,15 +11419,15 @@ yydefault: var yyLOCAL Expr //line sql.y:3848 { - yyLOCAL = &FuncExpr{Name: NewColIdent("right"), Exprs: yyDollar[3].selectExprsUnion()} + yyLOCAL = &FuncExpr{Name: NewColIdent("left"), Exprs: yyDollar[3].selectExprsUnion()} } yyVAL.union = yyLOCAL case 756: - yyDollar = yyS[yypt-6 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL Expr //line sql.y:3852 { - yyLOCAL = &ConvertExpr{Expr: yyDollar[3].exprUnion(), Type: yyDollar[5].convertTypeUnion()} + yyLOCAL = &FuncExpr{Name: NewColIdent("right"), Exprs: yyDollar[3].selectExprsUnion()} } yyVAL.union = yyLOCAL case 757: @@ -11391,15 +11443,15 @@ yydefault: var yyLOCAL Expr //line sql.y:3860 { - yyLOCAL = &ConvertUsingExpr{Expr: yyDollar[3].exprUnion(), Type: yyDollar[5].str} + yyLOCAL = &ConvertExpr{Expr: yyDollar[3].exprUnion(), Type: yyDollar[5].convertTypeUnion()} } yyVAL.union = yyLOCAL case 759: - yyDollar = yyS[yypt-8 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] var yyLOCAL Expr //line sql.y:3864 { - yyLOCAL = &SubstrExpr{Name: yyDollar[3].colNameUnion(), From: yyDollar[5].exprUnion(), To: yyDollar[7].exprUnion()} + yyLOCAL = &ConvertUsingExpr{Expr: yyDollar[3].exprUnion(), Type: yyDollar[5].str} } yyVAL.union = yyLOCAL case 760: @@ -11415,7 +11467,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3872 { - yyLOCAL = &SubstrExpr{StrVal: NewStrLiteral(yyDollar[3].str), From: yyDollar[5].exprUnion(), To: yyDollar[7].exprUnion()} + yyLOCAL = &SubstrExpr{Name: yyDollar[3].colNameUnion(), From: yyDollar[5].exprUnion(), To: yyDollar[7].exprUnion()} } yyVAL.union = yyLOCAL case 762: @@ -11427,51 +11479,51 @@ yydefault: } yyVAL.union = yyLOCAL case 763: - yyDollar = yyS[yypt-9 : yypt+1] + yyDollar = yyS[yypt-8 : yypt+1] var yyLOCAL Expr //line sql.y:3880 { - yyLOCAL = &MatchExpr{Columns: yyDollar[3].selectExprsUnion(), Expr: yyDollar[7].exprUnion(), Option: yyDollar[8].matchExprOptionUnion()} + yyLOCAL = &SubstrExpr{StrVal: NewStrLiteral(yyDollar[3].str), From: yyDollar[5].exprUnion(), To: yyDollar[7].exprUnion()} } yyVAL.union = yyLOCAL case 764: - yyDollar = yyS[yypt-8 : yypt+1] + yyDollar = yyS[yypt-9 : yypt+1] var yyLOCAL Expr //line sql.y:3884 { - yyLOCAL = &GroupConcatExpr{Distinct: yyDollar[3].booleanUnion(), Exprs: yyDollar[4].selectExprsUnion(), OrderBy: yyDollar[5].orderByUnion(), Separator: yyDollar[6].str, Limit: yyDollar[7].limitUnion()} + yyLOCAL = &MatchExpr{Columns: yyDollar[3].selectExprsUnion(), Expr: yyDollar[7].exprUnion(), Option: yyDollar[8].matchExprOptionUnion()} } yyVAL.union = yyLOCAL case 765: - yyDollar = yyS[yypt-5 : yypt+1] + yyDollar = yyS[yypt-8 : yypt+1] var yyLOCAL Expr //line sql.y:3888 { - yyLOCAL = &CaseExpr{Expr: yyDollar[2].exprUnion(), Whens: yyDollar[3].whensUnion(), Else: yyDollar[4].exprUnion()} + yyLOCAL = &GroupConcatExpr{Distinct: yyDollar[3].booleanUnion(), Exprs: yyDollar[4].selectExprsUnion(), OrderBy: yyDollar[5].orderByUnion(), Separator: yyDollar[6].str, Limit: yyDollar[7].limitUnion()} } yyVAL.union = yyLOCAL case 766: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL Expr //line sql.y:3892 { - yyLOCAL = &ValuesFuncExpr{Name: yyDollar[3].colNameUnion()} + yyLOCAL = &CaseExpr{Expr: yyDollar[2].exprUnion(), Whens: yyDollar[3].whensUnion(), Else: yyDollar[4].exprUnion()} } yyVAL.union = yyLOCAL case 767: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL Expr //line sql.y:3896 { - yyLOCAL = &FuncExpr{Name: NewColIdent(yyDollar[1].str)} + yyLOCAL = &ValuesFuncExpr{Name: yyDollar[3].colNameUnion()} } yyVAL.union = yyLOCAL case 768: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3906 +//line sql.y:3900 { - yyLOCAL = &FuncExpr{Name: NewColIdent("current_timestamp")} + yyLOCAL = &FuncExpr{Name: NewColIdent(yyDollar[1].str)} } yyVAL.union = yyLOCAL case 769: @@ -11479,7 +11531,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3910 { - yyLOCAL = &FuncExpr{Name: NewColIdent("utc_timestamp")} + yyLOCAL = &FuncExpr{Name: NewColIdent("current_timestamp")} } yyVAL.union = yyLOCAL case 770: @@ -11487,55 +11539,55 @@ yydefault: var yyLOCAL Expr //line sql.y:3914 { - yyLOCAL = &FuncExpr{Name: NewColIdent("utc_time")} + yyLOCAL = &FuncExpr{Name: NewColIdent("utc_timestamp")} } yyVAL.union = yyLOCAL case 771: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3919 +//line sql.y:3918 { - yyLOCAL = &FuncExpr{Name: NewColIdent("utc_date")} + yyLOCAL = &FuncExpr{Name: NewColIdent("utc_time")} } yyVAL.union = yyLOCAL case 772: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3924 +//line sql.y:3923 { - yyLOCAL = &FuncExpr{Name: NewColIdent("localtime")} + yyLOCAL = &FuncExpr{Name: NewColIdent("utc_date")} } yyVAL.union = yyLOCAL case 773: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3929 +//line sql.y:3928 { - yyLOCAL = &FuncExpr{Name: NewColIdent("localtimestamp")} + yyLOCAL = &FuncExpr{Name: NewColIdent("localtime")} } yyVAL.union = yyLOCAL case 774: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3935 +//line sql.y:3933 { - yyLOCAL = &FuncExpr{Name: NewColIdent("current_date")} + yyLOCAL = &FuncExpr{Name: NewColIdent("localtimestamp")} } yyVAL.union = yyLOCAL case 775: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3940 +//line sql.y:3939 { - yyLOCAL = &FuncExpr{Name: NewColIdent("current_time")} + yyLOCAL = &FuncExpr{Name: NewColIdent("current_date")} } yyVAL.union = yyLOCAL case 776: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3945 +//line sql.y:3944 { - yyLOCAL = &CurTimeFuncExpr{Name: NewColIdent("current_timestamp"), Fsp: yyDollar[2].exprUnion()} + yyLOCAL = &FuncExpr{Name: NewColIdent("current_time")} } yyVAL.union = yyLOCAL case 777: @@ -11543,7 +11595,7 @@ yydefault: var yyLOCAL Expr //line sql.y:3949 { - yyLOCAL = &CurTimeFuncExpr{Name: NewColIdent("utc_timestamp"), Fsp: yyDollar[2].exprUnion()} + yyLOCAL = &CurTimeFuncExpr{Name: NewColIdent("current_timestamp"), Fsp: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL case 778: @@ -11551,39 +11603,39 @@ yydefault: var yyLOCAL Expr //line sql.y:3953 { - yyLOCAL = &CurTimeFuncExpr{Name: NewColIdent("utc_time"), Fsp: yyDollar[2].exprUnion()} + yyLOCAL = &CurTimeFuncExpr{Name: NewColIdent("utc_timestamp"), Fsp: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL case 779: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3958 +//line sql.y:3957 { - yyLOCAL = &CurTimeFuncExpr{Name: NewColIdent("localtime"), Fsp: yyDollar[2].exprUnion()} + yyLOCAL = &CurTimeFuncExpr{Name: NewColIdent("utc_time"), Fsp: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL case 780: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3963 +//line sql.y:3962 { - yyLOCAL = &CurTimeFuncExpr{Name: NewColIdent("localtimestamp"), Fsp: yyDollar[2].exprUnion()} + yyLOCAL = &CurTimeFuncExpr{Name: NewColIdent("localtime"), Fsp: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL case 781: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:3968 +//line sql.y:3967 { - yyLOCAL = &CurTimeFuncExpr{Name: NewColIdent("current_time"), Fsp: yyDollar[2].exprUnion()} + yyLOCAL = &CurTimeFuncExpr{Name: NewColIdent("localtimestamp"), Fsp: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL case 782: - yyDollar = yyS[yypt-8 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr //line sql.y:3972 { - yyLOCAL = &TimestampFuncExpr{Name: string("timestampadd"), Unit: yyDollar[3].colIdent.String(), Expr1: yyDollar[5].exprUnion(), Expr2: yyDollar[7].exprUnion()} + yyLOCAL = &CurTimeFuncExpr{Name: NewColIdent("current_time"), Fsp: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL case 783: @@ -11591,23 +11643,23 @@ yydefault: var yyLOCAL Expr //line sql.y:3976 { - yyLOCAL = &TimestampFuncExpr{Name: string("timestampdiff"), Unit: yyDollar[3].colIdent.String(), Expr1: yyDollar[5].exprUnion(), Expr2: yyDollar[7].exprUnion()} + yyLOCAL = &TimestampFuncExpr{Name: string("timestampadd"), Unit: yyDollar[3].colIdent.String(), Expr1: yyDollar[5].exprUnion(), Expr2: yyDollar[7].exprUnion()} } yyVAL.union = yyLOCAL - case 786: - yyDollar = yyS[yypt-3 : yypt+1] + case 784: + yyDollar = yyS[yypt-8 : yypt+1] var yyLOCAL Expr -//line sql.y:3986 +//line sql.y:3980 { - yyLOCAL = yyDollar[2].exprUnion() + yyLOCAL = &TimestampFuncExpr{Name: string("timestampdiff"), Unit: yyDollar[3].colIdent.String(), Expr1: yyDollar[5].exprUnion(), Expr2: yyDollar[7].exprUnion()} } yyVAL.union = yyLOCAL case 787: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Expr -//line sql.y:3996 +//line sql.y:3990 { - yyLOCAL = &FuncExpr{Name: NewColIdent("if"), Exprs: yyDollar[3].selectExprsUnion()} + yyLOCAL = yyDollar[2].exprUnion() } yyVAL.union = yyLOCAL case 788: @@ -11615,7 +11667,7 @@ yydefault: var yyLOCAL Expr //line sql.y:4000 { - yyLOCAL = &FuncExpr{Name: NewColIdent("database"), Exprs: yyDollar[3].selectExprsUnion()} + yyLOCAL = &FuncExpr{Name: NewColIdent("if"), Exprs: yyDollar[3].selectExprsUnion()} } yyVAL.union = yyLOCAL case 789: @@ -11623,7 +11675,7 @@ yydefault: var yyLOCAL Expr //line sql.y:4004 { - yyLOCAL = &FuncExpr{Name: NewColIdent("schema"), Exprs: yyDollar[3].selectExprsUnion()} + yyLOCAL = &FuncExpr{Name: NewColIdent("database"), Exprs: yyDollar[3].selectExprsUnion()} } yyVAL.union = yyLOCAL case 790: @@ -11631,7 +11683,7 @@ yydefault: var yyLOCAL Expr //line sql.y:4008 { - yyLOCAL = &FuncExpr{Name: NewColIdent("mod"), Exprs: yyDollar[3].selectExprsUnion()} + yyLOCAL = &FuncExpr{Name: NewColIdent("schema"), Exprs: yyDollar[3].selectExprsUnion()} } yyVAL.union = yyLOCAL case 791: @@ -11639,7 +11691,7 @@ yydefault: var yyLOCAL Expr //line sql.y:4012 { - yyLOCAL = &FuncExpr{Name: NewColIdent("replace"), Exprs: yyDollar[3].selectExprsUnion()} + yyLOCAL = &FuncExpr{Name: NewColIdent("mod"), Exprs: yyDollar[3].selectExprsUnion()} } yyVAL.union = yyLOCAL case 792: @@ -11647,7 +11699,7 @@ yydefault: var yyLOCAL Expr //line sql.y:4016 { - yyLOCAL = &FuncExpr{Name: NewColIdent("substr"), Exprs: yyDollar[3].selectExprsUnion()} + yyLOCAL = &FuncExpr{Name: NewColIdent("replace"), Exprs: yyDollar[3].selectExprsUnion()} } yyVAL.union = yyLOCAL case 793: @@ -11659,56 +11711,58 @@ yydefault: } yyVAL.union = yyLOCAL case 794: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL MatchExprOption -//line sql.y:4026 + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL Expr +//line sql.y:4024 { - yyLOCAL = NoOption + yyLOCAL = &FuncExpr{Name: NewColIdent("substr"), Exprs: yyDollar[3].selectExprsUnion()} } yyVAL.union = yyLOCAL case 795: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL MatchExprOption //line sql.y:4030 { - yyLOCAL = BooleanModeOpt + yyLOCAL = NoOption } yyVAL.union = yyLOCAL case 796: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL MatchExprOption //line sql.y:4034 { - yyLOCAL = NaturalLanguageModeOpt + yyLOCAL = BooleanModeOpt } yyVAL.union = yyLOCAL case 797: - yyDollar = yyS[yypt-7 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL MatchExprOption //line sql.y:4038 { - yyLOCAL = NaturalLanguageModeWithQueryExpansionOpt + yyLOCAL = NaturalLanguageModeOpt } yyVAL.union = yyLOCAL case 798: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-7 : yypt+1] var yyLOCAL MatchExprOption //line sql.y:4042 { - yyLOCAL = QueryExpansionOpt + yyLOCAL = NaturalLanguageModeWithQueryExpansionOpt } yyVAL.union = yyLOCAL case 799: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4048 + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL MatchExprOption +//line sql.y:4046 { - yyVAL.str = string(yyDollar[1].colIdent.String()) + yyLOCAL = QueryExpansionOpt } + yyVAL.union = yyLOCAL case 800: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:4052 { - yyVAL.str = string(yyDollar[1].str) + yyVAL.str = string(yyDollar[1].colIdent.String()) } case 801: yyDollar = yyS[yypt-1 : yypt+1] @@ -11717,216 +11771,214 @@ yydefault: yyVAL.str = string(yyDollar[1].str) } case 802: + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:4060 + { + yyVAL.str = string(yyDollar[1].str) + } + case 803: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4062 +//line sql.y:4066 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str), Length: yyDollar[2].literalUnion()} } yyVAL.union = yyLOCAL - case 803: + case 804: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4066 +//line sql.y:4070 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str), Length: yyDollar[2].literalUnion(), Charset: yyDollar[3].str, Operator: CharacterSetOp} } yyVAL.union = yyLOCAL - case 804: + case 805: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4070 +//line sql.y:4074 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str), Length: yyDollar[2].literalUnion(), Charset: string(yyDollar[3].colIdent.String())} } yyVAL.union = yyLOCAL - case 805: + case 806: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4074 +//line sql.y:4078 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str)} } yyVAL.union = yyLOCAL - case 806: + case 807: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4078 +//line sql.y:4082 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str), Length: yyDollar[2].literalUnion()} } yyVAL.union = yyLOCAL - case 807: + case 808: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4082 +//line sql.y:4086 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str)} yyLOCAL.Length = yyDollar[2].LengthScaleOption.Length yyLOCAL.Scale = yyDollar[2].LengthScaleOption.Scale } yyVAL.union = yyLOCAL - case 808: + case 809: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4088 +//line sql.y:4092 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str)} } yyVAL.union = yyLOCAL - case 809: + case 810: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4092 +//line sql.y:4096 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str), Length: yyDollar[2].literalUnion()} } yyVAL.union = yyLOCAL - case 810: + case 811: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4096 +//line sql.y:4100 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str)} } yyVAL.union = yyLOCAL - case 811: + case 812: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4100 +//line sql.y:4104 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str)} } yyVAL.union = yyLOCAL - case 812: + case 813: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4104 +//line sql.y:4108 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str), Length: yyDollar[2].literalUnion()} } yyVAL.union = yyLOCAL - case 813: + case 814: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4108 +//line sql.y:4112 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str)} } yyVAL.union = yyLOCAL - case 814: + case 815: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *ConvertType -//line sql.y:4112 +//line sql.y:4116 { yyLOCAL = &ConvertType{Type: string(yyDollar[1].str)} } yyVAL.union = yyLOCAL - case 815: + case 816: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL Expr -//line sql.y:4117 +//line sql.y:4121 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 816: + case 817: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr -//line sql.y:4121 +//line sql.y:4125 { yyLOCAL = yyDollar[1].exprUnion() } yyVAL.union = yyLOCAL - case 817: + case 818: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4126 +//line sql.y:4130 { yyVAL.str = string("") } - case 818: + case 819: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4130 +//line sql.y:4134 { yyVAL.str = " separator " + encodeSQLString(yyDollar[2].str) } - case 819: + case 820: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL []*When -//line sql.y:4136 +//line sql.y:4140 { yyLOCAL = []*When{yyDollar[1].whenUnion()} } yyVAL.union = yyLOCAL - case 820: + case 821: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4140 +//line sql.y:4144 { yySLICE := (*[]*When)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[2].whenUnion()) } - case 821: + case 822: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL *When -//line sql.y:4146 +//line sql.y:4150 { yyLOCAL = &When{Cond: yyDollar[2].exprUnion(), Val: yyDollar[4].exprUnion()} } yyVAL.union = yyLOCAL - case 822: + case 823: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL Expr -//line sql.y:4151 +//line sql.y:4155 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 823: + case 824: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:4155 +//line sql.y:4159 { yyLOCAL = yyDollar[2].exprUnion() } yyVAL.union = yyLOCAL - case 824: + case 825: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL *ColName -//line sql.y:4161 +//line sql.y:4165 { yyLOCAL = &ColName{Name: yyDollar[1].colIdent} } yyVAL.union = yyLOCAL - case 825: + case 826: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *ColName -//line sql.y:4165 +//line sql.y:4169 { yyLOCAL = &ColName{Qualifier: TableName{Name: yyDollar[1].tableIdent}, Name: yyDollar[3].colIdent} } yyVAL.union = yyLOCAL - case 826: + case 827: yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL *ColName -//line sql.y:4169 +//line sql.y:4173 { yyLOCAL = &ColName{Qualifier: TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent}, Name: yyDollar[5].colIdent} } yyVAL.union = yyLOCAL - case 827: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL Expr -//line sql.y:4175 - { - yyLOCAL = NewStrLiteral(yyDollar[1].str) - } - yyVAL.union = yyLOCAL case 828: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr //line sql.y:4179 { - yyLOCAL = NewHexLiteral(yyDollar[1].str) + yyLOCAL = NewStrLiteral(yyDollar[1].str) } yyVAL.union = yyLOCAL case 829: @@ -11934,7 +11986,7 @@ yydefault: var yyLOCAL Expr //line sql.y:4183 { - yyLOCAL = NewBitLiteral(yyDollar[1].str) + yyLOCAL = NewHexLiteral(yyDollar[1].str) } yyVAL.union = yyLOCAL case 830: @@ -11942,7 +11994,7 @@ yydefault: var yyLOCAL Expr //line sql.y:4187 { - yyLOCAL = NewIntLiteral(yyDollar[1].str) + yyLOCAL = NewBitLiteral(yyDollar[1].str) } yyVAL.union = yyLOCAL case 831: @@ -11950,7 +12002,7 @@ yydefault: var yyLOCAL Expr //line sql.y:4191 { - yyLOCAL = NewFloatLiteral(yyDollar[1].str) + yyLOCAL = NewIntLiteral(yyDollar[1].str) } yyVAL.union = yyLOCAL case 832: @@ -11958,30 +12010,38 @@ yydefault: var yyLOCAL Expr //line sql.y:4195 { - yyLOCAL = NewHexNumLiteral(yyDollar[1].str) + yyLOCAL = NewFloatLiteral(yyDollar[1].str) } yyVAL.union = yyLOCAL case 833: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr //line sql.y:4199 + { + yyLOCAL = NewHexNumLiteral(yyDollar[1].str) + } + yyVAL.union = yyLOCAL + case 834: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL Expr +//line sql.y:4203 { yyLOCAL = NewArgument(yyDollar[1].str[1:]) bindVariable(yylex, yyDollar[1].str[1:]) } yyVAL.union = yyLOCAL - case 834: + case 835: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr -//line sql.y:4204 +//line sql.y:4208 { yyLOCAL = &NullVal{} } yyVAL.union = yyLOCAL - case 835: + case 836: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr -//line sql.y:4210 +//line sql.y:4214 { // TODO(sougou): Deprecate this construct. if yyDollar[1].colIdent.Lowered() != "value" { @@ -11991,164 +12051,156 @@ yydefault: yyLOCAL = NewIntLiteral("1") } yyVAL.union = yyLOCAL - case 836: + case 837: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:4219 +//line sql.y:4223 { yyLOCAL = NewIntLiteral(yyDollar[1].str) } yyVAL.union = yyLOCAL - case 837: + case 838: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:4223 +//line sql.y:4227 { yyLOCAL = NewArgument(yyDollar[1].str[1:]) bindVariable(yylex, yyDollar[1].str[1:]) } yyVAL.union = yyLOCAL - case 838: + case 839: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL Exprs -//line sql.y:4229 +//line sql.y:4233 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 839: + case 840: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Exprs -//line sql.y:4233 +//line sql.y:4237 { yyLOCAL = yyDollar[3].exprsUnion() } yyVAL.union = yyLOCAL - case 840: + case 841: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL Expr -//line sql.y:4238 +//line sql.y:4242 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 841: + case 842: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Expr -//line sql.y:4242 +//line sql.y:4246 { yyLOCAL = yyDollar[2].exprUnion() } yyVAL.union = yyLOCAL - case 842: + case 843: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL OrderBy -//line sql.y:4247 +//line sql.y:4251 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 843: + case 844: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL OrderBy -//line sql.y:4251 +//line sql.y:4255 { yyLOCAL = yyDollar[3].orderByUnion() } yyVAL.union = yyLOCAL - case 844: + case 845: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL OrderBy -//line sql.y:4257 +//line sql.y:4261 { yyLOCAL = OrderBy{yyDollar[1].orderUnion()} } yyVAL.union = yyLOCAL - case 845: + case 846: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4261 +//line sql.y:4265 { yySLICE := (*OrderBy)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[3].orderUnion()) } - case 846: + case 847: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *Order -//line sql.y:4267 +//line sql.y:4271 { yyLOCAL = &Order{Expr: yyDollar[1].exprUnion(), Direction: yyDollar[2].orderDirectionUnion()} } yyVAL.union = yyLOCAL - case 847: + case 848: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL OrderDirection -//line sql.y:4272 +//line sql.y:4276 { yyLOCAL = AscOrder } yyVAL.union = yyLOCAL - case 848: + case 849: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL OrderDirection -//line sql.y:4276 +//line sql.y:4280 { yyLOCAL = AscOrder } yyVAL.union = yyLOCAL - case 849: + case 850: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL OrderDirection -//line sql.y:4280 +//line sql.y:4284 { yyLOCAL = DescOrder } yyVAL.union = yyLOCAL - case 850: + case 851: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL *Limit -//line sql.y:4285 +//line sql.y:4289 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 851: + case 852: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *Limit -//line sql.y:4289 +//line sql.y:4293 { yyLOCAL = &Limit{Rowcount: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL - case 852: + case 853: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL *Limit -//line sql.y:4293 +//line sql.y:4297 { yyLOCAL = &Limit{Offset: yyDollar[2].exprUnion(), Rowcount: yyDollar[4].exprUnion()} } yyVAL.union = yyLOCAL - case 853: + case 854: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL *Limit -//line sql.y:4297 +//line sql.y:4301 { yyLOCAL = &Limit{Offset: yyDollar[4].exprUnion(), Rowcount: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL - case 854: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []AlterOption -//line sql.y:4302 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL case 855: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL []AlterOption //line sql.y:4306 { - yyLOCAL = []AlterOption{yyDollar[1].alterOptionUnion(), yyDollar[2].alterOptionUnion()} + yyLOCAL = nil } yyVAL.union = yyLOCAL case 856: @@ -12160,11 +12212,11 @@ yydefault: } yyVAL.union = yyLOCAL case 857: - yyDollar = yyS[yypt-1 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL []AlterOption //line sql.y:4314 { - yyLOCAL = []AlterOption{yyDollar[1].alterOptionUnion()} + yyLOCAL = []AlterOption{yyDollar[1].alterOptionUnion(), yyDollar[2].alterOptionUnion()} } yyVAL.union = yyLOCAL case 858: @@ -12176,11 +12228,11 @@ yydefault: } yyVAL.union = yyLOCAL case 859: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL AlterOption -//line sql.y:4325 + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []AlterOption +//line sql.y:4322 { - yyLOCAL = &LockOption{Type: DefaultType} + yyLOCAL = []AlterOption{yyDollar[1].alterOptionUnion()} } yyVAL.union = yyLOCAL case 860: @@ -12188,7 +12240,7 @@ yydefault: var yyLOCAL AlterOption //line sql.y:4329 { - yyLOCAL = &LockOption{Type: NoneType} + yyLOCAL = &LockOption{Type: DefaultType} } yyVAL.union = yyLOCAL case 861: @@ -12196,7 +12248,7 @@ yydefault: var yyLOCAL AlterOption //line sql.y:4333 { - yyLOCAL = &LockOption{Type: SharedType} + yyLOCAL = &LockOption{Type: NoneType} } yyVAL.union = yyLOCAL case 862: @@ -12204,15 +12256,15 @@ yydefault: var yyLOCAL AlterOption //line sql.y:4337 { - yyLOCAL = &LockOption{Type: ExclusiveType} + yyLOCAL = &LockOption{Type: SharedType} } yyVAL.union = yyLOCAL case 863: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL AlterOption -//line sql.y:4343 +//line sql.y:4341 { - yyLOCAL = AlgorithmValue(yyDollar[3].str) + yyLOCAL = &LockOption{Type: ExclusiveType} } yyVAL.union = yyLOCAL case 864: @@ -12232,16 +12284,18 @@ yydefault: } yyVAL.union = yyLOCAL case 866: - yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4356 + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL AlterOption +//line sql.y:4355 { - yyVAL.str = "" + yyLOCAL = AlgorithmValue(yyDollar[3].str) } + yyVAL.union = yyLOCAL case 867: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-0 : yypt+1] //line sql.y:4360 { - yyVAL.str = string(yyDollar[3].str) + yyVAL.str = "" } case 868: yyDollar = yyS[yypt-3 : yypt+1] @@ -12256,22 +12310,22 @@ yydefault: yyVAL.str = string(yyDollar[3].str) } case 870: - yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4373 + yyDollar = yyS[yypt-3 : yypt+1] +//line sql.y:4372 { - yyVAL.str = "" + yyVAL.str = string(yyDollar[3].str) } case 871: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-0 : yypt+1] //line sql.y:4377 { - yyVAL.str = yyDollar[3].str + yyVAL.str = "" } case 872: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4383 + yyDollar = yyS[yypt-3 : yypt+1] +//line sql.y:4381 { - yyVAL.str = string(yyDollar[1].str) + yyVAL.str = yyDollar[3].str } case 873: yyDollar = yyS[yypt-1 : yypt+1] @@ -12280,28 +12334,28 @@ yydefault: yyVAL.str = string(yyDollar[1].str) } case 874: - yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4392 + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:4391 { - yyVAL.str = "" + yyVAL.str = string(yyDollar[1].str) } case 875: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-0 : yypt+1] //line sql.y:4396 { - yyVAL.str = yyDollar[2].str + yyVAL.str = "" } case 876: - yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4401 + yyDollar = yyS[yypt-4 : yypt+1] +//line sql.y:4400 { - yyVAL.str = "cascaded" + yyVAL.str = yyDollar[2].str } case 877: - yyDollar = yyS[yypt-1 : yypt+1] + yyDollar = yyS[yypt-0 : yypt+1] //line sql.y:4405 { - yyVAL.str = string(yyDollar[1].str) + yyVAL.str = "cascaded" } case 878: yyDollar = yyS[yypt-1 : yypt+1] @@ -12310,388 +12364,394 @@ yydefault: yyVAL.str = string(yyDollar[1].str) } case 879: + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:4413 + { + yyVAL.str = string(yyDollar[1].str) + } + case 880: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4414 +//line sql.y:4418 { yyVAL.str = "" } - case 880: + case 881: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4418 +//line sql.y:4422 { yyVAL.str = yyDollar[3].str } - case 881: + case 882: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4424 +//line sql.y:4428 { yyVAL.str = string(yyDollar[1].str) } - case 882: + case 883: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4428 +//line sql.y:4432 { yyVAL.str = string(yyDollar[1].str) } - case 883: + case 884: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4432 +//line sql.y:4436 { yyVAL.str = encodeSQLString(yyDollar[1].str) + "@" + string(yyDollar[2].str) } - case 884: + case 885: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4436 +//line sql.y:4440 { yyVAL.str = string(yyDollar[1].str) } - case 885: + case 886: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL Lock -//line sql.y:4441 +//line sql.y:4445 { yyLOCAL = NoLock } yyVAL.union = yyLOCAL - case 886: + case 887: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL Lock -//line sql.y:4445 +//line sql.y:4449 { yyLOCAL = ForUpdateLock } yyVAL.union = yyLOCAL - case 887: + case 888: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL Lock -//line sql.y:4449 +//line sql.y:4453 { yyLOCAL = ShareModeLock } yyVAL.union = yyLOCAL - case 888: + case 889: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL *SelectInto -//line sql.y:4454 +//line sql.y:4458 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 889: + case 890: yyDollar = yyS[yypt-9 : yypt+1] var yyLOCAL *SelectInto -//line sql.y:4458 +//line sql.y:4462 { yyLOCAL = &SelectInto{Type: IntoOutfileS3, FileName: encodeSQLString(yyDollar[4].str), Charset: yyDollar[5].str, FormatOption: yyDollar[6].str, ExportOption: yyDollar[7].str, Manifest: yyDollar[8].str, Overwrite: yyDollar[9].str} } yyVAL.union = yyLOCAL - case 890: + case 891: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *SelectInto -//line sql.y:4462 +//line sql.y:4466 { yyLOCAL = &SelectInto{Type: IntoDumpfile, FileName: encodeSQLString(yyDollar[3].str), Charset: "", FormatOption: "", ExportOption: "", Manifest: "", Overwrite: ""} } yyVAL.union = yyLOCAL - case 891: + case 892: yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL *SelectInto -//line sql.y:4466 +//line sql.y:4470 { yyLOCAL = &SelectInto{Type: IntoOutfile, FileName: encodeSQLString(yyDollar[3].str), Charset: yyDollar[4].str, FormatOption: "", ExportOption: yyDollar[5].str, Manifest: "", Overwrite: ""} } yyVAL.union = yyLOCAL - case 892: + case 893: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4471 +//line sql.y:4475 { yyVAL.str = "" } - case 893: + case 894: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4475 +//line sql.y:4479 { yyVAL.str = " format csv" + yyDollar[3].str } - case 894: + case 895: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4479 +//line sql.y:4483 { yyVAL.str = " format text" + yyDollar[3].str } - case 895: + case 896: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4484 +//line sql.y:4488 { yyVAL.str = "" } - case 896: + case 897: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4488 +//line sql.y:4492 { yyVAL.str = " header" } - case 897: + case 898: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4493 +//line sql.y:4497 { yyVAL.str = "" } - case 898: + case 899: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4497 +//line sql.y:4501 { yyVAL.str = " manifest on" } - case 899: + case 900: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4501 +//line sql.y:4505 { yyVAL.str = " manifest off" } - case 900: + case 901: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4506 +//line sql.y:4510 { yyVAL.str = "" } - case 901: + case 902: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4510 +//line sql.y:4514 { yyVAL.str = " overwrite on" } - case 902: + case 903: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4514 +//line sql.y:4518 { yyVAL.str = " overwrite off" } - case 903: + case 904: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4520 +//line sql.y:4524 { yyVAL.str = yyDollar[1].str + yyDollar[2].str } - case 904: + case 905: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4525 +//line sql.y:4529 { yyVAL.str = "" } - case 905: + case 906: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4529 +//line sql.y:4533 { yyVAL.str = " lines" + yyDollar[2].str } - case 906: + case 907: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4535 +//line sql.y:4539 { yyVAL.str = yyDollar[1].str } - case 907: + case 908: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4539 +//line sql.y:4543 { yyVAL.str = yyDollar[1].str + yyDollar[2].str } - case 908: + case 909: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4545 +//line sql.y:4549 { yyVAL.str = " starting by " + encodeSQLString(yyDollar[3].str) } - case 909: + case 910: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4549 +//line sql.y:4553 { yyVAL.str = " terminated by " + encodeSQLString(yyDollar[3].str) } - case 910: + case 911: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4554 +//line sql.y:4558 { yyVAL.str = "" } - case 911: + case 912: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4558 +//line sql.y:4562 { yyVAL.str = " " + yyDollar[1].str + yyDollar[2].str } - case 912: + case 913: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4564 +//line sql.y:4568 { yyVAL.str = yyDollar[1].str } - case 913: + case 914: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4568 +//line sql.y:4572 { yyVAL.str = yyDollar[1].str + yyDollar[2].str } - case 914: + case 915: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4574 +//line sql.y:4578 { yyVAL.str = " terminated by " + encodeSQLString(yyDollar[3].str) } - case 915: + case 916: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:4578 +//line sql.y:4582 { yyVAL.str = yyDollar[1].str + " enclosed by " + encodeSQLString(yyDollar[4].str) } - case 916: + case 917: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4582 +//line sql.y:4586 { yyVAL.str = " escaped by " + encodeSQLString(yyDollar[3].str) } - case 917: + case 918: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4587 +//line sql.y:4591 { yyVAL.str = "" } - case 918: + case 919: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4591 +//line sql.y:4595 { yyVAL.str = " optionally" } - case 919: + case 920: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *Insert -//line sql.y:4604 +//line sql.y:4608 { yyLOCAL = &Insert{Rows: yyDollar[2].valuesUnion()} } yyVAL.union = yyLOCAL - case 920: + case 921: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL *Insert -//line sql.y:4608 +//line sql.y:4612 { yyLOCAL = &Insert{Rows: yyDollar[1].selStmtUnion()} } yyVAL.union = yyLOCAL - case 921: + case 922: yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL *Insert -//line sql.y:4612 +//line sql.y:4616 { yyLOCAL = &Insert{Columns: yyDollar[2].columnsUnion(), Rows: yyDollar[5].valuesUnion()} } yyVAL.union = yyLOCAL - case 922: + case 923: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL *Insert -//line sql.y:4616 +//line sql.y:4620 { yyLOCAL = &Insert{Rows: yyDollar[4].valuesUnion()} } yyVAL.union = yyLOCAL - case 923: + case 924: yyDollar = yyS[yypt-4 : yypt+1] var yyLOCAL *Insert -//line sql.y:4620 +//line sql.y:4624 { yyLOCAL = &Insert{Columns: yyDollar[2].columnsUnion(), Rows: yyDollar[4].selStmtUnion()} } yyVAL.union = yyLOCAL - case 924: + case 925: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Columns -//line sql.y:4626 +//line sql.y:4630 { yyLOCAL = Columns{yyDollar[1].colIdent} } yyVAL.union = yyLOCAL - case 925: + case 926: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL Columns -//line sql.y:4630 +//line sql.y:4634 { yyLOCAL = Columns{yyDollar[3].colIdent} } yyVAL.union = yyLOCAL - case 926: + case 927: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4634 +//line sql.y:4638 { yySLICE := (*Columns)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[3].colIdent) } - case 927: + case 928: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:4638 +//line sql.y:4642 { yySLICE := (*Columns)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[5].colIdent) } - case 928: + case 929: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL UpdateExprs -//line sql.y:4643 +//line sql.y:4647 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 929: + case 930: yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL UpdateExprs -//line sql.y:4647 +//line sql.y:4651 { yyLOCAL = yyDollar[5].updateExprsUnion() } yyVAL.union = yyLOCAL - case 930: + case 931: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Values -//line sql.y:4653 +//line sql.y:4657 { yyLOCAL = Values{yyDollar[1].valTupleUnion()} } yyVAL.union = yyLOCAL - case 931: + case 932: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4657 +//line sql.y:4661 { yySLICE := (*Values)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[3].valTupleUnion()) } - case 932: + case 933: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL ValTuple -//line sql.y:4663 +//line sql.y:4667 { yyLOCAL = yyDollar[1].valTupleUnion() } yyVAL.union = yyLOCAL - case 933: + case 934: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL ValTuple -//line sql.y:4667 +//line sql.y:4671 { yyLOCAL = ValTuple{} } yyVAL.union = yyLOCAL - case 934: + case 935: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL ValTuple -//line sql.y:4673 +//line sql.y:4677 { yyLOCAL = ValTuple(yyDollar[2].exprsUnion()) } yyVAL.union = yyLOCAL - case 935: + case 936: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr -//line sql.y:4679 +//line sql.y:4683 { if len(yyDollar[1].valTupleUnion()) == 1 { yyLOCAL = yyDollar[1].valTupleUnion()[0] @@ -12700,322 +12760,316 @@ yydefault: } } yyVAL.union = yyLOCAL - case 936: + case 937: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL UpdateExprs -//line sql.y:4689 +//line sql.y:4693 { yyLOCAL = UpdateExprs{yyDollar[1].updateExprUnion()} } yyVAL.union = yyLOCAL - case 937: + case 938: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4693 +//line sql.y:4697 { yySLICE := (*UpdateExprs)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[3].updateExprUnion()) } - case 938: + case 939: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *UpdateExpr -//line sql.y:4699 +//line sql.y:4703 { yyLOCAL = &UpdateExpr{Name: yyDollar[1].colNameUnion(), Expr: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL - case 939: + case 940: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL SetExprs -//line sql.y:4705 +//line sql.y:4709 { yyLOCAL = SetExprs{yyDollar[1].setExprUnion()} } yyVAL.union = yyLOCAL - case 940: + case 941: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:4709 +//line sql.y:4713 { yySLICE := (*SetExprs)(yyIaddr(yyVAL.union)) *yySLICE = append(*yySLICE, yyDollar[3].setExprUnion()) } - case 941: + case 942: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *SetExpr -//line sql.y:4715 +//line sql.y:4719 { yyLOCAL = &SetExpr{Name: yyDollar[1].colIdent, Scope: ImplicitScope, Expr: NewStrLiteral("on")} } yyVAL.union = yyLOCAL - case 942: + case 943: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *SetExpr -//line sql.y:4719 +//line sql.y:4723 { yyLOCAL = &SetExpr{Name: yyDollar[1].colIdent, Scope: ImplicitScope, Expr: NewStrLiteral("off")} } yyVAL.union = yyLOCAL - case 943: + case 944: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *SetExpr -//line sql.y:4723 +//line sql.y:4727 { yyLOCAL = &SetExpr{Name: yyDollar[1].colIdent, Scope: ImplicitScope, Expr: yyDollar[3].exprUnion()} } yyVAL.union = yyLOCAL - case 944: + case 945: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL *SetExpr -//line sql.y:4727 +//line sql.y:4731 { yyLOCAL = &SetExpr{Name: NewColIdent(string(yyDollar[1].str)), Scope: ImplicitScope, Expr: yyDollar[2].exprUnion()} } yyVAL.union = yyLOCAL - case 945: + case 946: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *SetExpr -//line sql.y:4731 +//line sql.y:4735 { yyDollar[2].setExprUnion().Scope = yyDollar[1].scopeUnion() yyLOCAL = yyDollar[2].setExprUnion() } yyVAL.union = yyLOCAL - case 947: + case 948: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:4739 +//line sql.y:4743 { yyVAL.str = "charset" } - case 950: + case 951: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr -//line sql.y:4749 +//line sql.y:4753 { yyLOCAL = NewStrLiteral(yyDollar[1].colIdent.String()) } yyVAL.union = yyLOCAL - case 951: + case 952: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr -//line sql.y:4753 +//line sql.y:4757 { yyLOCAL = NewStrLiteral(yyDollar[1].str) } yyVAL.union = yyLOCAL - case 952: + case 953: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Expr -//line sql.y:4757 +//line sql.y:4761 { yyLOCAL = &Default{} } yyVAL.union = yyLOCAL - case 955: + case 956: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL bool -//line sql.y:4766 +//line sql.y:4770 { yyLOCAL = false } yyVAL.union = yyLOCAL - case 956: + case 957: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL bool -//line sql.y:4768 +//line sql.y:4772 { yyLOCAL = true } yyVAL.union = yyLOCAL - case 957: + case 958: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL bool -//line sql.y:4771 +//line sql.y:4775 { yyLOCAL = false } yyVAL.union = yyLOCAL - case 958: + case 959: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL bool -//line sql.y:4773 +//line sql.y:4777 { yyLOCAL = true } yyVAL.union = yyLOCAL - case 959: + case 960: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL bool -//line sql.y:4776 +//line sql.y:4780 { yyLOCAL = false } yyVAL.union = yyLOCAL - case 960: + case 961: yyDollar = yyS[yypt-3 : yypt+1] var yyLOCAL bool -//line sql.y:4778 +//line sql.y:4782 { yyLOCAL = true } yyVAL.union = yyLOCAL - case 961: + case 962: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL Ignore -//line sql.y:4781 +//line sql.y:4785 { yyLOCAL = false } yyVAL.union = yyLOCAL - case 962: + case 963: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Ignore -//line sql.y:4783 +//line sql.y:4787 { yyLOCAL = true } yyVAL.union = yyLOCAL - case 963: + case 964: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4786 +//line sql.y:4790 { yyVAL.empty = struct{}{} } - case 964: + case 965: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4788 +//line sql.y:4792 { yyVAL.empty = struct{}{} } - case 965: + case 966: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4790 +//line sql.y:4794 { yyVAL.empty = struct{}{} } - case 966: + case 967: yyDollar = yyS[yypt-5 : yypt+1] var yyLOCAL Statement -//line sql.y:4794 +//line sql.y:4798 { yyLOCAL = &CallProc{Name: yyDollar[2].tableName, Params: yyDollar[4].exprsUnion()} } yyVAL.union = yyLOCAL - case 967: + case 968: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL Exprs -//line sql.y:4799 +//line sql.y:4803 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 968: + case 969: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL Exprs -//line sql.y:4803 +//line sql.y:4807 { yyLOCAL = yyDollar[1].exprsUnion() } yyVAL.union = yyLOCAL - case 969: + case 970: yyDollar = yyS[yypt-0 : yypt+1] var yyLOCAL []*IndexOption -//line sql.y:4808 +//line sql.y:4812 { yyLOCAL = nil } yyVAL.union = yyLOCAL - case 970: + case 971: yyDollar = yyS[yypt-1 : yypt+1] var yyLOCAL []*IndexOption -//line sql.y:4810 +//line sql.y:4814 { yyLOCAL = []*IndexOption{yyDollar[1].indexOptionUnion()} } yyVAL.union = yyLOCAL - case 971: + case 972: yyDollar = yyS[yypt-2 : yypt+1] var yyLOCAL *IndexOption -//line sql.y:4814 +//line sql.y:4818 { yyLOCAL = &IndexOption{Name: string(yyDollar[1].str), String: string(yyDollar[2].colIdent.String())} } yyVAL.union = yyLOCAL - case 972: + case 973: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4820 +//line sql.y:4824 { yyVAL.colIdent = yyDollar[1].colIdent } - case 973: + case 974: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4824 +//line sql.y:4828 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].str)) } - case 975: + case 976: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4831 +//line sql.y:4835 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].str)) } - case 976: + case 977: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4837 +//line sql.y:4841 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].colIdent.String())) } - case 977: + case 978: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4841 +//line sql.y:4845 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].str)) } - case 978: + case 979: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:4847 +//line sql.y:4851 { yyVAL.tableIdent = NewTableIdent("") } - case 979: + case 980: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4851 +//line sql.y:4855 { yyVAL.tableIdent = yyDollar[1].tableIdent } - case 981: + case 982: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:4858 +//line sql.y:4862 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].str)) } - case 1395: + case 1396: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:5296 +//line sql.y:5300 { if incNesting(yylex) { yylex.Error("max nesting level reached") return 1 } } - case 1396: + case 1397: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:5305 +//line sql.y:5309 { decNesting(yylex) } - case 1397: - yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:5310 - { - skipToEnd(yylex) - } case 1398: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:5315 +//line sql.y:5314 { skipToEnd(yylex) } case 1399: - yyDollar = yyS[yypt-1 : yypt+1] + yyDollar = yyS[yypt-0 : yypt+1] //line sql.y:5319 { skipToEnd(yylex) @@ -13026,6 +13080,12 @@ yydefault: { skipToEnd(yylex) } + case 1401: + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:5327 + { + skipToEnd(yylex) + } } goto yystack /* stack new state and value */ } diff --git a/go/vt/sqlparser/sql.y b/go/vt/sqlparser/sql.y index 9394f47b3e0..bc6c3029335 100644 --- a/go/vt/sqlparser/sql.y +++ b/go/vt/sqlparser/sql.y @@ -2603,6 +2603,10 @@ show_statement: { $$ = &Show{&ShowBasic{Command: VitessMigrations, Filter: $4, DbName: $3}} } +| SHOW VITESS_MIGRATION STRING LOGS + { + $$ = &ShowMigrationLogs{UUID: string($3)} + } | SHOW VSCHEMA TABLES { $$ = &Show{&ShowLegacy{Type: string($2) + " " + string($3), Scope: ImplicitScope}} diff --git a/go/vt/sqlparser/utils.go b/go/vt/sqlparser/utils.go index a9ec689aa2e..e2bee2cb959 100644 --- a/go/vt/sqlparser/utils.go +++ b/go/vt/sqlparser/utils.go @@ -40,7 +40,7 @@ func QueryMatchesTemplates(query string, queryTemplates []string) (match bool, e if err != nil { return "", err } - err = Normalize(stmt, NewReservedVars("", reservedVars), bv) + _, err = Normalize(stmt, NewReservedVars("", reservedVars), bv) if err != nil { return "", err } diff --git a/go/vt/srvtopo/resilient_server.go b/go/vt/srvtopo/resilient_server.go index edf9568f30d..8dd78f16624 100644 --- a/go/vt/srvtopo/resilient_server.go +++ b/go/vt/srvtopo/resilient_server.go @@ -20,7 +20,6 @@ import ( "flag" "fmt" "html/template" - "net/url" "sort" "sync" "time" @@ -467,11 +466,12 @@ func (server *ResilientServer) watchSrvKeyspace(callerCtx context.Context, entry } server.counts.Add(errorCategory, 1) - log.Errorf("Initial WatchSrvKeyspace failed for %v/%v: %v", cell, keyspace, current.Err) + log.Errorf("Initial WatchSrvKeyspace failed for %v/%v: %T %v", cell, keyspace, current.Err, current.Err) // This watcher will able to continue to return the last value till it is not able to connect to the topo server even if the cache TTL is reached. - _, netErr := current.Err.(*url.Error) - if !netErr && time.Since(entry.lastValueTime) > server.cacheTTL { + // TTL cache is only checked if the error is a known error i.e topo.Error. + _, topoErr := current.Err.(topo.Error) + if topoErr && time.Since(entry.lastValueTime) > server.cacheTTL { log.Errorf("WatchSrvKeyspace clearing cached entry for %v/%v", cell, keyspace) entry.value = nil } diff --git a/go/vt/srvtopo/resilient_server_test.go b/go/vt/srvtopo/resilient_server_test.go index 5fad2cf44cb..3ed58499397 100644 --- a/go/vt/srvtopo/resilient_server_test.go +++ b/go/vt/srvtopo/resilient_server_test.go @@ -141,7 +141,7 @@ func TestGetSrvKeyspace(t *testing.T) { // cached for at least half of the expected ttl. errorTestStart := time.Now() errorReqsBefore := rs.counts.Counts()[errorCategory] - forceErr := fmt.Errorf("test topo error") + forceErr := topo.NewError(topo.Timeout, "test topo error") factory.SetError(forceErr) expiry = time.Now().Add(*srvTopoCacheTTL / 2) @@ -200,7 +200,7 @@ func TestGetSrvKeyspace(t *testing.T) { // that even when there is no activity on the key, it is still cached // for the full configured TTL. time.Sleep(*srvTopoCacheTTL) - forceErr = fmt.Errorf("another test topo error") + forceErr = topo.NewError(topo.Interrupted, "another test topo error") factory.SetError(forceErr) expiry = time.Now().Add(*srvTopoCacheTTL / 2) diff --git a/go/vt/topo/tablet.go b/go/vt/topo/tablet.go index 42cb1544f97..5658346963e 100644 --- a/go/vt/topo/tablet.go +++ b/go/vt/topo/tablet.go @@ -228,6 +228,7 @@ func NewTabletInfo(tablet *topodatapb.Tablet, version Version) *TabletInfo { func (ts *Server) GetTablet(ctx context.Context, alias *topodatapb.TabletAlias) (*TabletInfo, error) { conn, err := ts.ConnForCell(ctx, alias.Cell) if err != nil { + log.Errorf("Unable to get connection for cell %s", alias.Cell) return nil, err } @@ -238,6 +239,7 @@ func (ts *Server) GetTablet(ctx context.Context, alias *topodatapb.TabletAlias) tabletPath := path.Join(TabletsPath, topoproto.TabletAliasString(alias), TabletFile) data, version, err := conn.Get(ctx, tabletPath) if err != nil { + log.Errorf("unable to connect to tablet %s: %s", alias, err) return nil, err } tablet := &topodatapb.Tablet{} diff --git a/go/vt/topo/vschema.go b/go/vt/topo/vschema.go index c64713488a1..af5dace20ca 100644 --- a/go/vt/topo/vschema.go +++ b/go/vt/topo/vschema.go @@ -46,7 +46,9 @@ func (ts *Server) SaveVSchema(ctx context.Context, keyspace string, vschema *vsc _, err = ts.globalCell.Update(ctx, nodePath, data, nil) if err != nil { - log.Infof("successfully updated vschema for keyspace %s: %v", keyspace, data) + log.Errorf("failed to update vschema for keyspace %s: %v", keyspace, err) + } else { + log.Infof("successfully updated vschema for keyspace %s: %+v", keyspace, vschema) } return err } diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index aa0350072e0..fc5e954624f 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -1831,19 +1831,29 @@ func commandValidateKeyspace(ctx context.Context, wr *wrangler.Wrangler, subFlag return wr.ValidateKeyspace(ctx, keyspace, *pingTablets) } -func commandReshard(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { +func useV1(args []string) bool { for _, arg := range args { - if arg == "-v2" { - fmt.Println("*** Using Reshard v2 flow ***") - return commandVRWorkflow(ctx, wr, subFlags, args, wrangler.ReshardWorkflow) + if arg == "-v1" { + return true } } + return false +} + +func commandReshard(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { + if !useV1(args) { + log.Infof("*** Using Reshard v2 flow ***") + return commandVRWorkflow(ctx, wr, subFlags, args, wrangler.ReshardWorkflow) + } + wr.Logger().Printf("*** The Reshard v1 flow is deprecated, consider using v2 commands instead, see https://vitess.io/docs/reference/vreplication/v2/ ***\n") + cells := subFlags.String("cells", "", "Cell(s) or CellAlias(es) (comma-separated) to replicate from.") tabletTypes := subFlags.String("tablet_types", "", "Source tablet types to replicate from.") skipSchemaCopy := subFlags.Bool("skip_schema_copy", false, "Skip copying of schema to targets") autoStart := subFlags.Bool("auto_start", true, "If false, streams will start in the Stopped state and will need to be explicitly started") stopAfterCopy := subFlags.Bool("stop_after_copy", false, "Streams will be stopped once the copy phase is completed") + _ = subFlags.Bool("v1", true, "") if err := subFlags.Parse(args); err != nil { return err @@ -1862,12 +1872,12 @@ func commandReshard(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.F } func commandMoveTables(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { - for _, arg := range args { - if arg == "-v2" { - fmt.Println("*** Using MoveTables v2 flow ***") - return commandVRWorkflow(ctx, wr, subFlags, args, wrangler.MoveTablesWorkflow) - } + if !useV1(args) { + log.Infof("*** Using MoveTables v2 flow ***") + return commandVRWorkflow(ctx, wr, subFlags, args, wrangler.MoveTablesWorkflow) } + wr.Logger().Printf("*** The MoveTables v1 flow is deprecated, consider using v2 commands instead, see https://vitess.io/docs/reference/vreplication/v2/ ***\n") + workflow := subFlags.String("workflow", "", "Workflow name. Can be any descriptive string. Will be used to later migrate traffic via SwitchReads/SwitchWrites.") cells := subFlags.String("cells", "", "Cell(s) or CellAlias(es) (comma-separated) to replicate from.") tabletTypes := subFlags.String("tablet_types", "", "Source tablet types to replicate from (e.g. master, replica, rdonly). Defaults to -vreplication_tablet_type parameter value for the tablet, which has the default value of replica.") @@ -1876,6 +1886,7 @@ func commandMoveTables(ctx context.Context, wr *wrangler.Wrangler, subFlags *fla autoStart := subFlags.Bool("auto_start", true, "If false, streams will start in the Stopped state and will need to be explicitly started") stopAfterCopy := subFlags.Bool("stop_after_copy", false, "Streams will be stopped once the copy phase is completed") + _ = subFlags.Bool("v1", true, "") if err := subFlags.Parse(args); err != nil { return err @@ -1931,7 +1942,7 @@ func getSourceKeyspace(clusterKeyspace string) (clusterName string, sourceKeyspa } // commandVRWorkflow is the common entry point for MoveTables/Reshard/Migrate workflows -// FIXME: this needs a refactor. Also validations for params need to be done per workflow type +// FIXME: this function needs a refactor. Also validations for params should to be done per workflow type func commandVRWorkflow(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string, workflowType wrangler.VReplicationWorkflowType) error { @@ -2259,8 +2270,8 @@ func commandVRWorkflow(ctx context.Context, wr *wrangler.Wrangler, subFlags *fla return nil } } - wr.Logger().Printf("%s was successful\nStart State: %s\nCurrent State: %s\n\n", - originalAction, startState, wf.CurrentState()) + wr.Logger().Printf("%s was successful for workflow %s.%s\nStart State: %s\nCurrent State: %s\n\n", + originalAction, vrwp.TargetKeyspace, vrwp.Workflow, startState, wf.CurrentState()) return nil } @@ -2269,6 +2280,7 @@ func commandCreateLookupVindex(ctx context.Context, wr *wrangler.Wrangler, subFl //TODO: keep -cell around for backward compatibility and remove it in a future version cell := subFlags.String("cell", "", "Cell to replicate from.") tabletTypes := subFlags.String("tablet_types", "", "Source tablet types to replicate from.") + continueAfterCopyWithOwner := subFlags.Bool("continue_after_copy_with_owner", false, "Vindex will continue materialization after copy when an owner is provided") if err := subFlags.Parse(args); err != nil { return err } @@ -2283,7 +2295,7 @@ func commandCreateLookupVindex(ctx context.Context, wr *wrangler.Wrangler, subFl if err := json2.Unmarshal([]byte(subFlags.Arg(1)), specs); err != nil { return err } - return wr.CreateLookupVindex(ctx, keyspace, specs, *cell, *tabletTypes) + return wr.CreateLookupVindex(ctx, keyspace, specs, *cell, *tabletTypes, *continueAfterCopyWithOwner) } func commandExternalizeVindex(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { @@ -2441,6 +2453,7 @@ func commandMigrateServedFrom(ctx context.Context, wr *wrangler.Wrangler, subFla } func commandDropSources(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { + wr.Logger().Printf("*** DropSources is deprecated. Consider using v2 commands instead, see https://vitess.io/docs/reference/vreplication/v2/ ***\n") dryRun := subFlags.Bool("dry_run", false, "Does a dry run of commandDropSources and only reports the actions to be taken") renameTables := subFlags.Bool("rename_tables", false, "Rename tables instead of dropping them") keepData := subFlags.Bool("keep_data", false, "Do not drop tables or shards (if true, only vreplication artifacts are cleaned up)") @@ -2473,6 +2486,8 @@ func commandDropSources(ctx context.Context, wr *wrangler.Wrangler, subFlags *fl } func commandSwitchReads(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { + wr.Logger().Printf("*** SwitchReads is deprecated. Consider using v2 commands instead, see https://vitess.io/docs/reference/vreplication/v2/ ***\n") + reverse := subFlags.Bool("reverse", false, "Moves the served tablet type backward instead of forward.") cellsStr := subFlags.String("cells", "", "Specifies a comma-separated list of cells to update") tabletTypes := subFlags.String("tablet_types", "rdonly,replica", "Tablet types to switch one or both or rdonly/replica") @@ -2526,6 +2541,8 @@ func commandSwitchReads(ctx context.Context, wr *wrangler.Wrangler, subFlags *fl } func commandSwitchWrites(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { + wr.Logger().Printf("*** SwitchWrites is deprecated. Consider using v2 commands instead, see https://vitess.io/docs/reference/vreplication/v2/ ***\n") + timeout := subFlags.Duration("timeout", 30*time.Second, "Specifies the maximum time to wait, in seconds, for vreplication to catch up on master migrations. The migration will be cancelled on a timeout.") filteredReplicationWaitTime := subFlags.Duration("filtered_replication_wait_time", 30*time.Second, "DEPRECATED Specifies the maximum time to wait, in seconds, for vreplication to catch up on master migrations. The migration will be cancelled on a timeout.") reverseReplication := subFlags.Bool("reverse_replication", true, "Also reverse the replication") diff --git a/go/vt/vtexplain/vtexplain_vtgate.go b/go/vt/vtexplain/vtexplain_vtgate.go index 625b3bceb5c..26c48a79de1 100644 --- a/go/vt/vtexplain/vtexplain_vtgate.go +++ b/go/vt/vtexplain/vtexplain_vtgate.go @@ -30,6 +30,7 @@ import ( "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/json2" + "vitess.io/vitess/go/streamlog" "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/log" @@ -70,7 +71,10 @@ func initVtgateExecutor(vSchemaStr, ksShardMapStr string, opts *Options) error { streamSize := 10 var schemaTracker vtgate.SchemaInfo // no schema tracker for these tests - vtgateExecutor = vtgate.NewExecutor(context.Background(), explainTopo, vtexplainCell, resolver, opts.Normalize, false /*do not warn for sharded only*/, streamSize, cache.DefaultConfig, schemaTracker) + vtgateExecutor = vtgate.NewExecutor(context.Background(), explainTopo, vtexplainCell, resolver, opts.Normalize, false /*do not warn for sharded only*/, streamSize, cache.DefaultConfig, schemaTracker, nil) + + queryLogBufferSize := 10 + vtgate.QueryLogger = streamlog.New("VTGate", queryLogBufferSize) return nil } diff --git a/go/vt/vtgate/boost/boost.go b/go/vt/vtgate/boost/boost.go new file mode 100644 index 00000000000..1a958ab2d23 --- /dev/null +++ b/go/vt/vtgate/boost/boost.go @@ -0,0 +1,24 @@ +package boost + +type Columns map[string]string + +type PlanConfig struct { + IsBoosted bool + BoostColumns Columns +} + +func NonBoostedPlanConfig() *PlanConfig { + return &PlanConfig{ + IsBoosted: false, + BoostColumns: Columns{}, + } +} + +type QueryFilterConfig struct { + Columns []string `yaml:"columns"` + TableName string `yaml:"tableName"` +} + +type QueryFilterConfigs struct { + BoostConfigs []QueryFilterConfig `yaml:"boostConfigs"` +} diff --git a/go/vt/vtgate/boost/load_configs.go b/go/vt/vtgate/boost/load_configs.go new file mode 100644 index 00000000000..461b1670b24 --- /dev/null +++ b/go/vt/vtgate/boost/load_configs.go @@ -0,0 +1,43 @@ +package boost + +import ( + "fmt" + "gopkg.in/yaml.v2" + "io/ioutil" +) + +func Load(configPath *string) (*QueryFilterConfigs, error) { + data, err := ioutil.ReadFile(*configPath) + fmt.Printf("Reading Boost Configs from: %s\n", *configPath) + if err != nil { + fmt.Printf("Error reading file: %v\n", err) + return nil, err + } + + var configs QueryFilterConfigs + err = yaml.Unmarshal(data, &configs) + if err != nil { + return nil, err + } + + fmt.Printf("Parsed Configs: %+v\n", configs) + + rocket := ` + | + / \ + / _ \ + |.'''.| + |'._.'| + |BOOST| + ,'| | |\. + / | | | \ + |,-'--|--'-.| + || || || +` + + fmt.Println(rocket) + + fmt.Println("Boost enabled.") + + return &configs, nil +} diff --git a/go/vt/vtgate/discoverygateway.go b/go/vt/vtgate/discoverygateway.go index c71620a992c..bde96830154 100644 --- a/go/vt/vtgate/discoverygateway.go +++ b/go/vt/vtgate/discoverygateway.go @@ -243,6 +243,11 @@ func (dg *DiscoveryGateway) withRetry(ctx context.Context, target *querypb.Targe var err error invalidTablets := make(map[string]bool) + if target == nil { + err = fmt.Errorf("withRetry called with nil target") + log.Errorf(err.Error()) + return err + } if len(discovery.AllowedTabletTypes) > 0 { var match bool for _, allowed := range discovery.AllowedTabletTypes { diff --git a/go/vt/vtgate/endtoend/aggr_test.go b/go/vt/vtgate/endtoend/aggr_test.go index b37697a72f4..ba161888815 100644 --- a/go/vt/vtgate/endtoend/aggr_test.go +++ b/go/vt/vtgate/endtoend/aggr_test.go @@ -54,4 +54,34 @@ func TestAggregateTypes(t *testing.T) { if got, want := fmt.Sprintf("%v", qr.Rows), `[[VARCHAR("c") INT64(2) INT64(2)] [VARCHAR("a") INT64(1) INT64(2)] [VARCHAR("b") INT64(1) INT64(1)] [VARCHAR("e") INT64(1) INT64(2)]]`; got != want { t.Errorf("select:\n%v want\n%v", got, want) } + + qr = exec(t, conn, "select ascii(val1) as a, count(*) from aggr_test group by a") + if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT32(65) INT64(1)] [INT32(69) INT64(1)] [INT32(97) INT64(1)] [INT32(98) INT64(1)] [INT32(99) INT64(2)] [INT32(100) INT64(1)] [INT32(101) INT64(1)]]`; got != want { + t.Errorf("select:\n%v want\n%v", got, want) + } + + qr = exec(t, conn, "select ascii(val1) as a, count(*) from aggr_test group by a order by a") + if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT32(65) INT64(1)] [INT32(69) INT64(1)] [INT32(97) INT64(1)] [INT32(98) INT64(1)] [INT32(99) INT64(2)] [INT32(100) INT64(1)] [INT32(101) INT64(1)]]`; got != want { + t.Errorf("select:\n%v want\n%v", got, want) + } + + qr = exec(t, conn, "select ascii(val1) as a, count(*) from aggr_test group by a order by 2, a") + if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT32(65) INT64(1)] [INT32(69) INT64(1)] [INT32(97) INT64(1)] [INT32(98) INT64(1)] [INT32(100) INT64(1)] [INT32(101) INT64(1)] [INT32(99) INT64(2)]]`; got != want { + t.Errorf("select:\n%v want\n%v", got, want) + } + + qr = exec(t, conn, "select val1 as a, count(*) from aggr_test group by a") + if got, want := fmt.Sprintf("%v", qr.Rows), `[[VARCHAR("a") INT64(2)] [VARCHAR("b") INT64(1)] [VARCHAR("c") INT64(2)] [VARCHAR("d") INT64(1)] [VARCHAR("e") INT64(2)]]`; got != want { + t.Errorf("select:\n%v want\n%v", got, want) + } + + qr = exec(t, conn, "select val1 as a, count(*) from aggr_test group by a order by a") + if got, want := fmt.Sprintf("%v", qr.Rows), `[[VARCHAR("a") INT64(2)] [VARCHAR("b") INT64(1)] [VARCHAR("c") INT64(2)] [VARCHAR("d") INT64(1)] [VARCHAR("e") INT64(2)]]`; got != want { + t.Errorf("select:\n%v want\n%v", got, want) + } + + qr = exec(t, conn, "select val1 as a, count(*) from aggr_test group by a order by 2, a") + if got, want := fmt.Sprintf("%v", qr.Rows), `[[VARCHAR("b") INT64(1)] [VARCHAR("d") INT64(1)] [VARCHAR("a") INT64(2)] [VARCHAR("c") INT64(2)] [VARCHAR("e") INT64(2)]]`; got != want { + t.Errorf("select:\n%v want\n%v", got, want) + } } diff --git a/go/vt/vtgate/engine/cached_size.go b/go/vt/vtgate/engine/cached_size.go index e348cfb7a41..a712e6937cf 100644 --- a/go/vt/vtgate/engine/cached_size.go +++ b/go/vt/vtgate/engine/cached_size.go @@ -138,7 +138,9 @@ func (cached *DML) CachedSize(alloc bool) int64 { size += cc.CachedSize(true) } // field Table *vitess.io/vitess/go/vt/vtgate/vindexes.Table - size += cached.Table.CachedSize(true) + for _, table := range cached.Table { + size += table.CachedSize(true) + } // field OwnedVindexQuery string size += int64(len(cached.OwnedVindexQuery)) return size diff --git a/go/vt/vtgate/engine/delete.go b/go/vt/vtgate/engine/delete.go index c2f245fba6c..eb1d0d67761 100644 --- a/go/vt/vtgate/engine/delete.go +++ b/go/vt/vtgate/engine/delete.go @@ -50,24 +50,6 @@ var delName = map[DMLOpcode]string{ ByDestination: "DeleteByDestination", } -// RouteType returns a description of the query routing type used by the primitive -func (del *Delete) RouteType() string { - return delName[del.Opcode] -} - -// GetKeyspaceName specifies the Keyspace that this primitive routes to. -func (del *Delete) GetKeyspaceName() string { - return del.Keyspace.Name -} - -// GetTableName specifies the table that this primitive routes to. -func (del *Delete) GetTableName() string { - if del.Table != nil { - return del.Table.Name.String() - } - return "" -} - // Execute performs a non-streaming exec. func (del *Delete) Execute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, _ bool) (*sqltypes.Result, error) { if del.QueryTimeout != 0 { @@ -178,7 +160,11 @@ func (del *Delete) execDeleteByDestination(vcursor VCursor, bindVars map[string] BindVariables: bindVars, } } - if len(del.Table.Owned) > 0 { + vindexTable, err := del.GetSingleTable() + if err != nil { + return nil, err + } + if len(vindexTable.Owned) > 0 { err = del.deleteVindexEntries(vcursor, bindVars, rss) if err != nil { return nil, err @@ -212,7 +198,11 @@ func (del *Delete) deleteVindexEntries(vcursor VCursor, bindVars map[string]*que if err != nil { return err } - for _, colVindex := range del.Table.Owned { + vindexTable, err := del.GetSingleTable() + if err != nil { + return err + } + for _, colVindex := range vindexTable.Owned { // Fetch the column values. colnum must keep incrementing. fromIds := make([]sqltypes.Value, 0, len(colVindex.Columns)) for range colVindex.Columns { diff --git a/go/vt/vtgate/engine/delete_test.go b/go/vt/vtgate/engine/delete_test.go index 586c78c6f7d..926898e0f39 100644 --- a/go/vt/vtgate/engine/delete_test.go +++ b/go/vt/vtgate/engine/delete_test.go @@ -144,12 +144,14 @@ func TestDeleteOwnedVindex(t *testing.T) { ks := buildTestVSchema().Keyspaces["sharded"] del := &Delete{ DML: DML{ - Opcode: Equal, - Keyspace: ks.Keyspace, - Query: "dummy_delete", - Vindex: ks.Vindexes["hash"].(vindexes.SingleColumn), - Values: []sqltypes.PlanValue{{Value: sqltypes.NewInt64(1)}}, - Table: ks.Tables["t1"], + Opcode: Equal, + Keyspace: ks.Keyspace, + Query: "dummy_delete", + Vindex: ks.Vindexes["hash"].(vindexes.SingleColumn), + Values: []sqltypes.PlanValue{{Value: sqltypes.NewInt64(1)}}, + Table: []*vindexes.Table{ + ks.Tables["t1"], + }, OwnedVindexQuery: "dummy_subquery", KsidVindex: ks.Vindexes["hash"].(vindexes.SingleColumn), }, @@ -230,7 +232,9 @@ func TestDeleteSharded(t *testing.T) { Opcode: Scatter, Keyspace: ks.Keyspace, Query: "dummy_delete", - Table: ks.Tables["t2"], + Table: []*vindexes.Table{ + ks.Tables["t2"], + }, }, } @@ -258,10 +262,12 @@ func TestDeleteScatterOwnedVindex(t *testing.T) { ks := buildTestVSchema().Keyspaces["sharded"] del := &Delete{ DML: DML{ - Opcode: Scatter, - Keyspace: ks.Keyspace, - Query: "dummy_delete", - Table: ks.Tables["t1"], + Opcode: Scatter, + Keyspace: ks.Keyspace, + Query: "dummy_delete", + Table: []*vindexes.Table{ + ks.Tables["t1"], + }, OwnedVindexQuery: "dummy_subquery", KsidVindex: ks.Vindexes["hash"].(vindexes.SingleColumn), }, diff --git a/go/vt/vtgate/engine/dml.go b/go/vt/vtgate/engine/dml.go index 9689074155f..f58f30914b0 100644 --- a/go/vt/vtgate/engine/dml.go +++ b/go/vt/vtgate/engine/dml.go @@ -17,9 +17,13 @@ limitations under the License. package engine import ( + "sort" + "strings" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" querypb "vitess.io/vitess/go/vt/proto/query" + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/srvtopo" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vtgate/vindexes" @@ -50,7 +54,7 @@ type DML struct { KsidVindex vindexes.SingleColumn // Table specifies the table for the update. - Table *vindexes.Table + Table []*vindexes.Table // OwnedVindexQuery is used for updating changes in lookup vindexes. OwnedVindexQuery string @@ -65,6 +69,43 @@ type DML struct { txNeeded } +// RouteType returns a description of the query routing type used by the primitive +func (dml *DML) RouteType() string { + return dml.Opcode.String() +} + +// GetKeyspaceName specifies the Keyspace that this primitive routes to. +func (dml *DML) GetKeyspaceName() string { + return dml.Keyspace.Name +} + +// GetTableName specifies the table that this primitive routes to. +func (dml *DML) GetTableName() string { + if dml.Table != nil { + tableNameMap := map[string]interface{}{} + for _, table := range dml.Table { + tableNameMap[table.Name.String()] = nil + } + + var tableNames []string + for name := range tableNameMap { + tableNames = append(tableNames, name) + } + sort.Strings(tableNames) + + return strings.Join(tableNames, ", ") + } + return "" +} + +// GetSingleTable returns single table used in dml. +func (dml *DML) GetSingleTable() (*vindexes.Table, error) { + if len(dml.Table) > 1 { + return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "unsupported dml on complex table expression") + } + return dml.Table[0], nil +} + // DMLOpcode is a number representing the opcode // for the Update or Delete primitve. type DMLOpcode int diff --git a/go/vt/vtgate/engine/join.go b/go/vt/vtgate/engine/join.go index cbdb8d58151..905bdaa64ab 100644 --- a/go/vt/vtgate/engine/join.go +++ b/go/vt/vtgate/engine/join.go @@ -238,7 +238,7 @@ func (jn *Join) GetKeyspaceName() string { // GetTableName specifies the table that this primitive routes to. func (jn *Join) GetTableName() string { - return jn.Left.GetTableName() + "_" + jn.Right.GetTableName() + return jn.Left.GetTableName() + ", " + jn.Right.GetTableName() } // NeedsTransaction implements the Primitive interface diff --git a/go/vt/vtgate/engine/ordered_aggregate.go b/go/vt/vtgate/engine/ordered_aggregate.go index 9411ee1a24c..47f9aa64dad 100644 --- a/go/vt/vtgate/engine/ordered_aggregate.go +++ b/go/vt/vtgate/engine/ordered_aggregate.go @@ -49,6 +49,9 @@ type OrderedAggregate struct { // the aggregation key. Keys []int + // Keeps track if the keys above were added because of GroupBy or not + FromGroupBy []bool + // TruncateColumnCount specifies the number of columns to return // in the final result. Rest of the columns are truncated // from the result received. If 0, no truncation happens. diff --git a/go/vt/vtgate/engine/primitive.go b/go/vt/vtgate/engine/primitive.go index ab08f72951e..22e75f476d4 100644 --- a/go/vt/vtgate/engine/primitive.go +++ b/go/vt/vtgate/engine/primitive.go @@ -21,6 +21,7 @@ import ( "encoding/json" "sync/atomic" "time" + "vitess.io/vitess/go/vt/vtgate/boost" "golang.org/x/sync/errgroup" @@ -161,11 +162,12 @@ type ( // each node does its part by combining the results of the // sub-nodes. Plan struct { - Type sqlparser.StatementType // The type of query we have - Original string // Original is the original query. - Instructions Primitive // Instructions contains the instructions needed to fulfil the query. - BindVarNeeds *sqlparser.BindVarNeeds // Stores BindVars needed to be provided as part of expression rewriting - Warnings []*querypb.QueryWarning // Warnings that need to be yielded every time this query runs + Type sqlparser.StatementType // The type of query we have + Original string // Original is the original query. + Instructions Primitive // Instructions contains the instructions needed to fulfil the query. + BindVarNeeds *sqlparser.BindVarNeeds // Stores BindVars needed to be provided as part of expression rewriting + Warnings []*querypb.QueryWarning // Warnings that need to be yielded every time this query runs + BoostPlanConfig *boost.PlanConfig ExecCount uint64 // Count of times this plan was executed ExecTime uint64 // Total execution time @@ -249,7 +251,7 @@ func Exists(m Match, p Primitive) bool { return Find(m, p) != nil } -//MarshalJSON serializes the plan into a JSON representation. +// MarshalJSON serializes the plan into a JSON representation. func (p *Plan) MarshalJSON() ([]byte, error) { var instructions *PrimitiveDescription if p.Instructions != nil { diff --git a/go/vt/vtgate/engine/rename_fields.go b/go/vt/vtgate/engine/rename_fields.go index 9983c5036e1..68b84f5155f 100644 --- a/go/vt/vtgate/engine/rename_fields.go +++ b/go/vt/vtgate/engine/rename_fields.go @@ -74,6 +74,9 @@ func (r *RenameFields) Execute(vcursor VCursor, bindVars map[string]*querypb.Bin func (r *RenameFields) renameFields(qr *sqltypes.Result) { for ind, index := range r.Indices { + if index >= len(qr.Fields) { + continue + } colName := r.Cols[ind] qr.Fields[index].Name = colName } @@ -84,7 +87,11 @@ func (r *RenameFields) StreamExecute(vcursor VCursor, bindVars map[string]*query if wantfields { innerCallback := callback callback = func(result *sqltypes.Result) error { - r.renameFields(result) + // Only the first callback will contain the fields. + // This check is to avoid going over the RenameFields indices when no fields are present in the result set. + if len(result.Fields) != 0 { + r.renameFields(result) + } return innerCallback(result) } } diff --git a/go/vt/vtgate/engine/route.go b/go/vt/vtgate/engine/route.go index f3f169bc477..2364944d316 100644 --- a/go/vt/vtgate/engine/route.go +++ b/go/vt/vtgate/engine/route.go @@ -131,6 +131,9 @@ type OrderbyParams struct { WeightStringCol int Desc bool StarColFixedIndex int + + // v3 specific boolean. Used to also add weight strings originating from GroupBys to the Group by clause + FromGroupBy bool } func (obp OrderbyParams) String() string { diff --git a/go/vt/vtgate/engine/update.go b/go/vt/vtgate/engine/update.go index 1bbdbc8d2a8..ece373f806a 100644 --- a/go/vt/vtgate/engine/update.go +++ b/go/vt/vtgate/engine/update.go @@ -62,24 +62,6 @@ var updName = map[DMLOpcode]string{ ByDestination: "UpdateByDestination", } -// RouteType returns a description of the query routing type used by the primitive -func (upd *Update) RouteType() string { - return updName[upd.Opcode] -} - -// GetKeyspaceName specifies the Keyspace that this primitive routes to. -func (upd *Update) GetKeyspaceName() string { - return upd.Keyspace.Name -} - -// GetTableName specifies the table that this primitive routes to. -func (upd *Update) GetTableName() string { - if upd.Table != nil { - return upd.Table.Name.String() - } - return "" -} - // Execute performs a non-streaming exec. func (upd *Update) Execute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) { if upd.QueryTimeout != 0 { @@ -229,7 +211,11 @@ func (upd *Update) updateVindexEntries(vcursor VCursor, bindVars map[string]*que if err != nil { return err } - for _, colVindex := range upd.Table.Owned { + vindexTable, err := upd.GetSingleTable() + if err != nil { + return err + } + for _, colVindex := range vindexTable.Owned { // Update columns only if they're being changed. if updColValues, ok := upd.ChangedVindexValues[colVindex.Name]; ok { offset := updColValues.Offset diff --git a/go/vt/vtgate/engine/update_test.go b/go/vt/vtgate/engine/update_test.go index 979629014c1..a423393d9d7 100644 --- a/go/vt/vtgate/engine/update_test.go +++ b/go/vt/vtgate/engine/update_test.go @@ -196,12 +196,14 @@ func TestUpdateEqualChangedVindex(t *testing.T) { ks := buildTestVSchema().Keyspaces["sharded"] upd := &Update{ DML: DML{ - Opcode: Equal, - Keyspace: ks.Keyspace, - Query: "dummy_update", - Vindex: ks.Vindexes["hash"].(vindexes.SingleColumn), - Values: []sqltypes.PlanValue{{Value: sqltypes.NewInt64(1)}}, - Table: ks.Tables["t1"], + Opcode: Equal, + Keyspace: ks.Keyspace, + Query: "dummy_update", + Vindex: ks.Vindexes["hash"].(vindexes.SingleColumn), + Values: []sqltypes.PlanValue{{Value: sqltypes.NewInt64(1)}}, + Table: []*vindexes.Table{ + ks.Tables["t1"], + }, OwnedVindexQuery: "dummy_subquery", KsidVindex: ks.Vindexes["hash"].(vindexes.SingleColumn), }, @@ -337,10 +339,12 @@ func TestUpdateScatterChangedVindex(t *testing.T) { ks := buildTestVSchema().Keyspaces["sharded"] upd := &Update{ DML: DML{ - Opcode: Scatter, - Keyspace: ks.Keyspace, - Query: "dummy_update", - Table: ks.Tables["t1"], + Opcode: Scatter, + Keyspace: ks.Keyspace, + Query: "dummy_update", + Table: []*vindexes.Table{ + ks.Tables["t1"], + }, OwnedVindexQuery: "dummy_subquery", KsidVindex: ks.Vindexes["hash"].(vindexes.SingleColumn), }, @@ -481,7 +485,9 @@ func TestUpdateInChangedVindex(t *testing.T) { {Value: sqltypes.NewInt64(2)}, }}, }, - Table: ks.Tables["t1"], + Table: []*vindexes.Table{ + ks.Tables["t1"], + }, OwnedVindexQuery: "dummy_subquery", KsidVindex: ks.Vindexes["hash"].(vindexes.SingleColumn), }, diff --git a/go/vt/vtgate/evalengine/arithmetic.go b/go/vt/vtgate/evalengine/arithmetic.go index 3a887d77763..7bc883acdac 100644 --- a/go/vt/vtgate/evalengine/arithmetic.go +++ b/go/vt/vtgate/evalengine/arithmetic.go @@ -243,7 +243,7 @@ func isByteComparable(v sqltypes.Value) bool { return true } switch v.Type() { - case sqltypes.Timestamp, sqltypes.Date, sqltypes.Time, sqltypes.Datetime, sqltypes.Enum, sqltypes.Set, sqltypes.TypeJSON: + case sqltypes.Timestamp, sqltypes.Date, sqltypes.Time, sqltypes.Datetime, sqltypes.Enum, sqltypes.Set, sqltypes.TypeJSON, sqltypes.Bit: return true } return false diff --git a/go/vt/vtgate/evalengine/arithmetic_test.go b/go/vt/vtgate/evalengine/arithmetic_test.go index eb37012252c..5575196baab 100644 --- a/go/vt/vtgate/evalengine/arithmetic_test.go +++ b/go/vt/vtgate/evalengine/arithmetic_test.go @@ -567,6 +567,21 @@ func TestNullsafeCompare(t *testing.T) { v1: TestValue(querypb.Type_DATETIME, "1000-01-01 00:00:00"), v2: TestValue(querypb.Type_BINARY, "2000-01-01 00:00:00"), out: -1, + }, { + // Date/Time types + v1: TestValue(querypb.Type_BIT, "101"), + v2: TestValue(querypb.Type_BIT, "101"), + out: 0, + }, { + // Date/Time types + v1: TestValue(querypb.Type_BIT, "1"), + v2: TestValue(querypb.Type_BIT, "0"), + out: 1, + }, { + // Date/Time types + v1: TestValue(querypb.Type_BIT, "0"), + v2: TestValue(querypb.Type_BIT, "1"), + out: -1, }} for _, tcase := range tcases { got, err := NullsafeCompare(tcase.v1, tcase.v2) diff --git a/go/vt/vtgate/executor.go b/go/vt/vtgate/executor.go index 3f483081175..b63069952d8 100644 --- a/go/vt/vtgate/executor.go +++ b/go/vt/vtgate/executor.go @@ -28,6 +28,7 @@ import ( "strings" "sync" "time" + "vitess.io/vitess/go/vt/vtgate/boost" "vitess.io/vitess/go/acl" "vitess.io/vitess/go/cache" @@ -100,6 +101,8 @@ type Executor struct { vm *VSchemaManager schemaTracker SchemaInfo + + queryFilterConfigs *boost.QueryFilterConfigs } var executorOnce sync.Once @@ -118,18 +121,20 @@ func NewExecutor( streamSize int, cacheCfg *cache.Config, schemaTracker SchemaInfo, + queryFilterConfigs *boost.QueryFilterConfigs, ) *Executor { e := &Executor{ - serv: serv, - cell: cell, - resolver: resolver, - scatterConn: resolver.scatterConn, - txConn: resolver.scatterConn.txConn, - plans: cache.NewDefaultCacheImpl(cacheCfg), - normalize: normalize, - warnShardedOnly: warnOnShardedOnly, - streamSize: streamSize, - schemaTracker: schemaTracker, + serv: serv, + cell: cell, + resolver: resolver, + scatterConn: resolver.scatterConn, + txConn: resolver.scatterConn.txConn, + plans: cache.NewDefaultCacheImpl(cacheCfg), + normalize: normalize, + warnShardedOnly: warnOnShardedOnly, + streamSize: streamSize, + schemaTracker: schemaTracker, + queryFilterConfigs: queryFilterConfigs, } vschemaacl.Init() @@ -163,7 +168,7 @@ func (e *Executor) Execute(ctx context.Context, method string, safeSession *Safe trace.AnnotateSQL(span, sql) defer span.Finish() - logStats := NewLogStats(ctx, method, sql, bindVars) + logStats := NewLogStats(ctx, method, sql, safeSession.GetSessionUUID(), bindVars) stmtType, result, err := e.execute(ctx, safeSession, sql, bindVars, logStats) logStats.Error = err saveSessionStats(safeSession, stmtType, result, err) @@ -175,7 +180,7 @@ func (e *Executor) Execute(ctx context.Context, method string, safeSession *Safe } log.Warningf("%q exceeds warning threshold of max memory rows: %v", piiSafeSQL, *warnMemoryRows) } - + logStats.InTransaction = safeSession.InTransaction() logStats.Send() return result, err } @@ -398,7 +403,7 @@ func (e *Executor) handleCommit(ctx context.Context, safeSession *SafeSession, l return &sqltypes.Result{}, err } -//Commit commits the existing transactions +// Commit commits the existing transactions func (e *Executor) Commit(ctx context.Context, safeSession *SafeSession) error { return e.txConn.Commit(ctx, safeSession) } @@ -1020,7 +1025,7 @@ func (e *Executor) handleOther(ctx context.Context, safeSession *SafeSession, sq // StreamExecute executes a streaming query. func (e *Executor) StreamExecute(ctx context.Context, method string, safeSession *SafeSession, sql string, bindVars map[string]*querypb.BindVariable, target *querypb.Target, callback func(*sqltypes.Result) error) (err error) { - logStats := NewLogStats(ctx, method, sql, bindVars) + logStats := NewLogStats(ctx, method, sql, safeSession.GetSessionUUID(), bindVars) defer logStats.Send() if bindVars == nil { @@ -1184,11 +1189,6 @@ func (e *Executor) ParseDestinationTarget(targetString string) (string, topodata // getPlan computes the plan for the given query. If one is in // the cache, it reuses it. func (e *Executor) getPlan(vcursor *vcursorImpl, sql string, comments sqlparser.MarginComments, bindVars map[string]*querypb.BindVariable, skipQueryPlanCache bool, logStats *LogStats) (*engine.Plan, error) { - if logStats != nil { - logStats.SQL = comments.Leading + sql + comments.Trailing - logStats.BindVariables = bindVars - } - if e.VSchema() == nil { return nil, errors.New("vschema not initialized") } @@ -1206,6 +1206,7 @@ func (e *Executor) getPlan(vcursor *vcursorImpl, sql string, comments sqlparser. } ignoreMaxMemoryRows := sqlparser.IgnoreMaxMaxMemoryRowsDirective(stmt) vcursor.SetIgnoreMaxMemoryRows(ignoreMaxMemoryRows) + var boostPlanConfig = boost.NonBoostedPlanConfig() // Normalize if possible and retry. if (e.normalize && sqlparser.CanNormalize(stmt)) || sqlparser.MustRewriteAST(stmt) { @@ -1217,11 +1218,12 @@ func (e *Executor) getPlan(vcursor *vcursorImpl, sql string, comments sqlparser. statement = result.AST bindVarNeeds = result.BindVarNeeds query = sqlparser.String(statement) + boostPlanConfig = configForBoost(e.queryFilterConfigs, result.Columns, vcursor.vschema.UniqueTables) } if logStats != nil { logStats.SQL = comments.Leading + query + comments.Trailing - logStats.BindVariables = bindVars + logStats.BindVariables = sqltypes.CopyBindVariables(bindVars) } planKey := vcursor.planPrefixKey() + ":" + query @@ -1229,7 +1231,7 @@ func (e *Executor) getPlan(vcursor *vcursorImpl, sql string, comments sqlparser. return plan.(*engine.Plan), nil } - plan, err := planbuilder.BuildFromStmt(query, statement, reservedVars, vcursor, bindVarNeeds, *enableOnlineDDL, *enableDirectDDL) + plan, err := planbuilder.BuildFromStmt(query, statement, reservedVars, vcursor, bindVarNeeds, *enableOnlineDDL, *enableDirectDDL, boostPlanConfig) if err != nil { return nil, err } @@ -1240,9 +1242,42 @@ func (e *Executor) getPlan(vcursor *vcursorImpl, sql string, comments sqlparser. if !skipQueryPlanCache && !sqlparser.SkipQueryPlanCacheDirective(statement) && sqlparser.CachePlan(statement) { e.plans.Set(planKey, plan) } + return plan, nil } +func configForBoost(configs *boost.QueryFilterConfigs, columns boost.Columns, inputMap map[string]*vindexes.Table) *boost.PlanConfig { + if configs == nil || columns == nil { + return boost.NonBoostedPlanConfig() + } + + for tableName, _ := range inputMap { + for _, filterConfig := range configs.BoostConfigs { + if tableName == filterConfig.TableName { + + if keysMatch(columns, filterConfig.Columns) { + return &boost.PlanConfig{ + IsBoosted: true, + BoostColumns: columns, + } + } + } + } + } + + return boost.NonBoostedPlanConfig() +} + +func keysMatch(columns map[string]string, keys []string) bool { + for _, k := range keys { + if _, exists := columns[k]; !exists { + return false + } + } + + return true +} + // skipQueryPlanCache extracts SkipQueryPlanCache from session func skipQueryPlanCache(safeSession *SafeSession) bool { if safeSession == nil || safeSession.Options == nil { @@ -1363,7 +1398,7 @@ func isValidPayloadSize(query string) bool { // Prepare executes a prepare statements. func (e *Executor) Prepare(ctx context.Context, method string, safeSession *SafeSession, sql string, bindVars map[string]*querypb.BindVariable) (fld []*querypb.Field, err error) { - logStats := NewLogStats(ctx, method, sql, bindVars) + logStats := NewLogStats(ctx, method, sql, safeSession.GetSessionUUID(), bindVars) fld, err = e.prepare(ctx, safeSession, sql, bindVars, logStats) logStats.Error = err @@ -1371,6 +1406,7 @@ func (e *Executor) Prepare(ctx context.Context, method string, safeSession *Safe // To avoid spamming the log with no-op rollback records, ignore it if // it was a no-op record (i.e. didn't issue any queries) if !(logStats.StmtType == "ROLLBACK" && logStats.ShardQueries == 0) { + logStats.InTransaction = safeSession.InTransaction() logStats.Send() } return fld, err diff --git a/go/vt/vtgate/executor_dml_test.go b/go/vt/vtgate/executor_dml_test.go index e94abe4d04f..df71773bacb 100644 --- a/go/vt/vtgate/executor_dml_test.go +++ b/go/vt/vtgate/executor_dml_test.go @@ -493,6 +493,315 @@ func TestDeleteScatter(t *testing.T) { } } +func TestUpdateEqualWithWriteOnlyLookupUniqueVindex(t *testing.T) { + res := []*sqltypes.Result{sqltypes.MakeTestResult( + sqltypes.MakeTestFields("id|wo_lu_col|lu_col|t2_lu_vdx", "int64|int64|int64|int64"), + "1|2|1|0", + )} + executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, res) + + _, err := executorExec(executor, "update t2_wo_lookup set lu_col = 5 where wo_lu_col = 2", nil) + require.NoError(t, err) + wantQueries := []*querypb.BoundQuery{ + { + Sql: "select id, wo_lu_col, lu_col, lu_col = 5 from t2_wo_lookup where wo_lu_col = 2 for update", + BindVariables: map[string]*querypb.BindVariable{}, + }, { + Sql: "update t2_wo_lookup set lu_col = 5 where wo_lu_col = 2", + BindVariables: map[string]*querypb.BindVariable{}, + }} + + utils.MustMatch(t, wantQueries, sbc1.Queries) + utils.MustMatch(t, wantQueries, sbc2.Queries) + + bq1 := &querypb.BoundQuery{ + Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id": sqltypes.Uint64BindVariable(1), + "lu_col": sqltypes.Int64BindVariable(1), + }, + } + bq2 := &querypb.BoundQuery{ + Sql: "insert into lu_idx(lu_col, keyspace_id) values (:lu_col_0, :keyspace_id_0)", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id_0": sqltypes.Uint64BindVariable(1), + "lu_col_0": sqltypes.Int64BindVariable(5), + }, + } + lookWant := []*querypb.BoundQuery{bq1, bq2, bq1, bq2, bq1, bq2, bq1, bq2, bq1, bq2, bq1, bq2, bq1, bq2, bq1, bq2} + utils.MustMatch(t, lookWant, sbcLookup.Queries) +} + +func TestUpdateEqualWithMultipleLookupVindex(t *testing.T) { + executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, nil) + + sbcLookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( + sqltypes.MakeTestFields("lu_col|keyspace_id", "int64|varbinary"), + "1|1", + )}) + + sbc1.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( + sqltypes.MakeTestFields("id|wo_lu_col|lu_col|t2_lu_vdx", "int64|int64|int64|int64"), + "1|2|1|0", + )}) + + _, err := executorExec(executor, "update t2_wo_lookup set lu_col = 5 where wo_lu_col = 2 and lu_col = 1", nil) + require.NoError(t, err) + wantQueries := []*querypb.BoundQuery{ + { + Sql: "select id, wo_lu_col, lu_col, lu_col = 5 from t2_wo_lookup where wo_lu_col = 2 and lu_col = 1 for update", + BindVariables: map[string]*querypb.BindVariable{}, + }, { + Sql: "update t2_wo_lookup set lu_col = 5 where wo_lu_col = 2 and lu_col = 1", + BindVariables: map[string]*querypb.BindVariable{}, + }} + + vars, _ := sqltypes.BuildBindVariable([]interface{}{ + sqltypes.NewInt64(1), + }) + lookWant := []*querypb.BoundQuery{{ + Sql: "select lu_col, keyspace_id from lu_idx where lu_col in ::lu_col for update", + BindVariables: map[string]*querypb.BindVariable{ + "lu_col": vars, + }, + }, { + Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id": sqltypes.Uint64BindVariable(1), + "lu_col": sqltypes.Int64BindVariable(1), + }, + }, { + Sql: "insert into lu_idx(lu_col, keyspace_id) values (:lu_col_0, :keyspace_id_0)", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id_0": sqltypes.Uint64BindVariable(1), + "lu_col_0": sqltypes.Int64BindVariable(5), + }, + }} + utils.MustMatch(t, lookWant, sbcLookup.Queries) + utils.MustMatch(t, wantQueries, sbc1.Queries) + assert.Nil(t, sbc2.Queries) +} + +func TestUpdateUseHigherCostVindexIfBackfilling(t *testing.T) { + executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, nil) + + sbcLookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( + sqltypes.MakeTestFields("lu_col|keyspace_id", "int64|varbinary"), + "1|1", + "2|1", + )}) + + sbc1.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( + sqltypes.MakeTestFields("id|wo_lu_col|lu_col|t2_lu_vdx", "int64|int64|int64|int64"), + "1|2|1|0", + "1|2|2|0", + )}) + + _, err := executorExec(executor, "update t2_wo_lookup set lu_col = 5 where wo_lu_col = 2 and lu_col in (1, 2)", nil) + require.NoError(t, err) + wantQueries := []*querypb.BoundQuery{ + { + Sql: "select id, wo_lu_col, lu_col, lu_col = 5 from t2_wo_lookup where wo_lu_col = 2 and lu_col in (1, 2) for update", + BindVariables: map[string]*querypb.BindVariable{}, + }, { + Sql: "update t2_wo_lookup set lu_col = 5 where wo_lu_col = 2 and lu_col in (1, 2)", + BindVariables: map[string]*querypb.BindVariable{}, + }} + + vars, _ := sqltypes.BuildBindVariable([]interface{}{ + sqltypes.NewInt64(1), + sqltypes.NewInt64(2), + }) + lookWant := []*querypb.BoundQuery{{ + Sql: "select lu_col, keyspace_id from lu_idx where lu_col in ::lu_col for update", + BindVariables: map[string]*querypb.BindVariable{ + "lu_col": vars, + }, + }, { + Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id": sqltypes.Uint64BindVariable(1), + "lu_col": sqltypes.Int64BindVariable(1), + }, + }, { + Sql: "insert into lu_idx(lu_col, keyspace_id) values (:lu_col_0, :keyspace_id_0)", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id_0": sqltypes.Uint64BindVariable(1), + "lu_col_0": sqltypes.Int64BindVariable(5), + }, + }, { + Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id": sqltypes.Uint64BindVariable(1), + "lu_col": sqltypes.Int64BindVariable(2), + }, + }, { + Sql: "insert into lu_idx(lu_col, keyspace_id) values (:lu_col_0, :keyspace_id_0)", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id_0": sqltypes.Uint64BindVariable(1), + "lu_col_0": sqltypes.Int64BindVariable(5), + }, + }} + utils.MustMatch(t, lookWant, sbcLookup.Queries) + utils.MustMatch(t, wantQueries, sbc1.Queries) + assert.Nil(t, sbc2.Queries) +} + +func TestDeleteEqualWithWriteOnlyLookupUniqueVindex(t *testing.T) { + res := []*sqltypes.Result{sqltypes.MakeTestResult( + sqltypes.MakeTestFields("id|wo_lu_col|lu_col", "int64|int64|int64"), + "1|1|1", + )} + executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, res) + + _, err := executorExec(executor, "delete from t2_wo_lookup where wo_lu_col = 1", nil) + require.NoError(t, err) + wantQueries := []*querypb.BoundQuery{ + { + Sql: "select id, wo_lu_col, lu_col from t2_wo_lookup where wo_lu_col = 1 for update", + BindVariables: map[string]*querypb.BindVariable{}, + }, { + Sql: "delete from t2_wo_lookup where wo_lu_col = 1", + BindVariables: map[string]*querypb.BindVariable{}, + }} + + bq1 := &querypb.BoundQuery{ + Sql: "delete from wo_lu_idx where wo_lu_col = :wo_lu_col and keyspace_id = :keyspace_id", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, + "wo_lu_col": sqltypes.Int64BindVariable(1), + }, + } + bq2 := &querypb.BoundQuery{ + Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id": sqltypes.Uint64BindVariable(1), + "lu_col": sqltypes.Int64BindVariable(1), + }, + } + lookWant := []*querypb.BoundQuery{bq1, bq2, bq1, bq2, bq1, bq2, bq1, bq2, bq1, bq2, bq1, bq2, bq1, bq2, bq1, bq2} + utils.MustMatch(t, lookWant, sbcLookup.Queries) + utils.MustMatch(t, wantQueries, sbc1.Queries) + utils.MustMatch(t, wantQueries, sbc2.Queries) +} + +func TestDeleteEqualWithMultipleLookupVindex(t *testing.T) { + executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, nil) + + sbcLookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( + sqltypes.MakeTestFields("lu_col|keyspace_id", "int64|varbinary"), + "1|1", + )}) + + sbc1.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( + sqltypes.MakeTestFields("id|wo_lu_col|lu_col", "int64|int64|int64"), + "1|1|1", + )}) + + _, err := executorExec(executor, "delete from t2_wo_lookup where wo_lu_col = 1 and lu_col = 1", nil) + require.NoError(t, err) + wantQueries := []*querypb.BoundQuery{ + { + Sql: "select id, wo_lu_col, lu_col from t2_wo_lookup where wo_lu_col = 1 and lu_col = 1 for update", + BindVariables: map[string]*querypb.BindVariable{}, + }, { + Sql: "delete from t2_wo_lookup where wo_lu_col = 1 and lu_col = 1", + BindVariables: map[string]*querypb.BindVariable{}, + }} + + vars, _ := sqltypes.BuildBindVariable([]interface{}{ + sqltypes.NewInt64(1), + }) + lookWant := []*querypb.BoundQuery{{ + Sql: "select lu_col, keyspace_id from lu_idx where lu_col in ::lu_col for update", + BindVariables: map[string]*querypb.BindVariable{ + "lu_col": vars, + }, + }, { + Sql: "delete from wo_lu_idx where wo_lu_col = :wo_lu_col and keyspace_id = :keyspace_id", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, + "wo_lu_col": sqltypes.Int64BindVariable(1), + }, + }, { + Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id": sqltypes.Uint64BindVariable(1), + "lu_col": {Type: querypb.Type_INT64, Value: []byte("1")}, + }, + }} + utils.MustMatch(t, lookWant, sbcLookup.Queries) + + utils.MustMatch(t, wantQueries, sbc1.Queries) + assert.Nil(t, sbc2.Queries) +} + +func TestDeleteUseHigherCostVindexIfBackfilling(t *testing.T) { + executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, nil) + + sbcLookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( + sqltypes.MakeTestFields("lu_col|keyspace_id", "int64|varbinary"), + "1|1", + "2|1", + )}) + + sbc1.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( + sqltypes.MakeTestFields("id|wo_lu_col|lu_col", "int64|int64|int64"), + "1|1|1", + "1|1|2", + )}) + + _, err := executorExec(executor, "delete from t2_wo_lookup where wo_lu_col = 1 and lu_col in (1, 2)", nil) + require.NoError(t, err) + wantQueries := []*querypb.BoundQuery{ + { + Sql: "select id, wo_lu_col, lu_col from t2_wo_lookup where wo_lu_col = 1 and lu_col in (1, 2) for update", + BindVariables: map[string]*querypb.BindVariable{}, + }, { + Sql: "delete from t2_wo_lookup where wo_lu_col = 1 and lu_col in (1, 2)", + BindVariables: map[string]*querypb.BindVariable{}, + }} + + vars, _ := sqltypes.BuildBindVariable([]interface{}{ + sqltypes.NewInt64(1), + sqltypes.NewInt64(2), + }) + lookWant := []*querypb.BoundQuery{{ + Sql: "select lu_col, keyspace_id from lu_idx where lu_col in ::lu_col for update", + BindVariables: map[string]*querypb.BindVariable{ + "lu_col": vars, + }, + }, { + Sql: "delete from wo_lu_idx where wo_lu_col = :wo_lu_col and keyspace_id = :keyspace_id", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, + "wo_lu_col": sqltypes.Int64BindVariable(1), + }, + }, { + Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id": sqltypes.Uint64BindVariable(1), + "lu_col": sqltypes.Int64BindVariable(1), + }, + }, { + Sql: "delete from wo_lu_idx where wo_lu_col = :wo_lu_col and keyspace_id = :keyspace_id", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, + "wo_lu_col": sqltypes.Int64BindVariable(1), + }, + }, { + Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", + BindVariables: map[string]*querypb.BindVariable{ + "keyspace_id": sqltypes.Uint64BindVariable(1), + "lu_col": sqltypes.Int64BindVariable(2), + }, + }} + utils.MustMatch(t, lookWant, sbcLookup.Queries) + + utils.MustMatch(t, wantQueries, sbc1.Queries) + assert.Nil(t, sbc2.Queries) +} + func TestDeleteByDestination(t *testing.T) { executor, sbc1, sbc2, _ := createLegacyExecutorEnv() // This query is not supported in v3, so we know for sure is taking the DeleteByDestination route diff --git a/go/vt/vtgate/executor_framework_test.go b/go/vt/vtgate/executor_framework_test.go index a3c4100d998..3d7e22cbee5 100644 --- a/go/vt/vtgate/executor_framework_test.go +++ b/go/vt/vtgate/executor_framework_test.go @@ -109,7 +109,26 @@ var executorVSchema = ` "from": "unq_col", "to": "keyspace_id" }, - "owner": "t1" + "owner": "t1" + }, + "t2_wo_lu_vdx": { + "type": "lookup_unique", + "params": { + "table": "TestUnsharded.wo_lu_idx", + "from": "wo_lu_col", + "to": "keyspace_id", + "write_only": "true" + }, + "owner": "t2_wo_lookup" + }, + "t2_lu_vdx": { + "type": "lookup_hash_unique", + "params": { + "table": "TestUnsharded.lu_idx", + "from": "lu_col", + "to": "keyspace_id" + }, + "owner": "t2_wo_lookup" } }, "tables": { @@ -266,7 +285,23 @@ var executorVSchema = ` "name": "hash_index" } ] - } + }, + "t2_wo_lookup": { + "column_vindexes": [ + { + "column": "id", + "name": "hash_index" + }, + { + "column": "wo_lu_col", + "name": "t2_wo_lu_vdx" + }, + { + "column": "lu_col", + "name": "t2_lu_vdx" + } + ] + } } } ` @@ -298,6 +333,8 @@ var unshardedVSchema = ` "sequence": "user_seq" } }, + "wo_lu_idx": {}, + "lu_idx": {}, "simple": {} } } @@ -457,6 +494,31 @@ func createCustomExecutor(vschema string) (executor *Executor, sbc1, sbc2, sbclo return executor, sbc1, sbc2, sbclookup } +func createCustomExecutorSetValues(vschema string, values []*sqltypes.Result) (executor *Executor, sbc1, sbc2, sbclookup *sandboxconn.SandboxConn) { + cell := "aa" + hc := discovery.NewFakeLegacyHealthCheck() + s := createSandbox("TestExecutor") + s.VSchema = vschema + serv := newSandboxForCells([]string{cell}) + resolver := newTestLegacyResolver(hc, serv, cell) + shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} + sbcs := []*sandboxconn.SandboxConn{} + for _, shard := range shards { + sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_MASTER, true, 1, nil) + if values != nil { + sbc.SetResults(values) + } + sbcs = append(sbcs, sbc) + } + + createSandbox(KsTestUnsharded) + sbclookup = hc.AddTestTablet(cell, "0", 1, KsTestUnsharded, "0", topodatapb.TabletType_MASTER, true, 1, nil) + getSandbox(KsTestUnsharded).VSchema = unshardedVSchema + + executor = NewExecutor(context.Background(), serv, cell, resolver, false, false, testBufferSize, cache.DefaultConfig, nil) + return executor, sbcs[0], sbcs[1], sbclookup +} + func executorExec(executor *Executor, sql string, bv map[string]*querypb.BindVariable) (*sqltypes.Result, error) { return executor.Execute( context.Background(), diff --git a/go/vt/vtgate/executor_select_test.go b/go/vt/vtgate/executor_select_test.go index 371df7c2acb..db07f101870 100644 --- a/go/vt/vtgate/executor_select_test.go +++ b/go/vt/vtgate/executor_select_test.go @@ -1569,7 +1569,7 @@ func TestSelectScatterAggregate(t *testing.T) { require.NoError(t, err) wantQueries := []*querypb.BoundQuery{{ - Sql: "select col, sum(foo), weight_string(col) from `user` group by col order by col asc", + Sql: "select col, sum(foo), weight_string(col) from `user` group by col, weight_string(col) order by col asc", BindVariables: map[string]*querypb.BindVariable{}, }} for _, conn := range conns { @@ -1628,7 +1628,7 @@ func TestStreamSelectScatterAggregate(t *testing.T) { require.NoError(t, err) wantQueries := []*querypb.BoundQuery{{ - Sql: "select col, sum(foo), weight_string(col) from `user` group by col order by col asc", + Sql: "select col, sum(foo), weight_string(col) from `user` group by col, weight_string(col) order by col asc", BindVariables: map[string]*querypb.BindVariable{}, }} for _, conn := range conns { diff --git a/go/vt/vtgate/executor_test.go b/go/vt/vtgate/executor_test.go index 44c6de5124f..f2ab50f4e64 100644 --- a/go/vt/vtgate/executor_test.go +++ b/go/vt/vtgate/executor_test.go @@ -119,7 +119,7 @@ func TestExecutorMaxMemoryRowsExceeded(t *testing.T) { func TestLegacyExecutorTransactionsNoAutoCommit(t *testing.T) { executor, _, _, sbclookup := createLegacyExecutorEnv() - session := NewSafeSession(&vtgatepb.Session{TargetString: "@master"}) + session := NewSafeSession(&vtgatepb.Session{TargetString: "@master", SessionUUID: "suuid"}) logChan := QueryLogger.Subscribe("Test") defer QueryLogger.Unsubscribe(logChan) @@ -127,23 +127,27 @@ func TestLegacyExecutorTransactionsNoAutoCommit(t *testing.T) { // begin. _, err := executor.Execute(ctx, "TestExecute", session, "begin", nil) require.NoError(t, err) - wantSession := &vtgatepb.Session{InTransaction: true, TargetString: "@master"} + wantSession := &vtgatepb.Session{InTransaction: true, TargetString: "@master", SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session") assert.EqualValues(t, 0, sbclookup.CommitCount.Get(), "commit count") logStats := testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) assert.EqualValues(t, 0, logStats.CommitTime, "logstats: expected zero CommitTime") + assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") + assert.EqualValues(t, true, logStats.InTransaction, "logstats: expected InTransaction to be true after BEGIN") // commit. _, err = executor.Execute(ctx, "TestExecute", session, "select id from main1", nil) require.NoError(t, err) logStats = testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) assert.EqualValues(t, 0, logStats.CommitTime, "logstats: expected zero CommitTime") + assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") + assert.EqualValues(t, true, logStats.InTransaction, "logstats: expected InTransaction to be true") _, err = executor.Execute(context.Background(), "TestExecute", session, "commit", nil) if err != nil { t.Fatal(err) } - wantSession = &vtgatepb.Session{TargetString: "@master"} + wantSession = &vtgatepb.Session{TargetString: "@master", SessionUUID: "suuid"} if !proto.Equal(session.Session, wantSession) { t.Errorf("begin: %v, want %v", session.Session, wantSession) } @@ -154,6 +158,8 @@ func TestLegacyExecutorTransactionsNoAutoCommit(t *testing.T) { if logStats.CommitTime == 0 { t.Errorf("logstats: expected non-zero CommitTime") } + assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") + assert.EqualValues(t, false, logStats.InTransaction, "logstats: expected InTransaction to be false after COMMIT") // rollback. _, err = executor.Execute(ctx, "TestExecute", session, "begin", nil) @@ -162,7 +168,7 @@ func TestLegacyExecutorTransactionsNoAutoCommit(t *testing.T) { require.NoError(t, err) _, err = executor.Execute(ctx, "TestExecute", session, "rollback", nil) require.NoError(t, err) - wantSession = &vtgatepb.Session{TargetString: "@master"} + wantSession = &vtgatepb.Session{TargetString: "@master", SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session") assert.EqualValues(t, 1, sbclookup.RollbackCount.Get(), "rollback count") _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) @@ -171,6 +177,8 @@ func TestLegacyExecutorTransactionsNoAutoCommit(t *testing.T) { if logStats.CommitTime == 0 { t.Errorf("logstats: expected non-zero CommitTime") } + assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") + assert.EqualValues(t, false, logStats.InTransaction, "logstats: expected InTransaction to be false after ROLLBACK") // CloseSession doesn't log anything err = executor.CloseSession(ctx, session) @@ -181,20 +189,20 @@ func TestLegacyExecutorTransactionsNoAutoCommit(t *testing.T) { } // Prevent transactions on non-master. - session = NewSafeSession(&vtgatepb.Session{TargetString: "@replica", InTransaction: true}) + session = NewSafeSession(&vtgatepb.Session{TargetString: "@replica", InTransaction: true, SessionUUID: "suuid"}) _, err = executor.Execute(ctx, "TestExecute", session, "select id from main1", nil) require.Error(t, err) want := "transaction is supported only for master tablet type, current type: REPLICA" require.Contains(t, err.Error(), want) // Prevent begin on non-master. - session = NewSafeSession(&vtgatepb.Session{TargetString: "@replica"}) + session = NewSafeSession(&vtgatepb.Session{TargetString: "@replica", SessionUUID: "suuid"}) _, err = executor.Execute(ctx, "TestExecute", session, "begin", nil) require.Error(t, err) require.Contains(t, err.Error(), want) // Prevent use of non-master if in_transaction is on. - session = NewSafeSession(&vtgatepb.Session{TargetString: "@master", InTransaction: true}) + session = NewSafeSession(&vtgatepb.Session{TargetString: "@master", InTransaction: true, SessionUUID: "suuid"}) _, err = executor.Execute(ctx, "TestExecute", session, "use @replica", nil) require.EqualError(t, err, `can't execute the given command because you have an active transaction`) } @@ -220,7 +228,7 @@ func TestDirectTargetRewrites(t *testing.T) { func TestExecutorTransactionsAutoCommit(t *testing.T) { executor, _, _, sbclookup := createLegacyExecutorEnv() - session := NewSafeSession(&vtgatepb.Session{TargetString: "@master", Autocommit: true}) + session := NewSafeSession(&vtgatepb.Session{TargetString: "@master", Autocommit: true, SessionUUID: "suuid"}) logChan := QueryLogger.Subscribe("Test") defer QueryLogger.Unsubscribe(logChan) @@ -228,26 +236,29 @@ func TestExecutorTransactionsAutoCommit(t *testing.T) { // begin. _, err := executor.Execute(ctx, "TestExecute", session, "begin", nil) require.NoError(t, err) - wantSession := &vtgatepb.Session{InTransaction: true, TargetString: "@master", Autocommit: true} + wantSession := &vtgatepb.Session{InTransaction: true, TargetString: "@master", Autocommit: true, SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session") if commitCount := sbclookup.CommitCount.Get(); commitCount != 0 { t.Errorf("want 0, got %d", commitCount) } - _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) + logStats := testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) + assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") // commit. _, err = executor.Execute(ctx, "TestExecute", session, "select id from main1", nil) require.NoError(t, err) _, err = executor.Execute(ctx, "TestExecute", session, "commit", nil) require.NoError(t, err) - wantSession = &vtgatepb.Session{TargetString: "@master", Autocommit: true} + wantSession = &vtgatepb.Session{TargetString: "@master", Autocommit: true, SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session") assert.EqualValues(t, 1, sbclookup.CommitCount.Get()) - logStats := testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) + logStats = testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) assert.EqualValues(t, 0, logStats.CommitTime) + assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") logStats = testQueryLog(t, logChan, "TestExecute", "COMMIT", "commit", 1) assert.NotEqual(t, 0, logStats.CommitTime) + assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") // rollback. _, err = executor.Execute(ctx, "TestExecute", session, "begin", nil) @@ -256,11 +267,15 @@ func TestExecutorTransactionsAutoCommit(t *testing.T) { require.NoError(t, err) _, err = executor.Execute(ctx, "TestExecute", session, "rollback", nil) require.NoError(t, err) - wantSession = &vtgatepb.Session{TargetString: "@master", Autocommit: true} + wantSession = &vtgatepb.Session{TargetString: "@master", Autocommit: true, SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session") if rollbackCount := sbclookup.RollbackCount.Get(); rollbackCount != 1 { t.Errorf("want 1, got %d", rollbackCount) } + _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) + _ = testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) + logStats = testQueryLog(t, logChan, "TestExecute", "ROLLBACK", "rollback", 1) + assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") } func TestExecutorDeleteMetadata(t *testing.T) { @@ -297,7 +312,7 @@ func TestExecutorDeleteMetadata(t *testing.T) { func TestExecutorAutocommit(t *testing.T) { executor, _, _, sbclookup := createLegacyExecutorEnv() - session := NewSafeSession(&vtgatepb.Session{TargetString: "@master"}) + session := NewSafeSession(&vtgatepb.Session{TargetString: "@master", SessionUUID: "suuid"}) logChan := QueryLogger.Subscribe("Test") defer QueryLogger.Unsubscribe(logChan) @@ -306,7 +321,7 @@ func TestExecutorAutocommit(t *testing.T) { startCount := sbclookup.CommitCount.Get() _, err := executor.Execute(ctx, "TestExecute", session, "select id from main1", nil) require.NoError(t, err) - wantSession := &vtgatepb.Session{TargetString: "@master", InTransaction: true, FoundRows: 1, RowCount: -1} + wantSession := &vtgatepb.Session{TargetString: "@master", InTransaction: true, FoundRows: 1, RowCount: -1, SessionUUID: "suuid"} testSession := proto.Clone(session.Session).(*vtgatepb.Session) testSession.ShardSessions = nil utils.MustMatch(t, wantSession, testSession, "session does not match for autocommit=0") @@ -318,11 +333,15 @@ func TestExecutorAutocommit(t *testing.T) { if logStats.RowsReturned == 0 { t.Errorf("logstats: expected non-zero RowsReturned") } + assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") + assert.EqualValues(t, true, logStats.InTransaction, "logstats: expected InTransaction to be true in autocommit=0") // autocommit = 1 _, err = executor.Execute(ctx, "TestExecute", session, "set autocommit=1", nil) require.NoError(t, err) - _ = testQueryLog(t, logChan, "TestExecute", "SET", "set session autocommit = 1", 0) + logStats = testQueryLog(t, logChan, "TestExecute", "SET", "set session autocommit = 1", 0) + assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") + assert.EqualValues(t, false, logStats.InTransaction, "logstats: expected InTransaction to be false in autocommit=1") // Setting autocommit=1 commits existing transaction. if got, want := sbclookup.CommitCount.Get(), startCount+1; got != want { @@ -331,29 +350,33 @@ func TestExecutorAutocommit(t *testing.T) { _, err = executor.Execute(ctx, "TestExecute", session, "update main1 set id=1", nil) require.NoError(t, err) - wantSession = &vtgatepb.Session{Autocommit: true, TargetString: "@master", FoundRows: 0, RowCount: 1} + wantSession = &vtgatepb.Session{Autocommit: true, TargetString: "@master", FoundRows: 0, RowCount: 1, SessionUUID: "suuid"} utils.MustMatch(t, wantSession, session.Session, "session does not match for autocommit=1") logStats = testQueryLog(t, logChan, "TestExecute", "UPDATE", "update main1 set id=1", 1) assert.NotEqual(t, time.Duration(0), logStats.CommitTime, "logstats: expected non-zero CommitTime") assert.NotEqual(t, uint64(0), logStats.RowsAffected, "logstats: expected non-zero RowsAffected") + assert.EqualValues(t, "suuid", logStats.SessionUUID, "logstats: expected non-empty SessionUUID") + assert.EqualValues(t, false, logStats.InTransaction, "logstats: expected InTransaction to be false in autocommit=1") // autocommit = 1, "begin" session.ResetTx() startCount = sbclookup.CommitCount.Get() _, err = executor.Execute(ctx, "TestExecute", session, "begin", nil) require.NoError(t, err) - _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) + logStats = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) + assert.EqualValues(t, true, logStats.InTransaction, "logstats: expected InTransaction to be true after BEGIN") _, err = executor.Execute(ctx, "TestExecute", session, "update main1 set id=1", nil) require.NoError(t, err) - wantSession = &vtgatepb.Session{InTransaction: true, Autocommit: true, TargetString: "@master", FoundRows: 0, RowCount: 1} + wantSession = &vtgatepb.Session{InTransaction: true, Autocommit: true, TargetString: "@master", FoundRows: 0, RowCount: 1, SessionUUID: "suuid"} testSession = proto.Clone(session.Session).(*vtgatepb.Session) testSession.ShardSessions = nil utils.MustMatch(t, wantSession, testSession, "session does not match for autocommit=1") if got, want := sbclookup.CommitCount.Get(), startCount; got != want { t.Errorf("Commit count: %d, want %d", got, want) } + assert.EqualValues(t, true, logStats.InTransaction, "logstats: expected InTransaction to be true") logStats = testQueryLog(t, logChan, "TestExecute", "UPDATE", "update main1 set id=1", 1) if logStats.CommitTime != 0 { @@ -362,30 +385,38 @@ func TestExecutorAutocommit(t *testing.T) { if logStats.RowsAffected == 0 { t.Errorf("logstats: expected non-zero RowsAffected") } + assert.EqualValues(t, true, logStats.InTransaction, "logstats: expected InTransaction to be true") _, err = executor.Execute(ctx, "TestExecute", session, "commit", nil) require.NoError(t, err) - wantSession = &vtgatepb.Session{Autocommit: true, TargetString: "@master"} + wantSession = &vtgatepb.Session{Autocommit: true, TargetString: "@master", SessionUUID: "suuid"} if !proto.Equal(session.Session, wantSession) { t.Errorf("autocommit=1: %v, want %v", session.Session, wantSession) } if got, want := sbclookup.CommitCount.Get(), startCount+1; got != want { t.Errorf("Commit count: %d, want %d", got, want) } - _ = testQueryLog(t, logChan, "TestExecute", "COMMIT", "commit", 1) + logStats = testQueryLog(t, logChan, "TestExecute", "COMMIT", "commit", 1) + assert.EqualValues(t, false, logStats.InTransaction, "logstats: expected InTransaction to be false after COMMIT") // transition autocommit from 0 to 1 in the middle of a transaction. startCount = sbclookup.CommitCount.Get() session = NewSafeSession(&vtgatepb.Session{TargetString: "@master"}) _, err = executor.Execute(ctx, "TestExecute", session, "begin", nil) require.NoError(t, err) + logStats = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) + assert.EqualValues(t, true, logStats.InTransaction, "logstats: expected InTransaction to be true after BEGIN") _, err = executor.Execute(ctx, "TestExecute", session, "update main1 set id=1", nil) require.NoError(t, err) + logStats = testQueryLog(t, logChan, "TestExecute", "UPDATE", "update main1 set id=1", 1) + assert.EqualValues(t, true, logStats.InTransaction, "logstats: expected InTransaction to be true") if got, want := sbclookup.CommitCount.Get(), startCount; got != want { t.Errorf("Commit count: %d, want %d", got, want) } _, err = executor.Execute(ctx, "TestExecute", session, "set autocommit=1", nil) require.NoError(t, err) + logStats = testQueryLog(t, logChan, "TestExecute", "SET", "set session autocommit = 1", 0) + assert.EqualValues(t, false, logStats.InTransaction, "logstats: expected InTransaction to be false after set session autocommit=1") wantSession = &vtgatepb.Session{Autocommit: true, TargetString: "@master"} if !proto.Equal(session.Session, wantSession) { t.Errorf("autocommit=1: %v, want %v", session.Session, wantSession) @@ -747,6 +778,8 @@ func TestExecutorShow(t *testing.T) { buildVarCharRow("TestExecutor", "name_lastname_keyspace_id_map", "lookup", "from=name,lastname; table=name_lastname_keyspace_id_map; to=keyspace_id", "user2"), buildVarCharRow("TestExecutor", "name_user_map", "lookup_hash", "from=name; table=name_user_map; to=user_id", "user"), buildVarCharRow("TestExecutor", "t1_lkp_vdx", "consistent_lookup_unique", "from=unq_col; table=t1_lkp_idx; to=keyspace_id", "t1"), + buildVarCharRow("TestExecutor", "t2_lu_vdx", "lookup_hash_unique", "from=lu_col; table=TestUnsharded.lu_idx; to=keyspace_id", "t2_wo_lookup"), + buildVarCharRow("TestExecutor", "t2_wo_lu_vdx", "lookup_unique", "from=wo_lu_col; table=TestUnsharded.wo_lu_idx; to=keyspace_id; write_only=true", "t2_wo_lookup"), }, } utils.MustMatch(t, wantqr, qr, query) @@ -877,6 +910,7 @@ func TestExecutorShow(t *testing.T) { Rows: [][]sqltypes.Value{ buildVarCharRow("dual"), buildVarCharRow("ins_lookup"), + buildVarCharRow("lu_idx"), buildVarCharRow("main1"), buildVarCharRow("music_user_map"), buildVarCharRow("name_lastname_keyspace_id_map"), @@ -884,6 +918,7 @@ func TestExecutorShow(t *testing.T) { buildVarCharRow("simple"), buildVarCharRow("user_msgs"), buildVarCharRow("user_seq"), + buildVarCharRow("wo_lu_idx"), }, } utils.MustMatch(t, wantqr, qr, query) @@ -1336,12 +1371,12 @@ func TestExecutorAddDropVschemaTableDDL(t *testing.T) { stmt := "alter vschema add table test_table" _, err := executor.Execute(ctx, "TestExecute", session, stmt, nil) require.NoError(t, err) - _ = waitForVschemaTables(t, ks, append(vschemaTables, "test_table"), executor) + _ = waitForVschemaTables(t, ks, append([]string{"test_table"}, vschemaTables...), executor) stmt = "alter vschema add table test_table2" _, err = executor.Execute(ctx, "TestExecute", session, stmt, nil) require.NoError(t, err) - _ = waitForVschemaTables(t, ks, append(vschemaTables, []string{"test_table", "test_table2"}...), executor) + _ = waitForVschemaTables(t, ks, append([]string{"test_table", "test_table2"}, vschemaTables...), executor) // Should fail adding a table on a sharded keyspace session = NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}) @@ -1499,7 +1534,7 @@ func assertCacheContains(t *testing.T, c cache.Cache, want []string) { } func getPlanCached(t *testing.T, e *Executor, vcursor *vcursorImpl, sql string, comments sqlparser.MarginComments, bindVars map[string]*querypb.BindVariable, skipQueryPlanCache bool) (*engine.Plan, *LogStats) { - logStats := NewLogStats(ctx, "Test", "", nil) + logStats := NewLogStats(ctx, "Test", "", "", nil) plan, err := e.getPlan(vcursor, sql, comments, bindVars, skipQueryPlanCache, logStats) require.NoError(t, err) diff --git a/go/vt/vtgate/executor_vschema_ddl_test.go b/go/vt/vtgate/executor_vschema_ddl_test.go index 12a7c91c7c0..46184ef5fd8 100644 --- a/go/vt/vtgate/executor_vschema_ddl_test.go +++ b/go/vt/vtgate/executor_vschema_ddl_test.go @@ -293,12 +293,12 @@ func TestPlanExecutorAddDropVschemaTableDDL(t *testing.T) { stmt := "alter vschema add table test_table" _, err := executor.Execute(context.Background(), "TestExecute", session, stmt, nil) require.NoError(t, err) - _ = waitForVschemaTables(t, ks, append(vschemaTables, "test_table"), executor) + _ = waitForVschemaTables(t, ks, append([]string{"test_table"}, vschemaTables...), executor) stmt = "alter vschema add table test_table2" _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) require.NoError(t, err) - _ = waitForVschemaTables(t, ks, append(vschemaTables, []string{"test_table", "test_table2"}...), executor) + _ = waitForVschemaTables(t, ks, append([]string{"test_table", "test_table2"}, vschemaTables...), executor) // Should fail adding a table on a sharded keyspace session = NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}) diff --git a/go/vt/vtgate/grpcvtgateservice/server.go b/go/vt/vtgate/grpcvtgateservice/server.go index a439fa0aae9..d4b17a6b1a5 100644 --- a/go/vt/vtgate/grpcvtgateservice/server.go +++ b/go/vt/vtgate/grpcvtgateservice/server.go @@ -228,8 +228,15 @@ func (vtg *VTGate) ResolveTransaction(ctx context.Context, request *vtgatepb.Res func (vtg *VTGate) VStream(request *vtgatepb.VStreamRequest, stream vtgateservicepb.Vitess_VStreamServer) (err error) { defer vtg.server.HandlePanic(&err) ctx := withCallerIDContext(stream.Context(), request.CallerId) + + // For backward compatibility. + // The mysql query equivalent has logic to use topodatapb.TabletType_MASTER if tablet_type is not set. + tabletType := request.TabletType + if tabletType == topodatapb.TabletType_UNKNOWN { + tabletType = topodatapb.TabletType_MASTER + } vtgErr := vtg.server.VStream(ctx, - request.TabletType, + tabletType, request.Vgtid, request.Filter, request.Flags, diff --git a/go/vt/vtgate/logstats.go b/go/vt/vtgate/logstats.go index aeac6fe84c2..9b8499931ae 100644 --- a/go/vt/vtgate/logstats.go +++ b/go/vt/vtgate/logstats.go @@ -54,15 +54,18 @@ type LogStats struct { ExecuteTime time.Duration CommitTime time.Duration Error error + InTransaction bool + SessionUUID string } // NewLogStats constructs a new LogStats with supplied Method and ctx // field values, and the StartTime field set to the present time. -func NewLogStats(ctx context.Context, methodName, sql string, bindVars map[string]*querypb.BindVariable) *LogStats { +func NewLogStats(ctx context.Context, methodName, sql, sessionUUID string, bindVars map[string]*querypb.BindVariable) *LogStats { return &LogStats{ Ctx: ctx, Method: methodName, SQL: sql, + SessionUUID: sessionUUID, BindVariables: bindVars, StartTime: time.Now(), } @@ -154,9 +157,9 @@ func (stats *LogStats) Logf(w io.Writer, params url.Values) error { var fmtString string switch *streamlog.QueryLogFormat { case streamlog.QueryLogFormatText: - fmtString = "%v\t%v\t%v\t'%v'\t'%v'\t%v\t%v\t%.6f\t%.6f\t%.6f\t%.6f\t%v\t%q\t%v\t%v\t%v\t%q\t%q\t%q\t%q\t\n" + fmtString = "%v\t%v\t%v\t'%v'\t'%v'\t%v\t%v\t%.6f\t%.6f\t%.6f\t%.6f\t%v\t%q\t%v\t%v\t%v\t%q\t%q\t%q\t%q\t%t\t%q\t\n" case streamlog.QueryLogFormatJSON: - fmtString = "{\"Method\": %q, \"RemoteAddr\": %q, \"Username\": %q, \"ImmediateCaller\": %q, \"Effective Caller\": %q, \"Start\": \"%v\", \"End\": \"%v\", \"TotalTime\": %.6f, \"PlanTime\": %v, \"ExecuteTime\": %v, \"CommitTime\": %v, \"StmtType\": %q, \"SQL\": %q, \"BindVars\": %v, \"ShardQueries\": %v, \"RowsAffected\": %v, \"Error\": %q, \"Keyspace\": %q, \"Table\": %q, \"TabletType\": %q}\n" + fmtString = "{\"Method\": %q, \"RemoteAddr\": %q, \"Username\": %q, \"ImmediateCaller\": %q, \"Effective Caller\": %q, \"Start\": \"%v\", \"End\": \"%v\", \"TotalTime\": %.6f, \"PlanTime\": %v, \"ExecuteTime\": %v, \"CommitTime\": %v, \"StmtType\": %q, \"SQL\": %q, \"BindVars\": %v, \"ShardQueries\": %v, \"RowsAffected\": %v, \"Error\": %q, \"Keyspace\": %q, \"Table\": %q, \"TabletType\": %q, \"InTransaction\": %t, \"SessionUUID\": %q}\n" } _, err := fmt.Fprintf( @@ -182,6 +185,8 @@ func (stats *LogStats) Logf(w io.Writer, params url.Values) error { stats.Keyspace, stats.Table, stats.TabletType, + stats.InTransaction, + stats.SessionUUID, ) return err } diff --git a/go/vt/vtgate/logstats_test.go b/go/vt/vtgate/logstats_test.go index 0aa77d7c075..d578aacafa9 100644 --- a/go/vt/vtgate/logstats_test.go +++ b/go/vt/vtgate/logstats_test.go @@ -41,7 +41,7 @@ func testFormat(stats *LogStats, params url.Values) string { } func TestLogStatsFormat(t *testing.T) { - logStats := NewLogStats(context.Background(), "test", "sql1", map[string]*querypb.BindVariable{"intVal": sqltypes.Int64BindVariable(1)}) + logStats := NewLogStats(context.Background(), "test", "sql1", "suuid", map[string]*querypb.BindVariable{"intVal": sqltypes.Int64BindVariable(1)}) logStats.StartTime = time.Date(2017, time.January, 1, 1, 2, 3, 0, time.UTC) logStats.EndTime = time.Date(2017, time.January, 1, 1, 2, 4, 1234, time.UTC) logStats.Keyspace = "ks" @@ -52,7 +52,7 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.RedactDebugUIQueries = false *streamlog.QueryLogFormat = "text" got := testFormat(logStats, url.Values(params)) - want := "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1\"\tmap[intVal:type:INT64 value:\"1\"]\t0\t0\t\"\"\t\"ks\"\t\"table\"\t\"MASTER\"\t\n" + want := "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1\"\tmap[intVal:type:INT64 value:\"1\"]\t0\t0\t\"\"\t\"ks\"\t\"table\"\t\"MASTER\"\tfalse\t\"suuid\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) } @@ -60,7 +60,7 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.RedactDebugUIQueries = true *streamlog.QueryLogFormat = "text" got = testFormat(logStats, url.Values(params)) - want = "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1\"\t\"[REDACTED]\"\t0\t0\t\"\"\t\"ks\"\t\"table\"\t\"MASTER\"\t\n" + want = "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1\"\t\"[REDACTED]\"\t0\t0\t\"\"\t\"ks\"\t\"table\"\t\"MASTER\"\tfalse\t\"suuid\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) } @@ -77,7 +77,7 @@ func TestLogStatsFormat(t *testing.T) { if err != nil { t.Errorf("logstats format: error marshaling json: %v -- got:\n%v", err, got) } - want = "{\n \"BindVars\": {\n \"intVal\": {\n \"type\": \"INT64\",\n \"value\": 1\n }\n },\n \"CommitTime\": 0,\n \"Effective Caller\": \"\",\n \"End\": \"2017-01-01 01:02:04.000001\",\n \"Error\": \"\",\n \"ExecuteTime\": 0,\n \"ImmediateCaller\": \"\",\n \"Keyspace\": \"ks\",\n \"Method\": \"test\",\n \"PlanTime\": 0,\n \"RemoteAddr\": \"\",\n \"RowsAffected\": 0,\n \"SQL\": \"sql1\",\n \"ShardQueries\": 0,\n \"Start\": \"2017-01-01 01:02:03.000000\",\n \"StmtType\": \"\",\n \"Table\": \"table\",\n \"TabletType\": \"MASTER\",\n \"TotalTime\": 1.000001,\n \"Username\": \"\"\n}" + want = "{\n \"BindVars\": {\n \"intVal\": {\n \"type\": \"INT64\",\n \"value\": 1\n }\n },\n \"CommitTime\": 0,\n \"Effective Caller\": \"\",\n \"End\": \"2017-01-01 01:02:04.000001\",\n \"Error\": \"\",\n \"ExecuteTime\": 0,\n \"ImmediateCaller\": \"\",\n \"InTransaction\": false,\n \"Keyspace\": \"ks\",\n \"Method\": \"test\",\n \"PlanTime\": 0,\n \"RemoteAddr\": \"\",\n \"RowsAffected\": 0,\n \"SQL\": \"sql1\",\n \"SessionUUID\": \"suuid\",\n \"ShardQueries\": 0,\n \"Start\": \"2017-01-01 01:02:03.000000\",\n \"StmtType\": \"\",\n \"Table\": \"table\",\n \"TabletType\": \"MASTER\",\n \"TotalTime\": 1.000001,\n \"Username\": \"\"\n}" if string(formatted) != want { t.Errorf("logstats format: got:\n%q\nwant:\n%v\n", string(formatted), want) } @@ -93,7 +93,7 @@ func TestLogStatsFormat(t *testing.T) { if err != nil { t.Errorf("logstats format: error marshaling json: %v -- got:\n%v", err, got) } - want = "{\n \"BindVars\": \"[REDACTED]\",\n \"CommitTime\": 0,\n \"Effective Caller\": \"\",\n \"End\": \"2017-01-01 01:02:04.000001\",\n \"Error\": \"\",\n \"ExecuteTime\": 0,\n \"ImmediateCaller\": \"\",\n \"Keyspace\": \"ks\",\n \"Method\": \"test\",\n \"PlanTime\": 0,\n \"RemoteAddr\": \"\",\n \"RowsAffected\": 0,\n \"SQL\": \"sql1\",\n \"ShardQueries\": 0,\n \"Start\": \"2017-01-01 01:02:03.000000\",\n \"StmtType\": \"\",\n \"Table\": \"table\",\n \"TabletType\": \"MASTER\",\n \"TotalTime\": 1.000001,\n \"Username\": \"\"\n}" + want = "{\n \"BindVars\": \"[REDACTED]\",\n \"CommitTime\": 0,\n \"Effective Caller\": \"\",\n \"End\": \"2017-01-01 01:02:04.000001\",\n \"Error\": \"\",\n \"ExecuteTime\": 0,\n \"ImmediateCaller\": \"\",\n \"InTransaction\": false,\n \"Keyspace\": \"ks\",\n \"Method\": \"test\",\n \"PlanTime\": 0,\n \"RemoteAddr\": \"\",\n \"RowsAffected\": 0,\n \"SQL\": \"sql1\",\n \"SessionUUID\": \"suuid\",\n \"ShardQueries\": 0,\n \"Start\": \"2017-01-01 01:02:03.000000\",\n \"StmtType\": \"\",\n \"Table\": \"table\",\n \"TabletType\": \"MASTER\",\n \"TotalTime\": 1.000001,\n \"Username\": \"\"\n}" if string(formatted) != want { t.Errorf("logstats format: got:\n%q\nwant:\n%v\n", string(formatted), want) } @@ -106,7 +106,7 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.QueryLogFormat = "text" got = testFormat(logStats, url.Values(params)) - want = "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1\"\tmap[strVal:type:VARBINARY value:\"abc\"]\t0\t0\t\"\"\t\"ks\"\t\"table\"\t\"MASTER\"\t\n" + want = "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1\"\tmap[strVal:type:VARBINARY value:\"abc\"]\t0\t0\t\"\"\t\"ks\"\t\"table\"\t\"MASTER\"\tfalse\t\"suuid\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) } @@ -121,7 +121,7 @@ func TestLogStatsFormat(t *testing.T) { if err != nil { t.Errorf("logstats format: error marshaling json: %v -- got:\n%v", err, got) } - want = "{\n \"BindVars\": {\n \"strVal\": {\n \"type\": \"VARBINARY\",\n \"value\": \"abc\"\n }\n },\n \"CommitTime\": 0,\n \"Effective Caller\": \"\",\n \"End\": \"2017-01-01 01:02:04.000001\",\n \"Error\": \"\",\n \"ExecuteTime\": 0,\n \"ImmediateCaller\": \"\",\n \"Keyspace\": \"ks\",\n \"Method\": \"test\",\n \"PlanTime\": 0,\n \"RemoteAddr\": \"\",\n \"RowsAffected\": 0,\n \"SQL\": \"sql1\",\n \"ShardQueries\": 0,\n \"Start\": \"2017-01-01 01:02:03.000000\",\n \"StmtType\": \"\",\n \"Table\": \"table\",\n \"TabletType\": \"MASTER\",\n \"TotalTime\": 1.000001,\n \"Username\": \"\"\n}" + want = "{\n \"BindVars\": {\n \"strVal\": {\n \"type\": \"VARBINARY\",\n \"value\": \"abc\"\n }\n },\n \"CommitTime\": 0,\n \"Effective Caller\": \"\",\n \"End\": \"2017-01-01 01:02:04.000001\",\n \"Error\": \"\",\n \"ExecuteTime\": 0,\n \"ImmediateCaller\": \"\",\n \"InTransaction\": false,\n \"Keyspace\": \"ks\",\n \"Method\": \"test\",\n \"PlanTime\": 0,\n \"RemoteAddr\": \"\",\n \"RowsAffected\": 0,\n \"SQL\": \"sql1\",\n \"SessionUUID\": \"suuid\",\n \"ShardQueries\": 0,\n \"Start\": \"2017-01-01 01:02:03.000000\",\n \"StmtType\": \"\",\n \"Table\": \"table\",\n \"TabletType\": \"MASTER\",\n \"TotalTime\": 1.000001,\n \"Username\": \"\"\n}" if string(formatted) != want { t.Errorf("logstats format: got:\n%q\nwant:\n%v\n", string(formatted), want) } @@ -132,20 +132,20 @@ func TestLogStatsFormat(t *testing.T) { func TestLogStatsFilter(t *testing.T) { defer func() { *streamlog.QueryLogFilterTag = "" }() - logStats := NewLogStats(context.Background(), "test", "sql1 /* LOG_THIS_QUERY */", map[string]*querypb.BindVariable{"intVal": sqltypes.Int64BindVariable(1)}) + logStats := NewLogStats(context.Background(), "test", "sql1 /* LOG_THIS_QUERY */", "suuid", map[string]*querypb.BindVariable{"intVal": sqltypes.Int64BindVariable(1)}) logStats.StartTime = time.Date(2017, time.January, 1, 1, 2, 3, 0, time.UTC) logStats.EndTime = time.Date(2017, time.January, 1, 1, 2, 4, 1234, time.UTC) params := map[string][]string{"full": {}} got := testFormat(logStats, url.Values(params)) - want := "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1 /* LOG_THIS_QUERY */\"\tmap[intVal:type:INT64 value:\"1\"]\t0\t0\t\"\"\t\"\"\t\"\"\t\"\"\t\n" + want := "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1 /* LOG_THIS_QUERY */\"\tmap[intVal:type:INT64 value:\"1\"]\t0\t0\t\"\"\t\"\"\t\"\"\t\"\"\tfalse\t\"suuid\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) } *streamlog.QueryLogFilterTag = "LOG_THIS_QUERY" got = testFormat(logStats, url.Values(params)) - want = "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1 /* LOG_THIS_QUERY */\"\tmap[intVal:type:INT64 value:\"1\"]\t0\t0\t\"\"\t\"\"\t\"\"\t\"\"\t\n" + want = "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1 /* LOG_THIS_QUERY */\"\tmap[intVal:type:INT64 value:\"1\"]\t0\t0\t\"\"\t\"\"\t\"\"\t\"\"\tfalse\t\"suuid\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) } @@ -161,20 +161,20 @@ func TestLogStatsFilter(t *testing.T) { func TestLogStatsRowThreshold(t *testing.T) { defer func() { *streamlog.QueryLogRowThreshold = 0 }() - logStats := NewLogStats(context.Background(), "test", "sql1 /* LOG_THIS_QUERY */", map[string]*querypb.BindVariable{"intVal": sqltypes.Int64BindVariable(1)}) + logStats := NewLogStats(context.Background(), "test", "sql1 /* LOG_THIS_QUERY */", "suuid", map[string]*querypb.BindVariable{"intVal": sqltypes.Int64BindVariable(1)}) logStats.StartTime = time.Date(2017, time.January, 1, 1, 2, 3, 0, time.UTC) logStats.EndTime = time.Date(2017, time.January, 1, 1, 2, 4, 1234, time.UTC) params := map[string][]string{"full": {}} got := testFormat(logStats, url.Values(params)) - want := "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1 /* LOG_THIS_QUERY */\"\tmap[intVal:type:INT64 value:\"1\"]\t0\t0\t\"\"\t\"\"\t\"\"\t\"\"\t\n" + want := "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1 /* LOG_THIS_QUERY */\"\tmap[intVal:type:INT64 value:\"1\"]\t0\t0\t\"\"\t\"\"\t\"\"\t\"\"\tfalse\t\"suuid\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) } *streamlog.QueryLogRowThreshold = 0 got = testFormat(logStats, url.Values(params)) - want = "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1 /* LOG_THIS_QUERY */\"\tmap[intVal:type:INT64 value:\"1\"]\t0\t0\t\"\"\t\"\"\t\"\"\t\"\"\t\n" + want = "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1 /* LOG_THIS_QUERY */\"\tmap[intVal:type:INT64 value:\"1\"]\t0\t0\t\"\"\t\"\"\t\"\"\t\"\"\tfalse\t\"suuid\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) } @@ -193,14 +193,14 @@ func TestLogStatsContextHTML(t *testing.T) { Html: html, } ctx := callinfo.NewContext(context.Background(), callInfo) - logStats := NewLogStats(ctx, "test", "sql1", map[string]*querypb.BindVariable{}) + logStats := NewLogStats(ctx, "test", "sql1", "suuid", map[string]*querypb.BindVariable{}) if string(logStats.ContextHTML()) != html { t.Fatalf("expect to get html: %s, but got: %s", html, string(logStats.ContextHTML())) } } func TestLogStatsErrorStr(t *testing.T) { - logStats := NewLogStats(context.Background(), "test", "sql1", map[string]*querypb.BindVariable{}) + logStats := NewLogStats(context.Background(), "test", "sql1", "suuid", map[string]*querypb.BindVariable{}) if logStats.ErrorStr() != "" { t.Fatalf("should not get error in stats, but got: %s", logStats.ErrorStr()) } @@ -212,7 +212,7 @@ func TestLogStatsErrorStr(t *testing.T) { } func TestLogStatsRemoteAddrUsername(t *testing.T) { - logStats := NewLogStats(context.Background(), "test", "sql1", map[string]*querypb.BindVariable{}) + logStats := NewLogStats(context.Background(), "test", "sql1", "suuid", map[string]*querypb.BindVariable{}) addr, user := logStats.RemoteAddrUsername() if addr != "" { t.Fatalf("remote addr should be empty") @@ -228,7 +228,7 @@ func TestLogStatsRemoteAddrUsername(t *testing.T) { User: username, } ctx := callinfo.NewContext(context.Background(), callInfo) - logStats = NewLogStats(ctx, "test", "sql1", map[string]*querypb.BindVariable{}) + logStats = NewLogStats(ctx, "test", "sql1", "suuid", map[string]*querypb.BindVariable{}) addr, user = logStats.RemoteAddrUsername() if addr != remoteAddr { t.Fatalf("expected to get remote addr: %s, but got: %s", remoteAddr, addr) diff --git a/go/vt/vtgate/plan_execute.go b/go/vt/vtgate/plan_execute.go index 3865ffabad3..f19c392809f 100644 --- a/go/vt/vtgate/plan_execute.go +++ b/go/vt/vtgate/plan_execute.go @@ -120,7 +120,14 @@ func (e *Executor) newExecute(ctx context.Context, safeSession *SafeSession, sql e.executePlan(ctx, plan, vcursor, bindVars, execStart)) } - return e.executePlan(ctx, plan, vcursor, bindVars, execStart)(logStats, safeSession) + // Check if boosted and hit Redis + // plan.BoostPlanConfig.IsBoosted == true + + statementTypeResult, sqlResult, err := e.executePlan(ctx, plan, vcursor, bindVars, execStart)(logStats, safeSession) + + // Maybe store in Redis here if boosted, but cache miss + + return statementTypeResult, sqlResult, err } func (e *Executor) startTxIfNecessary(ctx context.Context, safeSession *SafeSession) error { diff --git a/go/vt/vtgate/planbuilder/builder.go b/go/vt/vtgate/planbuilder/builder.go index 5260ff184c4..5478e4fbc38 100644 --- a/go/vt/vtgate/planbuilder/builder.go +++ b/go/vt/vtgate/planbuilder/builder.go @@ -19,6 +19,7 @@ package planbuilder import ( "errors" "sort" + "vitess.io/vitess/go/vt/vtgate/boost" "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" @@ -93,29 +94,30 @@ func TestBuilder(query string, vschema ContextVSchema) (*engine.Plan, error) { if err != nil { return nil, err } - result, err := sqlparser.RewriteAST(stmt, "") + result, err := sqlparser.RewriteAST(stmt, "", make(map[string]string)) if err != nil { return nil, err } reservedVars := sqlparser.NewReservedVars("vtg", reserved) - return BuildFromStmt(query, result.AST, reservedVars, vschema, result.BindVarNeeds, true, true) + return BuildFromStmt(query, result.AST, reservedVars, vschema, result.BindVarNeeds, true, true, nil) } // ErrPlanNotSupported is an error for plan building not supported var ErrPlanNotSupported = errors.New("plan building not supported") // BuildFromStmt builds a plan based on the AST provided. -func BuildFromStmt(query string, stmt sqlparser.Statement, reservedVars *sqlparser.ReservedVars, vschema ContextVSchema, bindVarNeeds *sqlparser.BindVarNeeds, enableOnlineDDL, enableDirectDDL bool) (*engine.Plan, error) { +func BuildFromStmt(query string, stmt sqlparser.Statement, reservedVars *sqlparser.ReservedVars, vschema ContextVSchema, bindVarNeeds *sqlparser.BindVarNeeds, enableOnlineDDL, enableDirectDDL bool, config *boost.PlanConfig) (*engine.Plan, error) { instruction, err := createInstructionFor(query, stmt, reservedVars, vschema, enableOnlineDDL, enableDirectDDL) if err != nil { return nil, err } plan := &engine.Plan{ - Type: sqlparser.ASTToStatementType(stmt), - Original: query, - Instructions: instruction, - BindVarNeeds: bindVarNeeds, + Type: sqlparser.ASTToStatementType(stmt), + Original: query, + Instructions: instruction, + BindVarNeeds: bindVarNeeds, + BoostPlanConfig: config, } return plan, nil } @@ -167,6 +169,8 @@ func createInstructionFor(query string, stmt sqlparser.Statement, reservedVars * return buildAlterMigrationPlan(query, vschema, enableOnlineDDL) case *sqlparser.RevertMigration: return buildRevertMigrationPlan(query, stmt, vschema, enableOnlineDDL) + case *sqlparser.ShowMigrationLogs: + return buildShowMigrationLogsPlan(query, vschema, enableOnlineDDL) case *sqlparser.AlterVschema: return buildVSchemaDDLPlan(stmt, vschema) case *sqlparser.Use: diff --git a/go/vt/vtgate/planbuilder/concatenate.go b/go/vt/vtgate/planbuilder/concatenate.go index 93cb30d5935..adbff8f1695 100644 --- a/go/vt/vtgate/planbuilder/concatenate.go +++ b/go/vt/vtgate/planbuilder/concatenate.go @@ -70,7 +70,7 @@ func (c *concatenate) SupplyCol(col *sqlparser.ColName) (rc *resultColumn, colNu panic("implement me") } -func (c *concatenate) SupplyWeightString(colNumber int) (weightcolNumber int, err error) { +func (c *concatenate) SupplyWeightString(int, bool) (weightcolNumber int, err error) { panic("implement me") } diff --git a/go/vt/vtgate/planbuilder/delete.go b/go/vt/vtgate/planbuilder/delete.go index f4f409dfa65..3a4d1a1772b 100644 --- a/go/vt/vtgate/planbuilder/delete.go +++ b/go/vt/vtgate/planbuilder/delete.go @@ -49,12 +49,16 @@ func buildDeletePlan(stmt sqlparser.Statement, reservedVars *sqlparser.ReservedV return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "multi-table delete statement in not supported in sharded database") } - if len(del.Targets) == 1 && del.Targets[0].Name != edel.Table.Name { + edelTable, err := edel.GetSingleTable() + if err != nil { + return nil, err + } + if len(del.Targets) == 1 && del.Targets[0].Name != edelTable.Name { return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.UnknownTable, "Unknown table '%s' in MULTI DELETE", del.Targets[0].Name.String()) } - if len(edel.Table.Owned) > 0 { - edel.OwnedVindexQuery = generateDMLSubquery(del.Where, del.OrderBy, del.Limit, edel.Table, ksidCol) + if len(edelTable.Owned) > 0 { + edel.OwnedVindexQuery = generateDMLSubquery(del.Where, del.OrderBy, del.Limit, edelTable, ksidCol) edel.KsidVindex = ksidVindex } diff --git a/go/vt/vtgate/planbuilder/dml.go b/go/vt/vtgate/planbuilder/dml.go index 06d87df428e..d46983c1da1 100644 --- a/go/vt/vtgate/planbuilder/dml.go +++ b/go/vt/vtgate/planbuilder/dml.go @@ -51,6 +51,10 @@ func getDMLRouting(where *sqlparser.Where, table *vindexes.Table) (engine.DMLOpc opcode := engine.Equal if pv.IsList() { opcode = engine.In + } else if lu, isLu := single.(vindexes.LookupBackfill); isLu && lu.IsBackfilling() { + // Checking if the Vindex is currently backfilling or not, if it isn't we can read from the vindex table + // and we will be able to do a delete equal. Otherwise, we continue to look for next best vindex. + continue } return opcode, ksidVindex, ksidCol, single, []sqltypes.PlanValue{pv}, nil } @@ -108,12 +112,17 @@ func buildDMLPlan(vschema ContextVSchema, dmlType string, stmt sqlparser.Stateme return nil, nil, "", err } edml.Keyspace = rb.eroute.Keyspace + edml.Table, err = pb.st.AllVschemaTableNames() + if err != nil { + return nil, nil, "", err + } if !edml.Keyspace.Sharded { // We only validate non-table subexpressions because the previous analysis has already validated them. var subqueryArgs []sqlparser.SQLNode subqueryArgs = append(subqueryArgs, nodes...) subqueryArgs = append(subqueryArgs, where, orderBy, limit) - if pb.finalizeUnshardedDMLSubqueries(reservedVars, subqueryArgs...) { + subqueryIsUnsharded, subqueryTables := pb.finalizeUnshardedDMLSubqueries(reservedVars, subqueryArgs...) + if subqueryIsUnsharded { vschema.WarnUnshardedOnly("subqueries can't be sharded in DML") } else { return nil, nil, "", vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "unsupported: sharded subqueries in DML") @@ -122,6 +131,7 @@ func buildDMLPlan(vschema ContextVSchema, dmlType string, stmt sqlparser.Stateme // Generate query after all the analysis. Otherwise table name substitutions for // routed tables won't happen. edml.Query = generateQuery(stmt) + edml.Table = append(edml.Table, subqueryTables...) return edml, nil, "", nil } @@ -143,12 +153,12 @@ func buildDMLPlan(vschema ContextVSchema, dmlType string, stmt sqlparser.Stateme if len(pb.st.tables) != 1 { return nil, nil, "", vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "multi-table %s statement is not supported in sharded database", dmlType) } - for _, tval := range pb.st.tables { - // There is only one table. - edml.Table = tval.vschemaTable + edmlTable, err := edml.GetSingleTable() + if err != nil { + return nil, nil, "", err } - routingType, ksidVindex, ksidCol, vindex, values, err := getDMLRouting(where, edml.Table) + routingType, ksidVindex, ksidCol, vindex, values, err := getDMLRouting(where, edmlTable) if err != nil { return nil, nil, "", err } diff --git a/go/vt/vtgate/planbuilder/expr.go b/go/vt/vtgate/planbuilder/expr.go index 82ed9008644..6c796345cfe 100644 --- a/go/vt/vtgate/planbuilder/expr.go +++ b/go/vt/vtgate/planbuilder/expr.go @@ -23,6 +23,7 @@ import ( "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vtgate/engine" + "vitess.io/vitess/go/vt/vtgate/vindexes" ) type subqueryInfo struct { @@ -206,13 +207,14 @@ func hasSubquery(node sqlparser.SQLNode) bool { return has } -func (pb *primitiveBuilder) finalizeUnshardedDMLSubqueries(reservedVars *sqlparser.ReservedVars, nodes ...sqlparser.SQLNode) bool { +func (pb *primitiveBuilder) finalizeUnshardedDMLSubqueries(reservedVars *sqlparser.ReservedVars, nodes ...sqlparser.SQLNode) (bool, []*vindexes.Table) { var keyspace string + var tables []*vindexes.Table if rb, ok := pb.plan.(*route); ok { keyspace = rb.eroute.Keyspace.Name } else { // This code is unreachable because the caller checks. - return false + return false, nil } for _, node := range nodes { @@ -244,6 +246,11 @@ func (pb *primitiveBuilder) finalizeUnshardedDMLSubqueries(reservedVars *sqlpars for _, sub := range innerRoute.substitutions { *sub.oldExpr = *sub.newExpr } + spbTables, err := spb.st.AllVschemaTableNames() + if err != nil { + return false, err + } + tables = append(tables, spbTables...) case *sqlparser.Union: if !inSubQuery { return true, nil @@ -267,10 +274,10 @@ func (pb *primitiveBuilder) finalizeUnshardedDMLSubqueries(reservedVars *sqlpars return true, nil }, node) if !samePlan { - return false + return false, nil } } - return true + return true, tables } func valEqual(a, b sqlparser.Expr) bool { diff --git a/go/vt/vtgate/planbuilder/from.go b/go/vt/vtgate/planbuilder/from.go index 026010585a2..54fb99a2852 100644 --- a/go/vt/vtgate/planbuilder/from.go +++ b/go/vt/vtgate/planbuilder/from.go @@ -19,6 +19,8 @@ package planbuilder import ( "errors" "fmt" + "sort" + "strings" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" @@ -142,8 +144,18 @@ func (pb *primitiveBuilder) processAliasedTable(tableExpr *sqlparser.AliasedTabl // a new set of column references will be generated against the new tables, // and those vindex maps will be returned. They have to replace the old vindex // maps of the inherited route options. + var tableNames []string + spbTables, err := spb.st.AllVschemaTableNames() + if err != nil { + return err + } + for _, table := range spbTables { + tableNames = append(tableNames, table.Name.String()) + } + sort.Strings(tableNames) vschemaTable := &vindexes.Table{ Keyspace: subroute.eroute.Keyspace, + Name: sqlparser.NewTableIdent(strings.Join(tableNames, ", ")), } for _, rc := range subroute.ResultColumns() { if rc.column.vindex == nil { @@ -186,6 +198,7 @@ func (pb *primitiveBuilder) buildTablePrimitive(tableExpr *sqlparser.AliasedTabl } rb, st := newRoute(sel) rb.eroute = engine.NewSimpleRoute(engine.SelectDBA, ks) + rb.eroute.TableName = sqlparser.String(tableName) pb.plan, pb.st = rb, st // Add the table to symtab return st.AddTable(&table{ @@ -344,6 +357,14 @@ func (pb *primitiveBuilder) join(rpb *primitiveBuilder, ajoin *sqlparser.JoinTab sel.From = sqlparser.TableExprs{ajoin} } + // join table name + if lRoute.eroute.TableName != rRoute.eroute.TableName { + lRoute.eroute.TableName = strings.Join([]string{lRoute.eroute.TableName, rRoute.eroute.TableName}, ", ") + } + + // join sysTableNames + lRoute.eroute.SysTableTableName = append(lRoute.eroute.SysTableTableName, rRoute.eroute.SysTableTableName...) + // Since the routes have merged, set st.singleRoute to point at // the merged route. pb.st.singleRoute = lRoute diff --git a/go/vt/vtgate/planbuilder/grouping.go b/go/vt/vtgate/planbuilder/grouping.go index a1b8614a64b..788942d061e 100644 --- a/go/vt/vtgate/planbuilder/grouping.go +++ b/go/vt/vtgate/planbuilder/grouping.go @@ -77,6 +77,7 @@ func planGroupBy(pb *primitiveBuilder, input logicalPlan, groupBy sqlparser.Grou return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "unsupported: in scatter query: only simple references allowed") } node.eaggr.Keys = append(node.eaggr.Keys, colNumber) + node.eaggr.FromGroupBy = append(node.eaggr.FromGroupBy, true) } // Append the distinct aggregate if any. if node.extraDistinct != nil { @@ -110,6 +111,7 @@ func planDistinct(input logicalPlan) (logicalPlan, error) { return newDistinct(node), nil } node.eaggr.Keys = append(node.eaggr.Keys, i) + node.eaggr.FromGroupBy = append(node.eaggr.FromGroupBy, false) } newInput, err := planDistinct(node.input) if err != nil { diff --git a/go/vt/vtgate/planbuilder/insert.go b/go/vt/vtgate/planbuilder/insert.go index fd3144f175b..f0af6ae618e 100644 --- a/go/vt/vtgate/planbuilder/insert.go +++ b/go/vt/vtgate/planbuilder/insert.go @@ -54,7 +54,7 @@ func buildInsertPlan(stmt sqlparser.Statement, reservedVars *sqlparser.ReservedV vschemaTable = tval.vschemaTable } if !rb.eroute.Keyspace.Sharded { - if pb.finalizeUnshardedDMLSubqueries(reservedVars, ins) { + if subqueryIsUnsharded, _ := pb.finalizeUnshardedDMLSubqueries(reservedVars, ins); subqueryIsUnsharded { vschema.WarnUnshardedOnly("subqueries can't be sharded for INSERT") } else { return nil, errors.New("unsupported: sharded subquery in insert values") diff --git a/go/vt/vtgate/planbuilder/join.go b/go/vt/vtgate/planbuilder/join.go index 30f79b69060..b5c499973f8 100644 --- a/go/vt/vtgate/planbuilder/join.go +++ b/go/vt/vtgate/planbuilder/join.go @@ -210,20 +210,20 @@ func (jb *join) SupplyCol(col *sqlparser.ColName) (rc *resultColumn, colNumber i } // SupplyWeightString implements the logicalPlan interface -func (jb *join) SupplyWeightString(colNumber int) (weightcolNumber int, err error) { +func (jb *join) SupplyWeightString(colNumber int, alsoAddToGroupBy bool) (weightcolNumber int, err error) { rc := jb.resultColumns[colNumber] if weightcolNumber, ok := jb.weightStrings[rc]; ok { return weightcolNumber, nil } routeNumber := rc.column.Origin().Order() if jb.isOnLeft(routeNumber) { - sourceCol, err := jb.Left.SupplyWeightString(-jb.ejoin.Cols[colNumber] - 1) + sourceCol, err := jb.Left.SupplyWeightString(-jb.ejoin.Cols[colNumber]-1, alsoAddToGroupBy) if err != nil { return 0, err } jb.ejoin.Cols = append(jb.ejoin.Cols, -sourceCol-1) } else { - sourceCol, err := jb.Right.SupplyWeightString(jb.ejoin.Cols[colNumber] - 1) + sourceCol, err := jb.Right.SupplyWeightString(jb.ejoin.Cols[colNumber]-1, alsoAddToGroupBy) if err != nil { return 0, err } diff --git a/go/vt/vtgate/planbuilder/joinGen4.go b/go/vt/vtgate/planbuilder/joinGen4.go index 4339f1f2452..6da7e618a50 100644 --- a/go/vt/vtgate/planbuilder/joinGen4.go +++ b/go/vt/vtgate/planbuilder/joinGen4.go @@ -76,7 +76,7 @@ func (j *joinGen4) SupplyCol(col *sqlparser.ColName) (rc *resultColumn, colNumbe } // SupplyWeightString implements the logicalPlan interface -func (j *joinGen4) SupplyWeightString(colNumber int) (weightcolNumber int, err error) { +func (j *joinGen4) SupplyWeightString(int, bool) (weightcolNumber int, err error) { panic("implement me") } diff --git a/go/vt/vtgate/planbuilder/jointree_transformers.go b/go/vt/vtgate/planbuilder/jointree_transformers.go index d828cc0971c..234a6928b0f 100644 --- a/go/vt/vtgate/planbuilder/jointree_transformers.go +++ b/go/vt/vtgate/planbuilder/jointree_transformers.go @@ -112,8 +112,9 @@ func transformRoutePlan(n *routePlan) (*route, error) { LeftExpr: lft, } tablesForSelect = sqlparser.TableExprs{joinExpr} - // todo: add table - // tableNameMap[sqlparser.String()] = nil + for _, tblNames := range leftJoin.right.tableNames() { + tableNameMap[tblNames] = nil + } } predicates := n.Predicates() diff --git a/go/vt/vtgate/planbuilder/logical_plan.go b/go/vt/vtgate/planbuilder/logical_plan.go index 00ee488a2cf..0cf87f05567 100644 --- a/go/vt/vtgate/planbuilder/logical_plan.go +++ b/go/vt/vtgate/planbuilder/logical_plan.go @@ -70,7 +70,7 @@ type logicalPlan interface { // SupplyWeightString must supply a weight_string expression of the // specified column. It returns an error if we cannot supply a weight column for it. - SupplyWeightString(colNumber int) (weightcolNumber int, err error) + SupplyWeightString(colNumber int, alsoAddToGroupBy bool) (weightcolNumber int, err error) // Primitive returns the underlying primitive. // This function should only be called after Wireup is finished. @@ -170,8 +170,8 @@ func (bc *logicalPlanCommon) SupplyCol(col *sqlparser.ColName) (rc *resultColumn return bc.input.SupplyCol(col) } -func (bc *logicalPlanCommon) SupplyWeightString(colNumber int) (weightcolNumber int, err error) { - return bc.input.SupplyWeightString(colNumber) +func (bc *logicalPlanCommon) SupplyWeightString(colNumber int, alsoAddToGroupBy bool) (weightcolNumber int, err error) { + return bc.input.SupplyWeightString(colNumber, alsoAddToGroupBy) } // Rewrite implements the logicalPlan interface @@ -239,12 +239,14 @@ func (rsb *resultsBuilder) SupplyCol(col *sqlparser.ColName) (rc *resultColumn, return rc, colNumber } -func (rsb *resultsBuilder) SupplyWeightString(colNumber int) (weightcolNumber int, err error) { +func (rsb *resultsBuilder) SupplyWeightString(colNumber int, alsoAddToGroupBy bool) (weightcolNumber int, err error) { rc := rsb.resultColumns[colNumber] - if weightcolNumber, ok := rsb.weightStrings[rc]; ok { + var ok bool + weightcolNumber, ok = rsb.weightStrings[rc] + if !alsoAddToGroupBy && ok { return weightcolNumber, nil } - weightcolNumber, err = rsb.input.SupplyWeightString(colNumber) + weightcolNumber, err = rsb.input.SupplyWeightString(colNumber, alsoAddToGroupBy) if err != nil { return 0, nil } diff --git a/go/vt/vtgate/planbuilder/memory_sort.go b/go/vt/vtgate/planbuilder/memory_sort.go index 8f06423699f..4793edc38db 100644 --- a/go/vt/vtgate/planbuilder/memory_sort.go +++ b/go/vt/vtgate/planbuilder/memory_sort.go @@ -40,7 +40,7 @@ type memorySort struct { } // newMemorySort builds a new memorySort. -func newMemorySort(plan logicalPlan, orderBy sqlparser.OrderBy) (*memorySort, error) { +func newMemorySort(plan logicalPlan, orderBy v3OrderBy) (*memorySort, error) { eMemorySort := &engine.MemorySort{} ms := &memorySort{ resultsBuilder: newResultsBuilder(plan, eMemorySort), @@ -115,15 +115,9 @@ func (ms *memorySort) Wireup(plan logicalPlan, jt *jointab) error { rc := ms.resultColumns[orderby.Col] // Add a weight_string column if we know that the column is a textual column or if its type is unknown if sqltypes.IsText(rc.column.typ) || rc.column.typ == sqltypes.Null { - // If a weight string was previously requested, reuse it. - if weightcolNumber, ok := ms.weightStrings[rc]; ok { - ms.eMemorySort.OrderBy[i].WeightStringCol = weightcolNumber - continue - } - weightcolNumber, err := ms.input.SupplyWeightString(orderby.Col) + weightcolNumber, err := ms.input.SupplyWeightString(orderby.Col, orderby.FromGroupBy) if err != nil { - _, isUnsupportedErr := err.(UnsupportedSupplyWeightString) - if isUnsupportedErr { + if _, isUnsupportedErr := err.(UnsupportedSupplyWeightString); isUnsupportedErr { continue } return err diff --git a/go/vt/vtgate/planbuilder/merge_sort.go b/go/vt/vtgate/planbuilder/merge_sort.go index 76915f3b623..2646d9b2627 100644 --- a/go/vt/vtgate/planbuilder/merge_sort.go +++ b/go/vt/vtgate/planbuilder/merge_sort.go @@ -68,13 +68,8 @@ func (ms *mergeSort) Wireup(plan logicalPlan, jt *jointab) error { rc := ms.resultColumns[orderby.Col] // Add a weight_string column if we know that the column is a textual column or if its type is unknown if sqltypes.IsText(rc.column.typ) || rc.column.typ == sqltypes.Null { - // If a weight string was previously requested, reuse it. - if colNumber, ok := ms.weightStrings[rc]; ok { - rb.eroute.OrderBy[i].WeightStringCol = colNumber - continue - } var err error - rb.eroute.OrderBy[i].WeightStringCol, err = rb.SupplyWeightString(orderby.Col) + rb.eroute.OrderBy[i].WeightStringCol, err = rb.SupplyWeightString(orderby.Col, orderby.FromGroupBy) if err != nil { _, isUnsupportedErr := err.(UnsupportedSupplyWeightString) if isUnsupportedErr { diff --git a/go/vt/vtgate/planbuilder/migration.go b/go/vt/vtgate/planbuilder/migration.go index 521e97defd5..8d9fcda52b7 100644 --- a/go/vt/vtgate/planbuilder/migration.go +++ b/go/vt/vtgate/planbuilder/migration.go @@ -80,3 +80,30 @@ func buildRevertMigrationPlan(query string, stmt *sqlparser.RevertMigration, vsc Query: query, }, nil } + +func buildShowMigrationLogsPlan(query string, vschema ContextVSchema, enableOnlineDDL bool) (engine.Primitive, error) { + if !enableOnlineDDL { + return nil, schema.ErrOnlineDDLDisabled + } + dest, ks, tabletType, err := vschema.TargetDestination("") + if err != nil { + return nil, err + } + if ks == nil { + return nil, vterrors.NewErrorf(vtrpcpb.Code_FAILED_PRECONDITION, vterrors.NoDB, "No database selected: use keyspace<:shard><@type> or keyspace<[range]><@type> (<> are optional)") + } + + if tabletType != topodatapb.TabletType_MASTER { + return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "SHOW VITESS_MIGRATION works only on primary tablet") + } + + if dest == nil { + dest = key.DestinationAllShards{} + } + + return &engine.Send{ + Keyspace: ks, + TargetDestination: dest, + Query: query, + }, nil +} diff --git a/go/vt/vtgate/planbuilder/ordered_aggregate.go b/go/vt/vtgate/planbuilder/ordered_aggregate.go index e3a82a08f47..3b7546e6feb 100644 --- a/go/vt/vtgate/planbuilder/ordered_aggregate.go +++ b/go/vt/vtgate/planbuilder/ordered_aggregate.go @@ -334,11 +334,7 @@ func (oa *orderedAggregate) Wireup(plan logicalPlan, jt *jointab) error { for i, colNumber := range oa.eaggr.Keys { rc := oa.resultColumns[colNumber] if sqltypes.IsText(rc.column.typ) { - if weightcolNumber, ok := oa.weightStrings[rc]; ok { - oa.eaggr.Keys[i] = weightcolNumber - continue - } - weightcolNumber, err := oa.input.SupplyWeightString(colNumber) + weightcolNumber, err := oa.input.SupplyWeightString(colNumber, oa.eaggr.FromGroupBy[i]) if err != nil { _, isUnsupportedErr := err.(UnsupportedSupplyWeightString) if isUnsupportedErr { diff --git a/go/vt/vtgate/planbuilder/ordering.go b/go/vt/vtgate/planbuilder/ordering.go index 57f3b268db6..7bdb77c9f22 100644 --- a/go/vt/vtgate/planbuilder/ordering.go +++ b/go/vt/vtgate/planbuilder/ordering.go @@ -22,7 +22,14 @@ import ( "vitess.io/vitess/go/vt/vtgate/engine" ) -func planOrdering(pb *primitiveBuilder, input logicalPlan, orderBy sqlparser.OrderBy) (logicalPlan, error) { +type v3Order struct { + *sqlparser.Order + fromGroupBy bool +} + +type v3OrderBy []*v3Order + +func planOrdering(pb *primitiveBuilder, input logicalPlan, orderBy v3OrderBy) (logicalPlan, error) { switch node := input.(type) { case *subquery, *vindexFunc: if len(orderBy) == 0 { @@ -56,7 +63,7 @@ func planOrdering(pb *primitiveBuilder, input logicalPlan, orderBy sqlparser.Ord return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "[BUG] unreachable %T.ordering", input) } -func planOAOrdering(pb *primitiveBuilder, orderBy sqlparser.OrderBy, oa *orderedAggregate) (logicalPlan, error) { +func planOAOrdering(pb *primitiveBuilder, orderBy v3OrderBy, oa *orderedAggregate) (logicalPlan, error) { // The requested order must be such that the ordering can be done // before the group by, which will allow us to push it down to the // route. This is actually true in most use cases, except for situations @@ -78,7 +85,7 @@ func planOAOrdering(pb *primitiveBuilder, orderBy sqlparser.OrderBy, oa *ordered // referenced tracks the keys referenced by the order by clause. referenced := make([]bool, len(oa.eaggr.Keys)) postSort := false - selOrderBy := make(sqlparser.OrderBy, 0, len(orderBy)) + selOrderBy := make(v3OrderBy, 0, len(orderBy)) for _, order := range orderBy { // Identify the order by column. var orderByCol *column @@ -110,6 +117,7 @@ func planOAOrdering(pb *primitiveBuilder, orderBy sqlparser.OrderBy, oa *ordered found = true referenced[j] = true + order.fromGroupBy = oa.eaggr.FromGroupBy[j] selOrderBy = append(selOrderBy, order) break } @@ -128,12 +136,19 @@ func planOAOrdering(pb *primitiveBuilder, orderBy sqlparser.OrderBy, oa *ordered if err != nil { return nil, vterrors.Wrapf(err, "generating order by clause") } - selOrderBy = append(selOrderBy, &sqlparser.Order{Expr: col, Direction: sqlparser.AscOrder}) + selOrderBy = append(selOrderBy, &v3Order{ + Order: &sqlparser.Order{Expr: col, Direction: sqlparser.AscOrder}, + fromGroupBy: oa.eaggr.FromGroupBy[i], + }) } // Append the distinct aggregate if any. if oa.extraDistinct != nil { - selOrderBy = append(selOrderBy, &sqlparser.Order{Expr: oa.extraDistinct, Direction: sqlparser.AscOrder}) + el := &sqlparser.Order{Expr: oa.extraDistinct, Direction: sqlparser.AscOrder} + selOrderBy = append(selOrderBy, &v3Order{ + Order: el, + fromGroupBy: true, + }) } // Push down the order by. @@ -151,7 +166,7 @@ func planOAOrdering(pb *primitiveBuilder, orderBy sqlparser.OrderBy, oa *ordered return oa, nil } -func planJoinOrdering(pb *primitiveBuilder, orderBy sqlparser.OrderBy, node *join) (logicalPlan, error) { +func planJoinOrdering(pb *primitiveBuilder, orderBy v3OrderBy, node *join) (logicalPlan, error) { isSpecial := false switch len(orderBy) { case 0: @@ -226,7 +241,7 @@ func planJoinOrdering(pb *primitiveBuilder, orderBy sqlparser.OrderBy, node *joi return node, nil } -func planRouteOrdering(orderBy sqlparser.OrderBy, node *route) (logicalPlan, error) { +func planRouteOrdering(orderBy v3OrderBy, node *route) (logicalPlan, error) { switch len(orderBy) { case 0: return node, nil @@ -240,14 +255,14 @@ func planRouteOrdering(orderBy sqlparser.OrderBy, node *route) (logicalPlan, err } } if isSpecial { - node.Select.AddOrder(orderBy[0]) + node.Select.AddOrder(orderBy[0].Order) return node, nil } } if node.isSingleShard() { for _, order := range orderBy { - node.Select.AddOrder(order) + node.Select.AddOrder(order.Order) } return node, nil } @@ -318,10 +333,11 @@ func planRouteOrdering(orderBy sqlparser.OrderBy, node *route) (logicalPlan, err WeightStringCol: -1, Desc: order.Direction == sqlparser.DescOrder, StarColFixedIndex: starColFixedIndex, + FromGroupBy: order.fromGroupBy, } node.eroute.OrderBy = append(node.eroute.OrderBy, ob) - node.Select.AddOrder(order) + node.Select.AddOrder(order.Order) } return newMergeSort(node), nil } diff --git a/go/vt/vtgate/planbuilder/postprocess.go b/go/vt/vtgate/planbuilder/postprocess.go index 2df10473fe6..b1c0b936360 100644 --- a/go/vt/vtgate/planbuilder/postprocess.go +++ b/go/vt/vtgate/planbuilder/postprocess.go @@ -54,7 +54,16 @@ func (pb *primitiveBuilder) pushOrderBy(orderBy sqlparser.OrderBy) error { if err := pb.st.ResolveSymbols(orderBy); err != nil { return err } - plan, err := planOrdering(pb, pb.plan, orderBy) + + var v3OrderBylist v3OrderBy + + if orderBy != nil { + v3OrderBylist = make(v3OrderBy, 0, len(orderBy)) + for _, order := range orderBy { + v3OrderBylist = append(v3OrderBylist, &v3Order{Order: order}) + } + } + plan, err := planOrdering(pb, pb.plan, v3OrderBylist) if err != nil { return err } diff --git a/go/vt/vtgate/planbuilder/pullout_subquery.go b/go/vt/vtgate/planbuilder/pullout_subquery.go index 8b03ec852bd..68f3d0073ef 100644 --- a/go/vt/vtgate/planbuilder/pullout_subquery.go +++ b/go/vt/vtgate/planbuilder/pullout_subquery.go @@ -110,8 +110,8 @@ func (ps *pulloutSubquery) SupplyCol(col *sqlparser.ColName) (rc *resultColumn, } // SupplyWeightString implements the logicalPlan interface -func (ps *pulloutSubquery) SupplyWeightString(colNumber int) (weightcolNumber int, err error) { - return ps.underlying.SupplyWeightString(colNumber) +func (ps *pulloutSubquery) SupplyWeightString(colNumber int, alsoAddToGroupBy bool) (weightcolNumber int, err error) { + return ps.underlying.SupplyWeightString(colNumber, alsoAddToGroupBy) } // Rewrite implements the logicalPlan interface diff --git a/go/vt/vtgate/planbuilder/route.go b/go/vt/vtgate/planbuilder/route.go index 418d083e8f9..4988f28f578 100644 --- a/go/vt/vtgate/planbuilder/route.go +++ b/go/vt/vtgate/planbuilder/route.go @@ -333,11 +333,8 @@ func (rb *route) SupplyCol(col *sqlparser.ColName) (rc *resultColumn, colNumber } // SupplyWeightString implements the logicalPlan interface -func (rb *route) SupplyWeightString(colNumber int) (weightcolNumber int, err error) { +func (rb *route) SupplyWeightString(colNumber int, alsoAddToGroupBy bool) (weightcolNumber int, err error) { rc := rb.resultColumns[colNumber] - if weightcolNumber, ok := rb.weightStrings[rc]; ok { - return weightcolNumber, nil - } s, ok := rb.Select.(*sqlparser.Select) if !ok { return 0, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "unexpected AST struct for query") @@ -347,16 +344,29 @@ func (rb *route) SupplyWeightString(colNumber int) (weightcolNumber int, err err if !ok { return 0, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "unexpected AST struct for query %T", s.SelectExprs[colNumber]) } - expr := &sqlparser.AliasedExpr{ - Expr: &sqlparser.FuncExpr{ - Name: sqlparser.NewColIdent("weight_string"), - Exprs: []sqlparser.SelectExpr{ - &sqlparser.AliasedExpr{ - Expr: aliasExpr.Expr, - }, + weightStringExpr := &sqlparser.FuncExpr{ + Name: sqlparser.NewColIdent("weight_string"), + Exprs: []sqlparser.SelectExpr{ + &sqlparser.AliasedExpr{ + Expr: aliasExpr.Expr, }, }, } + if alsoAddToGroupBy { + sel, isSelect := rb.Select.(*sqlparser.Select) + if !isSelect { + return 0, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "cannot add weight string in %T", rb.Select) + } + sel.GroupBy = append(sel.GroupBy, weightStringExpr) + } + + expr := &sqlparser.AliasedExpr{ + Expr: weightStringExpr, + } + + if weightcolNumber, ok := rb.weightStrings[rc]; ok { + return weightcolNumber, nil + } // It's ok to pass nil for pb and logicalPlan because PushSelect doesn't use them. // TODO: we are ignoring a potential error here. need to clean this up _, _, weightcolNumber, err = planProjection(nil, rb, expr, nil) @@ -457,9 +467,15 @@ func (rb *route) SubqueryCanMerge(pb *primitiveBuilder, inner *route) bool { if rb.eroute.Keyspace.Name != inner.eroute.Keyspace.Name { return false } + + // if either side is a reference table, we can just merge it and use the opcode of the other side + if rb.eroute.Opcode == engine.SelectReference || inner.eroute.Opcode == engine.SelectReference { + return true + } + switch rb.eroute.Opcode { - case engine.SelectUnsharded, engine.SelectDBA, engine.SelectReference: - return rb.eroute.Opcode == inner.eroute.Opcode || inner.eroute.Opcode == engine.SelectReference + case engine.SelectUnsharded, engine.SelectDBA: + return rb.eroute.Opcode == inner.eroute.Opcode case engine.SelectEqualUnique: // Check if they target the same shard. if inner.eroute.Opcode == engine.SelectEqualUnique && rb.eroute.Vindex == inner.eroute.Vindex && valEqual(rb.condition, inner.condition) { @@ -468,11 +484,7 @@ func (rb *route) SubqueryCanMerge(pb *primitiveBuilder, inner *route) bool { case engine.SelectNext: return false } - // Any sharded plan (including SelectEqualUnique) can merge on a reference table subquery. - // This excludes the case of SelectReference with a sharded subquery. - if inner.eroute.Opcode == engine.SelectReference { - return true - } + switch vals := inner.condition.(type) { case *sqlparser.ColName: if pb.st.Vindex(vals, rb) == inner.eroute.Vindex { diff --git a/go/vt/vtgate/planbuilder/route_test.go b/go/vt/vtgate/planbuilder/route_test.go index 81736fb452e..0e0efae42f2 100644 --- a/go/vt/vtgate/planbuilder/route_test.go +++ b/go/vt/vtgate/planbuilder/route_test.go @@ -87,9 +87,9 @@ func TestSubqueryCanMerge(t *testing.T) { {false, false, false, false, false, false, false, false, true, false}, {false, false, false, false, false, false, false, false, true, false}, {false, false, false, false, false, false, false, false, true, false}, - {false, false, false, false, false, false, false, false, false, false}, - {false, false, false, false, false, false, false, true, true, false}, {false, false, false, false, false, false, false, false, true, false}, + {false, false, false, false, false, false, false, true, true, false}, + {true, true, true, true, true, true, true, true, true, true}, {false, false, false, false, false, false, false, false, true, false}, } diff --git a/go/vt/vtgate/planbuilder/sql_calc_found_rows.go b/go/vt/vtgate/planbuilder/sql_calc_found_rows.go index 5534d20bee0..ac55baada8e 100644 --- a/go/vt/vtgate/planbuilder/sql_calc_found_rows.go +++ b/go/vt/vtgate/planbuilder/sql_calc_found_rows.go @@ -90,7 +90,7 @@ func (s *sqlCalcFoundRows) SupplyCol(col *sqlparser.ColName) (*resultColumn, int } //SupplyWeightString implements the logicalPlan interface -func (s *sqlCalcFoundRows) SupplyWeightString(int) (weightcolNumber int, err error) { +func (s *sqlCalcFoundRows) SupplyWeightString(int, bool) (weightcolNumber int, err error) { return 0, UnsupportedSupplyWeightString{Type: "sqlCalcFoundRows"} } diff --git a/go/vt/vtgate/planbuilder/symtab.go b/go/vt/vtgate/planbuilder/symtab.go index 658f52d5c9e..305af6d64fa 100644 --- a/go/vt/vtgate/planbuilder/symtab.go +++ b/go/vt/vtgate/planbuilder/symtab.go @@ -205,6 +205,24 @@ func (st *symtab) AllTables() []*table { return tables } +// AllVschemaTableNames returns an ordered list of all current vschema tables. +func (st *symtab) AllVschemaTableNames() ([]*vindexes.Table, error) { + if len(st.tableNames) == 0 { + return nil, nil + } + tables := make([]*vindexes.Table, 0, len(st.tableNames)) + for _, tname := range st.tableNames { + t, ok := st.tables[tname] + if !ok { + return nil, fmt.Errorf("table %v not found", sqlparser.String(tname)) + } + if t.vschemaTable != nil { + tables = append(tables, t.vschemaTable) + } + } + return tables, nil +} + // FindTable finds a table in symtab. This function is specifically used // for expanding 'select a.*' constructs. If you're in a subquery, // you're most likely referring to a table in the local 'from' clause. diff --git a/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt b/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt index b109137932f..f0e5b5c686d 100644 --- a/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt @@ -115,9 +115,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select count(*), a, textcol1, b, weight_string(textcol1), weight_string(a), weight_string(b) from `user` where 1 != 1 group by a, textcol1, b", + "FieldQuery": "select count(*), a, textcol1, b, weight_string(textcol1), weight_string(a), weight_string(b) from `user` where 1 != 1 group by a, textcol1, b, weight_string(textcol1), weight_string(a), weight_string(textcol1), weight_string(b)", "OrderBy": "1 ASC, 2 ASC, 3 ASC", - "Query": "select count(*), a, textcol1, b, weight_string(textcol1), weight_string(a), weight_string(b) from `user` group by a, textcol1, b order by a asc, textcol1 asc, b asc", + "Query": "select count(*), a, textcol1, b, weight_string(textcol1), weight_string(a), weight_string(b) from `user` group by a, textcol1, b, weight_string(textcol1), weight_string(a), weight_string(textcol1), weight_string(b) order by a asc, textcol1 asc, b asc", "ResultColumns": 5, "Table": "`user`" } @@ -175,9 +175,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select count(*) as k, a, textcol1, b, weight_string(textcol1), weight_string(a), weight_string(b) from `user` where 1 != 1 group by a, textcol1, b", + "FieldQuery": "select count(*) as k, a, textcol1, b, weight_string(textcol1), weight_string(a), weight_string(b) from `user` where 1 != 1 group by a, textcol1, b, weight_string(textcol1), weight_string(textcol1), weight_string(a), weight_string(b)", "OrderBy": "2 ASC, 1 ASC, 3 ASC", - "Query": "select count(*) as k, a, textcol1, b, weight_string(textcol1), weight_string(a), weight_string(b) from `user` group by a, textcol1, b order by textcol1 asc, a asc, b asc", + "Query": "select count(*) as k, a, textcol1, b, weight_string(textcol1), weight_string(a), weight_string(b) from `user` group by a, textcol1, b, weight_string(textcol1), weight_string(textcol1), weight_string(a), weight_string(b) order by textcol1 asc, a asc, b asc", "ResultColumns": 5, "Table": "`user`" } @@ -308,9 +308,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select col1, col2, weight_string(col1), weight_string(col2) from `user` where 1 != 1 group by col1", + "FieldQuery": "select col1, col2, weight_string(col1), weight_string(col2) from `user` where 1 != 1 group by col1, weight_string(col1)", "OrderBy": "0 ASC, 1 ASC, 0 ASC", - "Query": "select distinct col1, col2, weight_string(col1), weight_string(col2) from `user` group by col1 order by col1 asc, col2 asc, col1 asc", + "Query": "select distinct col1, col2, weight_string(col1), weight_string(col2) from `user` group by col1, weight_string(col1) order by col1 asc, col2 asc, col1 asc", "ResultColumns": 2, "Table": "`user`" } @@ -327,7 +327,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -409,9 +409,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select col, count(*), weight_string(col) from `user` where 1 != 1 group by col", + "FieldQuery": "select col, count(*), weight_string(col) from `user` where 1 != 1 group by col, weight_string(col)", "OrderBy": "0 ASC", - "Query": "select col, count(*), weight_string(col) from `user` group by col order by col asc", + "Query": "select col, count(*), weight_string(col) from `user` group by col, weight_string(col) order by col asc", "ResultColumns": 2, "Table": "`user`" } @@ -441,9 +441,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select `name`, count(*), weight_string(`name`) from `user` where 1 != 1 group by `name`", + "FieldQuery": "select `name`, count(*), weight_string(`name`) from `user` where 1 != 1 group by `name`, weight_string(`name`)", "OrderBy": "0 ASC", - "Query": "select `name`, count(*), weight_string(`name`) from `user` group by `name` order by `name` asc", + "Query": "select `name`, count(*), weight_string(`name`) from `user` group by `name`, weight_string(`name`) order by `name` asc", "ResultColumns": 2, "Table": "`user`" } @@ -648,9 +648,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select col, weight_string(col) from `user` where 1 != 1 group by col", + "FieldQuery": "select col, weight_string(col) from `user` where 1 != 1 group by col, weight_string(col)", "OrderBy": "0 ASC", - "Query": "select col, weight_string(col) from `user` group by col order by col asc", + "Query": "select col, weight_string(col) from `user` group by col, weight_string(col) order by col asc", "ResultColumns": 1, "Table": "`user`" } @@ -694,9 +694,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select col, count(distinct id), weight_string(col) from `user` where 1 != 1 group by col", + "FieldQuery": "select col, count(distinct id), weight_string(col) from `user` where 1 != 1 group by col, weight_string(col)", "OrderBy": "0 ASC", - "Query": "select col, count(distinct id), weight_string(col) from `user` group by col order by col asc", + "Query": "select col, count(distinct id), weight_string(col) from `user` group by col, weight_string(col) order by col asc", "ResultColumns": 2, "Table": "`user`" } @@ -722,9 +722,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select col1, col2, weight_string(col1), weight_string(col2) from `user` where 1 != 1 group by col1, col2", + "FieldQuery": "select col1, col2, weight_string(col1), weight_string(col2) from `user` where 1 != 1 group by col1, col2, weight_string(col1), weight_string(col2)", "OrderBy": "0 ASC, 1 ASC", - "Query": "select col1, col2, weight_string(col1), weight_string(col2) from `user` group by col1, col2 order by col1 asc, col2 asc", + "Query": "select col1, col2, weight_string(col1), weight_string(col2) from `user` group by col1, col2, weight_string(col1), weight_string(col2) order by col1 asc, col2 asc", "ResultColumns": 2, "Table": "`user`" } @@ -749,9 +749,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select col2, weight_string(col2) from `user` where 1 != 1 group by col2", + "FieldQuery": "select col2, weight_string(col2) from `user` where 1 != 1 group by col2, weight_string(col2)", "OrderBy": "0 ASC", - "Query": "select col2, weight_string(col2) from `user` group by col2 order by col2 asc", + "Query": "select col2, weight_string(col2) from `user` group by col2, weight_string(col2) order by col2 asc", "ResultColumns": 1, "Table": "`user`" } @@ -777,9 +777,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select col1, col2, weight_string(col1), weight_string(col2) from `user` where 1 != 1 group by col1, col2", + "FieldQuery": "select col1, col2, weight_string(col1), weight_string(col2) from `user` where 1 != 1 group by col1, col2, weight_string(col1), weight_string(col2)", "OrderBy": "0 ASC, 1 ASC", - "Query": "select col1, col2, weight_string(col1), weight_string(col2) from `user` group by col1, col2 order by col1 asc, col2 asc", + "Query": "select col1, col2, weight_string(col1), weight_string(col2) from `user` group by col1, col2, weight_string(col1), weight_string(col2) order by col1 asc, col2 asc", "ResultColumns": 2, "Table": "`user`" } @@ -805,9 +805,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select col1, col2, weight_string(col1), weight_string(col2) from `user` where 1 != 1 group by col1, col2", + "FieldQuery": "select col1, col2, weight_string(col1), weight_string(col2) from `user` where 1 != 1 group by col1, col2, weight_string(col1), weight_string(col2)", "OrderBy": "0 ASC, 1 ASC", - "Query": "select col1, col2, weight_string(col1), weight_string(col2) from `user` group by col1, col2 order by col1 asc, col2 asc", + "Query": "select col1, col2, weight_string(col1), weight_string(col2) from `user` group by col1, col2, weight_string(col1), weight_string(col2) order by col1 asc, col2 asc", "ResultColumns": 2, "Table": "`user`" } @@ -833,9 +833,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select col1, min(distinct col2), weight_string(col1) from `user` where 1 != 1 group by col1", + "FieldQuery": "select col1, min(distinct col2), weight_string(col1) from `user` where 1 != 1 group by col1, weight_string(col1)", "OrderBy": "0 ASC", - "Query": "select col1, min(distinct col2), weight_string(col1) from `user` group by col1 order by col1 asc", + "Query": "select col1, min(distinct col2), weight_string(col1) from `user` group by col1, weight_string(col1) order by col1 asc", "ResultColumns": 2, "Table": "`user`" } @@ -866,9 +866,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select col1, col2, weight_string(col1), weight_string(col2) from `user` where 1 != 1 group by col1, col2", + "FieldQuery": "select col1, col2, weight_string(col1), weight_string(col2) from `user` where 1 != 1 group by col1, col2, weight_string(col1), weight_string(col2)", "OrderBy": "0 ASC, 1 ASC", - "Query": "select col1, col2, weight_string(col1), weight_string(col2) from `user` group by col1, col2 order by col1 asc, col2 asc", + "Query": "select col1, col2, weight_string(col1), weight_string(col2) from `user` group by col1, col2, weight_string(col1), weight_string(col2) order by col1 asc, col2 asc", "ResultColumns": 2, "Table": "`user`" } @@ -900,9 +900,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, count(*), weight_string(b), weight_string(a) from `user` where 1 != 1 group by b, a", + "FieldQuery": "select a, b, count(*), weight_string(b), weight_string(a) from `user` where 1 != 1 group by b, a, weight_string(b), weight_string(a)", "OrderBy": "1 ASC, 0 ASC", - "Query": "select a, b, count(*), weight_string(b), weight_string(a) from `user` group by b, a order by b asc, a asc", + "Query": "select a, b, count(*), weight_string(b), weight_string(a) from `user` group by b, a, weight_string(b), weight_string(a) order by b asc, a asc", "ResultColumns": 3, "Table": "`user`" } @@ -928,9 +928,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, count(*), weight_string(b), weight_string(a) from `user` where 1 != 1 group by 2, 1", + "FieldQuery": "select a, b, count(*), weight_string(b), weight_string(a) from `user` where 1 != 1 group by 2, 1, weight_string(b), weight_string(a)", "OrderBy": "1 ASC, 0 ASC", - "Query": "select a, b, count(*), weight_string(b), weight_string(a) from `user` group by 2, 1 order by b asc, a asc", + "Query": "select a, b, count(*), weight_string(b), weight_string(a) from `user` group by 2, 1, weight_string(b), weight_string(a) order by b asc, a asc", "ResultColumns": 3, "Table": "`user`" } @@ -956,9 +956,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, count(*), weight_string(b), weight_string(a) from `user` where 1 != 1 group by b, a", + "FieldQuery": "select a, b, count(*), weight_string(b), weight_string(a) from `user` where 1 != 1 group by b, a, weight_string(b), weight_string(a)", "OrderBy": "1 ASC, 0 ASC", - "Query": "select a, b, count(*), weight_string(b), weight_string(a) from `user` group by b, a order by b asc, a asc", + "Query": "select a, b, count(*), weight_string(b), weight_string(a) from `user` group by b, a, weight_string(b), weight_string(a) order by b asc, a asc", "ResultColumns": 3, "Table": "`user`" } @@ -983,9 +983,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select col, weight_string(col) from `user` where 1 != 1 group by 1", + "FieldQuery": "select col, weight_string(col) from `user` where 1 != 1 group by 1, weight_string(col)", "OrderBy": "0 ASC", - "Query": "select col, weight_string(col) from `user` group by 1 order by col asc", + "Query": "select col, weight_string(col) from `user` group by 1, weight_string(col) order by col asc", "ResultColumns": 1, "Table": "`user`" } @@ -1044,9 +1044,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, c, d, count(*), weight_string(a), weight_string(b), weight_string(c) from `user` where 1 != 1 group by 1, 2, 3", + "FieldQuery": "select a, b, c, d, count(*), weight_string(a), weight_string(b), weight_string(c) from `user` where 1 != 1 group by 1, 2, 3, weight_string(a), weight_string(b), weight_string(c)", "OrderBy": "0 ASC, 1 ASC, 2 ASC", - "Query": "select a, b, c, d, count(*), weight_string(a), weight_string(b), weight_string(c) from `user` group by 1, 2, 3 order by 1 asc, 2 asc, 3 asc", + "Query": "select a, b, c, d, count(*), weight_string(a), weight_string(b), weight_string(c) from `user` group by 1, 2, 3, weight_string(a), weight_string(b), weight_string(c) order by 1 asc, 2 asc, 3 asc", "ResultColumns": 5, "Table": "`user`" } @@ -1072,9 +1072,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, c, d, count(*), weight_string(a), weight_string(b), weight_string(c) from `user` where 1 != 1 group by 1, 2, 3", + "FieldQuery": "select a, b, c, d, count(*), weight_string(a), weight_string(b), weight_string(c) from `user` where 1 != 1 group by 1, 2, 3, weight_string(a), weight_string(b), weight_string(c)", "OrderBy": "0 ASC, 1 ASC, 2 ASC", - "Query": "select a, b, c, d, count(*), weight_string(a), weight_string(b), weight_string(c) from `user` group by 1, 2, 3 order by a asc, b asc, c asc", + "Query": "select a, b, c, d, count(*), weight_string(a), weight_string(b), weight_string(c) from `user` group by 1, 2, 3, weight_string(a), weight_string(b), weight_string(c) order by a asc, b asc, c asc", "ResultColumns": 5, "Table": "`user`" } @@ -1100,9 +1100,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, c, d, count(*), weight_string(d), weight_string(b), weight_string(a), weight_string(c) from `user` where 1 != 1 group by 1, 2, 3, 4", + "FieldQuery": "select a, b, c, d, count(*), weight_string(d), weight_string(b), weight_string(a), weight_string(c) from `user` where 1 != 1 group by 1, 2, 3, 4, weight_string(d), weight_string(b), weight_string(a), weight_string(c)", "OrderBy": "3 ASC, 1 ASC, 0 ASC, 2 ASC", - "Query": "select a, b, c, d, count(*), weight_string(d), weight_string(b), weight_string(a), weight_string(c) from `user` group by 1, 2, 3, 4 order by d asc, b asc, a asc, c asc", + "Query": "select a, b, c, d, count(*), weight_string(d), weight_string(b), weight_string(a), weight_string(c) from `user` group by 1, 2, 3, 4, weight_string(d), weight_string(b), weight_string(a), weight_string(c) order by d asc, b asc, a asc, c asc", "ResultColumns": 5, "Table": "`user`" } @@ -1128,9 +1128,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, c, d, count(*), weight_string(d), weight_string(b), weight_string(a), weight_string(c) from `user` where 1 != 1 group by 3, 2, 1, 4", + "FieldQuery": "select a, b, c, d, count(*), weight_string(d), weight_string(b), weight_string(a), weight_string(c) from `user` where 1 != 1 group by 3, 2, 1, 4, weight_string(d), weight_string(b), weight_string(a), weight_string(c)", "OrderBy": "3 ASC, 1 ASC, 0 ASC, 2 ASC", - "Query": "select a, b, c, d, count(*), weight_string(d), weight_string(b), weight_string(a), weight_string(c) from `user` group by 3, 2, 1, 4 order by d asc, b asc, a asc, c asc", + "Query": "select a, b, c, d, count(*), weight_string(d), weight_string(b), weight_string(a), weight_string(c) from `user` group by 3, 2, 1, 4, weight_string(d), weight_string(b), weight_string(a), weight_string(c) order by d asc, b asc, a asc, c asc", "ResultColumns": 5, "Table": "`user`" } @@ -1156,9 +1156,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, c, count(*), weight_string(a), weight_string(c), weight_string(b) from `user` where 1 != 1 group by 3, 2, 1", + "FieldQuery": "select a, b, c, count(*), weight_string(a), weight_string(c), weight_string(b) from `user` where 1 != 1 group by 3, 2, 1, weight_string(a), weight_string(c), weight_string(b)", "OrderBy": "0 DESC, 2 DESC, 1 ASC", - "Query": "select a, b, c, count(*), weight_string(a), weight_string(c), weight_string(b) from `user` group by 3, 2, 1 order by 1 desc, 3 desc, b asc", + "Query": "select a, b, c, count(*), weight_string(a), weight_string(c), weight_string(b) from `user` group by 3, 2, 1, weight_string(a), weight_string(c), weight_string(b) order by 1 desc, 3 desc, b asc", "ResultColumns": 4, "Table": "`user`" } @@ -1192,9 +1192,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select col, count(*), weight_string(col) from `user` where 1 != 1 group by col", + "FieldQuery": "select col, count(*), weight_string(col) from `user` where 1 != 1 group by col, weight_string(col)", "OrderBy": "0 ASC", - "Query": "select col, count(*), weight_string(col) from `user` group by col order by col asc limit :__upper_limit", + "Query": "select col, count(*), weight_string(col) from `user` group by col, weight_string(col) order by col asc limit :__upper_limit", "ResultColumns": 2, "Table": "`user`" } @@ -1319,9 +1319,9 @@ Gen4 plan same as above "Name": "user", "Sharded": true }, - "FieldQuery": "select a, count(*), weight_string(a) from `user` where 1 != 1 group by a", + "FieldQuery": "select a, count(*), weight_string(a) from `user` where 1 != 1 group by a, weight_string(a)", "OrderBy": "0 ASC, 0 ASC", - "Query": "select a, count(*), weight_string(a) from `user` group by a order by a asc, a asc", + "Query": "select a, count(*), weight_string(a) from `user` group by a, weight_string(a) order by a asc, a asc", "ResultColumns": 2, "Table": "`user`" } diff --git a/go/vt/vtgate/planbuilder/testdata/ddl_cases.txt b/go/vt/vtgate/planbuilder/testdata/ddl_cases.txt index accb0316f37..ba1090f2f98 100644 --- a/go/vt/vtgate/planbuilder/testdata/ddl_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/ddl_cases.txt @@ -413,3 +413,19 @@ Gen4 plan same as above } } Gen4 plan same as above + +# create table with function as a default value +"create table function_default (x varchar(25) DEFAULT (TRIM(' check ')))" +{ + "QueryType": "DDL", + "Original": "create table function_default (x varchar(25) DEFAULT (TRIM(' check ')))", + "Instructions": { + "OperatorType": "DDL", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "Query": "create table function_default (\n\tx varchar(25) default (TRIM(' check '))\n)" + } +} +Gen4 plan same as above diff --git a/go/vt/vtgate/planbuilder/testdata/dml_cases.txt b/go/vt/vtgate/planbuilder/testdata/dml_cases.txt index 34d2742f363..1ebbd26fac9 100644 --- a/go/vt/vtgate/planbuilder/testdata/dml_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/dml_cases.txt @@ -22,7 +22,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "update m1 set val = 1" + "Query": "update m1 set val = 1", + "Table": "m1" } } Gen4 plan same as above @@ -41,7 +42,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "update unsharded set val = 1" + "Query": "update unsharded set val = 1", + "Table": "unsharded" } } Gen4 plan same as above @@ -60,7 +62,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "update unsharded set col = (select col from unsharded limit 1)" + "Query": "update unsharded set col = (select col from unsharded limit 1)", + "Table": "unsharded" } } Gen4 plan same as above @@ -79,7 +82,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "update unsharded set col = (select id from unsharded union select id from unsharded)" + "Query": "update unsharded set col = (select id from unsharded union select id from unsharded)", + "Table": "unsharded" } } Gen4 plan same as above @@ -98,7 +102,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "update unsharded set col = (select id from unsharded as a join unsharded as b on a.id = b.id)" + "Query": "update unsharded set col = (select id from unsharded as a join unsharded as b on a.id = b.id)", + "Table": "unsharded" } } Gen4 plan same as above @@ -117,7 +122,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "update unsharded as foo left join (select id from unsharded where col is not null order by col desc limit 10) as keepers on foo.id = keepers.id set col1 = 'asdf' where keepers.id is null and foo.col is not null and foo.col \u003c 1000" + "Query": "update unsharded as foo left join (select id from unsharded where col is not null order by col desc limit 10) as keepers on foo.id = keepers.id set col1 = 'asdf' where keepers.id is null and foo.col is not null and foo.col \u003c 1000", + "Table": "unsharded" } } Gen4 plan same as above @@ -160,7 +166,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "update unsharded_a set a = (select a from unsharded as route2)" + "Query": "update unsharded_a set a = (select a from unsharded as route2)", + "Table": "unsharded, unsharded_a" } } Gen4 plan same as above @@ -179,7 +186,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "delete from unsharded" + "Query": "delete from unsharded", + "Table": "unsharded" } } Gen4 plan same as above @@ -461,7 +469,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "delete a from unsharded_a as a, unsharded_b as b where a.id = b.id and b.val = 1" + "Query": "delete a from unsharded_a as a, unsharded_b as b where a.id = b.id and b.val = 1", + "Table": "unsharded_a, unsharded_b" } } Gen4 plan same as above @@ -480,7 +489,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "delete a from unsharded_a as a join unsharded_b as b on a.id = b.id where b.val = 1" + "Query": "delete a from unsharded_a as a join unsharded_b as b on a.id = b.id where b.val = 1", + "Table": "unsharded_a, unsharded_b" } } Gen4 plan same as above @@ -499,7 +509,28 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "delete foo from unsharded as foo left join (select id from unsharded where col is not null order by col desc limit 10) as keepers on foo.id = keepers.id where keepers.id is null and foo.col is not null and foo.col \u003c 1000" + "Query": "delete foo from unsharded as foo left join (select id from unsharded where col is not null order by col desc limit 10) as keepers on foo.id = keepers.id where keepers.id is null and foo.col is not null and foo.col \u003c 1000", + "Table": "unsharded" + } +} +Gen4 plan same as above + +#delete with join from multi table join subquery +"delete foo from unsharded as foo left join (select id from unsharded a join unsharded_b b on a.user_id = b.user_id) as keepers on foo.id = keepers.id where keepers.id is null and foo.col is not null and foo.col < 1000" +{ + "QueryType": "DELETE", + "Original": "delete foo from unsharded as foo left join (select id from unsharded a join unsharded_b b on a.user_id = b.user_id) as keepers on foo.id = keepers.id where keepers.id is null and foo.col is not null and foo.col \u003c 1000", + "Instructions": { + "OperatorType": "Delete", + "Variant": "Unsharded", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "TargetTabletType": "MASTER", + "MultiShardAutocommit": false, + "Query": "delete foo from unsharded as foo left join (select id from unsharded as a join unsharded_b as b on a.user_id = b.user_id) as keepers on foo.id = keepers.id where keepers.id is null and foo.col is not null and foo.col \u003c 1000", + "Table": "unsharded, unsharded, unsharded_b" } } Gen4 plan same as above @@ -544,7 +575,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "delete from unsharded_a where a = (select a from unsharded as route2)" + "Query": "delete from unsharded_a where a = (select a from unsharded as route2)", + "Table": "unsharded, unsharded_a" } } Gen4 plan same as above @@ -587,7 +619,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "update unsharded_a as a join unsharded_b as b on a.id = b.id set a.val = 'foo' where b.val = 1" + "Query": "update unsharded_a as a join unsharded_b as b on a.id = b.id set a.val = 'foo' where b.val = 1", + "Table": "unsharded_a, unsharded_b" } } Gen4 plan same as above @@ -606,7 +639,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "update unsharded_a as a, unsharded_b as b set a.val = 'foo' where a.id = b.id and b.val = 1" + "Query": "update unsharded_a as a, unsharded_b as b set a.val = 'foo' where a.id = b.id and b.val = 1", + "Table": "unsharded_a, unsharded_b" } } Gen4 plan same as above @@ -1922,7 +1956,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "update unsharded set col = (select id from unsharded_a where id = unsharded.col) where col = (select id from unsharded_b)" + "Query": "update unsharded set col = (select id from unsharded_a where id = unsharded.col) where col = (select id from unsharded_b)", + "Table": "unsharded, unsharded_a, unsharded_b" } } Gen4 plan same as above @@ -1941,7 +1976,8 @@ Gen4 plan same as above }, "TargetTabletType": "MASTER", "MultiShardAutocommit": false, - "Query": "delete from unsharded where col = (select id from unsharded_a where id = unsharded.col)" + "Query": "delete from unsharded where col = (select id from unsharded_a where id = unsharded.col)", + "Table": "unsharded, unsharded_a" } } Gen4 plan same as above @@ -2427,3 +2463,185 @@ Gen4 plan same as above "delete user from (select * from user) music where id = 1" "Unknown table 'user' in MULTI DELETE" Gen4 plan same as above + +"INSERT INTO main.user_privacy_consents (user_id, accepted_at) SELECT user_id, accepted_at FROM (SELECT 1 as user_id, 1629194864 as accepted_at) AS tmp WHERE NOT EXISTS (SELECT user_id FROM main.user_privacy_consents WHERE user_id = 1)" +{ + "QueryType": "INSERT", + "Original": "INSERT INTO main.user_privacy_consents (user_id, accepted_at) SELECT user_id, accepted_at FROM (SELECT 1 as user_id, 1629194864 as accepted_at) AS tmp WHERE NOT EXISTS (SELECT user_id FROM main.user_privacy_consents WHERE user_id = 1)", + "Instructions": { + "OperatorType": "Insert", + "Variant": "Unsharded", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "TargetTabletType": "MASTER", + "MultiShardAutocommit": false, + "Query": "insert into user_privacy_consents(user_id, accepted_at) select user_id, accepted_at from (select 1 as user_id, 1629194864 as accepted_at from dual) as tmp where not exists (select user_id from user_privacy_consents where user_id = 1)", + "TableName": "user_privacy_consents" + } +} +Gen4 plan same as above + +# Delete on backfilling unique lookup vindex should be a scatter +"delete from zlookup_unique.t1 where c2 = 20" +{ + "QueryType": "DELETE", + "Original": "delete from zlookup_unique.t1 where c2 = 20", + "Instructions": { + "OperatorType": "Delete", + "Variant": "Scatter", + "Keyspace": { + "Name": "zlookup_unique", + "Sharded": true + }, + "TargetTabletType": "MASTER", + "KsidVindex": "xxhash", + "MultiShardAutocommit": false, + "OwnedVindexQuery": "select c1, c2, c3 from t1 where c2 = 20 for update", + "Query": "delete from t1 where c2 = 20", + "Table": "t1" + } +} +Gen4 plan same as above + +# Update on backfilling unique lookup vindex should be a scatter +"update zlookup_unique.t1 set c2 = 1 where c2 = 20" +{ + "QueryType": "UPDATE", + "Original": "update zlookup_unique.t1 set c2 = 1 where c2 = 20", + "Instructions": { + "OperatorType": "Update", + "Variant": "Scatter", + "Keyspace": { + "Name": "zlookup_unique", + "Sharded": true + }, + "TargetTabletType": "MASTER", + "ChangedVindexValues": [ + "lookup_t1:3" + ], + "KsidVindex": "xxhash", + "MultiShardAutocommit": false, + "OwnedVindexQuery": "select c1, c2, c3, c2 = 1 from t1 where c2 = 20 for update", + "Query": "update t1 set c2 = 1 where c2 = 20", + "Table": "t1" + } +} +Gen4 plan same as above + +# Delete on backfilling and non-backfilling unique lookup vindexes should be a delete equal +"delete from zlookup_unique.t1 where c2 = 10 and c3 = 20" +{ + "QueryType": "DELETE", + "Original": "delete from zlookup_unique.t1 where c2 = 10 and c3 = 20", + "Instructions": { + "OperatorType": "Delete", + "Variant": "Equal", + "Keyspace": { + "Name": "zlookup_unique", + "Sharded": true + }, + "TargetTabletType": "MASTER", + "KsidVindex": "xxhash", + "MultiShardAutocommit": false, + "OwnedVindexQuery": "select c1, c2, c3 from t1 where c2 = 10 and c3 = 20 for update", + "Query": "delete from t1 where c2 = 10 and c3 = 20", + "Table": "t1", + "Values": [ + 20 + ], + "Vindex": "lookup_t1_2" + } +} +Gen4 plan same as above + +# Update on backfilling and non-backfilling unique lookup vindexes should be an equal +"update zlookup_unique.t1 set c2 = 1 where c2 = 10 and c3 = 20" +{ + "QueryType": "UPDATE", + "Original": "update zlookup_unique.t1 set c2 = 1 where c2 = 10 and c3 = 20", + "Instructions": { + "OperatorType": "Update", + "Variant": "Equal", + "Keyspace": { + "Name": "zlookup_unique", + "Sharded": true + }, + "TargetTabletType": "MASTER", + "ChangedVindexValues": [ + "lookup_t1:3" + ], + "KsidVindex": "xxhash", + "MultiShardAutocommit": false, + "OwnedVindexQuery": "select c1, c2, c3, c2 = 1 from t1 where c2 = 10 and c3 = 20 for update", + "Query": "update t1 set c2 = 1 where c2 = 10 and c3 = 20", + "Table": "t1", + "Values": [ + 20 + ], + "Vindex": "lookup_t1_2" + } +} +Gen4 plan same as above + +# Delete EQUAL and IN on backfilling and non-backfilling unique lookup vindexes should be a delete IN +"delete from zlookup_unique.t1 where c2 = 10 and c3 in (20, 21)" +{ + "QueryType": "DELETE", + "Original": "delete from zlookup_unique.t1 where c2 = 10 and c3 in (20, 21)", + "Instructions": { + "OperatorType": "Delete", + "Variant": "In", + "Keyspace": { + "Name": "zlookup_unique", + "Sharded": true + }, + "TargetTabletType": "MASTER", + "KsidVindex": "xxhash", + "MultiShardAutocommit": false, + "OwnedVindexQuery": "select c1, c2, c3 from t1 where c2 = 10 and c3 in (20, 21) for update", + "Query": "delete from t1 where c2 = 10 and c3 in (20, 21)", + "Table": "t1", + "Values": [ + [ + 20, + 21 + ] + ], + "Vindex": "lookup_t1_2" + } +} +Gen4 plan same as above + +# Update EQUAL and IN on backfilling and non-backfilling unique lookup vindexes should be an update IN +"update zlookup_unique.t1 set c2 = 1 where c2 = 10 and c3 in (20, 21)" +{ + "QueryType": "UPDATE", + "Original": "update zlookup_unique.t1 set c2 = 1 where c2 = 10 and c3 in (20, 21)", + "Instructions": { + "OperatorType": "Update", + "Variant": "In", + "Keyspace": { + "Name": "zlookup_unique", + "Sharded": true + }, + "TargetTabletType": "MASTER", + "ChangedVindexValues": [ + "lookup_t1:3" + ], + "KsidVindex": "xxhash", + "MultiShardAutocommit": false, + "OwnedVindexQuery": "select c1, c2, c3, c2 = 1 from t1 where c2 = 10 and c3 in (20, 21) for update", + "Query": "update t1 set c2 = 1 where c2 = 10 and c3 in (20, 21)", + "Table": "t1", + "Values": [ + [ + 20, + 21 + ] + ], + "Vindex": "lookup_t1_2" + } +} +Gen4 plan same as above diff --git a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt index c7642bf5369..aa75d27e524 100644 --- a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt @@ -557,7 +557,7 @@ Gen4 plan same as above }, "FieldQuery": "select user_extra.id from `user` join user_extra on `user`.id = user_extra.user_id where 1 != 1", "Query": "select user_extra.id from `user` join user_extra on `user`.id = user_extra.user_id where `user`.id = 5", - "Table": "`user`", + "Table": "`user`, user_extra", "Values": [ 5 ], @@ -598,7 +598,7 @@ Gen4 plan same as above }, "FieldQuery": "select user_extra.id from `user` join user_extra on `user`.id = user_extra.user_id where 1 != 1", "Query": "select user_extra.id from `user` join user_extra on `user`.id = user_extra.user_id where user_extra.user_id = 5", - "Table": "`user`", + "Table": "`user`, user_extra", "Values": [ 5 ], @@ -639,7 +639,7 @@ Gen4 plan same as above }, "FieldQuery": "select user_extra.id from `user` left join user_extra on `user`.id = user_extra.user_id where 1 != 1", "Query": "select user_extra.id from `user` left join user_extra on `user`.id = user_extra.user_id where `user`.id = 5", - "Table": "`user`", + "Table": "`user`, user_extra", "Values": [ 5 ], @@ -662,7 +662,7 @@ Gen4 plan same as above }, "FieldQuery": "select user_extra.id from `user` left join user_extra on `user`.id = user_extra.user_id where 1 != 1", "Query": "select user_extra.id from `user` left join user_extra on `user`.id = user_extra.user_id where user_extra.user_id = 5", - "Table": "`user`", + "Table": "`user`, user_extra", "Values": [ 5 ], @@ -679,7 +679,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -721,7 +721,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -763,7 +763,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -808,7 +808,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -850,7 +850,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -884,7 +884,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1081,7 +1081,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -1115,7 +1115,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "unsharded_`user`", + "TableName": "unsharded, `user`", "Inputs": [ { "OperatorType": "Route", @@ -1183,7 +1183,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select * from information_schema.a where 1 != 1", - "Query": "select * from information_schema.a where id in (select * from information_schema.b)" + "Query": "select * from information_schema.a where id in (select * from information_schema.b)", + "Table": "information_schema.a" } } @@ -1196,7 +1197,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "user_extra_`user`", + "TableName": "user_extra, `user`", "Inputs": [ { "OperatorType": "Route", @@ -1240,7 +1241,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "user_extra_`user`", + "TableName": "user_extra, `user`", "Inputs": [ { "OperatorType": "Route", @@ -1281,7 +1282,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "user_extra_`user`", + "TableName": "user_extra, `user`", "Inputs": [ { "OperatorType": "Route", @@ -1698,7 +1699,7 @@ Gen4 plan same as above }, "FieldQuery": "select user_extra.Id from `user` join user_extra on `user`.iD = user_extra.User_Id where 1 != 1", "Query": "select user_extra.Id from `user` join user_extra on `user`.iD = user_extra.User_Id where `user`.Id = 5", - "Table": "`user`", + "Table": "`user`, user_extra", "Values": [ 5 ], @@ -1925,7 +1926,8 @@ Gen4 plan same as above }, "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1", "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname and TABLE_SCHEMA = :__vtschemaname", - "SysTableTableSchema": "[VARBINARY(\"user\"), VARBINARY(\"main\")]" + "SysTableTableSchema": "[VARBINARY(\"user\"), VARBINARY(\"main\")]", + "Table": "INFORMATION_SCHEMA.`TABLES`" } } @@ -1942,7 +1944,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1", - "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = database()" + "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = database()", + "Table": "INFORMATION_SCHEMA.`TABLES`" } } @@ -1960,7 +1963,8 @@ Gen4 plan same as above }, "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1", "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname", - "SysTableTableSchema": "[VARBINARY(\"ks\")]" + "SysTableTableSchema": "[VARBINARY(\"ks\")]", + "Table": "INFORMATION_SCHEMA.`TABLES`" } } @@ -1977,7 +1981,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1", - "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = 'ks' or TABLE_SCHEMA = 'main'" + "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = 'ks' or TABLE_SCHEMA = 'main'", + "Table": "INFORMATION_SCHEMA.`TABLES`" } } @@ -1996,7 +2001,8 @@ Gen4 plan same as above "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1", "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname and TABLE_NAME = :__vttablename", "SysTableTableName": "[VARBINARY(\"route1\")]", - "SysTableTableSchema": "[VARBINARY(\"ks\")]" + "SysTableTableSchema": "[VARBINARY(\"ks\")]", + "Table": "INFORMATION_SCHEMA.`TABLES`" } } @@ -2014,7 +2020,8 @@ Gen4 plan same as above }, "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1", "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname and other_column = 42", - "SysTableTableSchema": "[VARBINARY(\"ks\")]" + "SysTableTableSchema": "[VARBINARY(\"ks\")]", + "Table": "INFORMATION_SCHEMA.`TABLES`" } } @@ -2096,7 +2103,8 @@ Gen4 plan same as above }, "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1", "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname and (other_column = 42 or TABLE_SCHEMA = 'ks') and (other_column = 42 or foobar = 'value')", - "SysTableTableSchema": "[VARBINARY(\"ks\")]" + "SysTableTableSchema": "[VARBINARY(\"ks\")]", + "Table": "INFORMATION_SCHEMA.`TABLES`" } } diff --git a/go/vt/vtgate/planbuilder/testdata/from_cases.txt b/go/vt/vtgate/planbuilder/testdata/from_cases.txt index 3a0e1b308de..5a568a315f8 100644 --- a/go/vt/vtgate/planbuilder/testdata/from_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/from_cases.txt @@ -87,7 +87,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select col from information_schema.foo where 1 != 1", - "Query": "select col from information_schema.foo" + "Query": "select col from information_schema.foo", + "Table": "information_schema.foo" } } @@ -133,7 +134,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_music", + "TableName": "`user`, music", "Inputs": [ { "OperatorType": "Route", @@ -271,7 +272,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_music", + "TableName": "`user`, music", "Inputs": [ { "OperatorType": "Route", @@ -332,7 +333,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select a.id, b.id from information_schema.a as a, information_schema.b as b where 1 != 1", - "Query": "select a.id, b.id from information_schema.a as a, information_schema.b as b" + "Query": "select a.id, b.id from information_schema.a as a, information_schema.b as b", + "Table": "information_schema.a, information_schema.b" } } @@ -383,7 +385,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "LeftJoin", "JoinColumnIndexes": "-1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -417,7 +419,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "LeftJoin", "JoinColumnIndexes": "-2", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -454,13 +456,13 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "LeftJoin", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_unsharded_unsharded", + "TableName": "`user`, unsharded, unsharded", "Inputs": [ { "OperatorType": "Join", "Variant": "LeftJoin", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -507,13 +509,13 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "LeftJoin", "JoinColumnIndexes": "-2,1", - "TableName": "`user`_unsharded_unsharded", + "TableName": "`user`, unsharded, unsharded", "Inputs": [ { "OperatorType": "Join", "Variant": "LeftJoin", "JoinColumnIndexes": "1,-1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -563,7 +565,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "LeftJoin", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra_unsharded", + "TableName": "`user`, user_extra, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -579,7 +581,7 @@ Gen4 plan same as above { "OperatorType": "Join", "Variant": "LeftJoin", - "TableName": "user_extra_unsharded", + "TableName": "user_extra, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -615,7 +617,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "LeftJoin", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra_unsharded", + "TableName": "`user`, user_extra, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -631,7 +633,7 @@ Gen4 plan same as above { "OperatorType": "Join", "Variant": "LeftJoin", - "TableName": "user_extra_unsharded", + "TableName": "user_extra, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -740,13 +742,13 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_unsharded_unsharded", + "TableName": "`user`, unsharded, unsharded", "Inputs": [ { "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -793,7 +795,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -831,7 +833,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -865,7 +867,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -902,7 +904,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_`user`_unsharded", + "TableName": "`user`, `user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -918,7 +920,7 @@ Gen4 plan same as above { "OperatorType": "Join", "Variant": "Join", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -954,7 +956,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_`user`_unsharded", + "TableName": "`user`, `user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -971,7 +973,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -1033,7 +1035,7 @@ Gen4 plan same as above }, "FieldQuery": "select `user`.col from `user` join user_extra on `user`.id = user_extra.user_id where 1 != 1", "Query": "select `user`.col from `user` join user_extra on `user`.id = user_extra.user_id", - "Table": "`user`" + "Table": "`user`, user_extra" } } { @@ -1066,7 +1068,7 @@ Gen4 plan same as above }, "FieldQuery": "select `user`.col from `user` join user_extra on `user`.id = user_extra.user_id where 1 != 1", "Query": "select `user`.col from `user` join user_extra on `user`.id = user_extra.user_id", - "Table": "`user`" + "Table": "`user`, user_extra" } } { @@ -1099,7 +1101,7 @@ Gen4 plan same as above }, "FieldQuery": "select `user`.col from `user` join user_extra on `user`.col between 1 and 2 and `user`.id = user_extra.user_id where 1 != 1", "Query": "select `user`.col from `user` join user_extra on `user`.col between 1 and 2 and `user`.id = user_extra.user_id", - "Table": "`user`" + "Table": "`user`, user_extra" } } { @@ -1132,7 +1134,7 @@ Gen4 plan same as above }, "FieldQuery": "select `user`.col from `user` join user_extra on user_extra.user_id = `user`.id where 1 != 1", "Query": "select `user`.col from `user` join user_extra on user_extra.user_id = `user`.id", - "Table": "`user`" + "Table": "`user`, user_extra" } } { @@ -1165,7 +1167,7 @@ Gen4 plan same as above }, "FieldQuery": "select `user`.col from `user` join user_extra on `user`.id = 5 and `user`.id = user_extra.user_id where 1 != 1", "Query": "select `user`.col from `user` join user_extra on `user`.id = 5 and `user`.id = user_extra.user_id", - "Table": "`user`", + "Table": "`user`, user_extra", "Values": [ 5 ], @@ -1201,7 +1203,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1238,7 +1240,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1280,7 +1282,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1322,7 +1324,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1356,7 +1358,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "user_extra_`user`", + "TableName": "user_extra, `user`", "Inputs": [ { "OperatorType": "Route", @@ -1397,7 +1399,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "user_extra_`user`", + "TableName": "user_extra, `user`", "Inputs": [ { "OperatorType": "Route", @@ -1435,7 +1437,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-2", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1481,7 +1483,7 @@ Gen4 plan same as above }, "FieldQuery": "select `user`.col from `user` join ref where 1 != 1", "Query": "select `user`.col from `user` join ref", - "Table": "`user`" + "Table": "`user`, ref" } } @@ -1517,7 +1519,7 @@ Gen4 plan same as above }, "FieldQuery": "select ref.col from ref join `user` where 1 != 1", "Query": "select ref.col from ref join `user`", - "Table": "`user`" + "Table": "`user`, ref" } } @@ -1536,7 +1538,7 @@ Gen4 plan same as above }, "FieldQuery": "select ref.col from ref join (select aa from `user` where 1 != 1) as `user` where 1 != 1", "Query": "select ref.col from ref join (select aa from `user` where `user`.id = 1) as `user`", - "Table": "`user`", + "Table": "`user`, ref", "Values": [ 1 ], @@ -1553,7 +1555,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "unsharded_user_extra", + "TableName": "unsharded, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1618,7 +1620,7 @@ Gen4 plan same as above }, "FieldQuery": "select t.id from (select id from `user` where 1 != 1) as t join user_extra on t.id = user_extra.user_id where 1 != 1", "Query": "select t.id from (select id from `user` where id = 5) as t join user_extra on t.id = user_extra.user_id", - "Table": "`user`", + "Table": "`user`, user_extra", "Values": [ 5 ], @@ -1640,7 +1642,7 @@ Gen4 plan same as above }, "FieldQuery": "select t.id from (select `user`.id from `user` where 1 != 1) as t join user_extra on t.id = user_extra.user_id where 1 != 1", "Query": "select t.id from (select `user`.id from `user` where `user`.id = 5) as t join user_extra on t.id = user_extra.user_id", - "Table": "`user`", + "Table": "`user`, user_extra", "Values": [ 5 ], @@ -1666,7 +1668,7 @@ Gen4 plan same as above }, "FieldQuery": "select t.id from user_extra join (select id from `user` where 1 != 1) as t on t.id = user_extra.user_id where 1 != 1", "Query": "select t.id from user_extra join (select id from `user` where id = 5) as t on t.id = user_extra.user_id", - "Table": "user_extra" + "Table": "user_extra, `user`" } } @@ -1679,7 +1681,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1769,7 +1771,7 @@ Gen4 plan same as above }, "FieldQuery": "select u.col, e.col from (select col from `user` where 1 != 1) as u join (select col from user_extra where 1 != 1) as e where 1 != 1", "Query": "select u.col, e.col from (select col from `user` where id = 5) as u join (select col from user_extra where user_id = 5) as e", - "Table": "`user`", + "Table": "`user`, user_extra", "Values": [ 5 ], @@ -1790,7 +1792,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select * from information_schema.a where 1 != 1", - "Query": "select * from information_schema.a where b = 10" + "Query": "select * from information_schema.a where b = 10", + "Table": "information_schema.a" } } @@ -1807,7 +1810,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select * from information_schema.a where 1 != 1", - "Query": "select * from information_schema.a where information_schema.a.b = 10" + "Query": "select * from information_schema.a where information_schema.a.b = 10", + "Table": "information_schema.a" } } @@ -1820,7 +1824,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "_unsharded", + "TableName": "information_schema.a, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -1830,7 +1834,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select 1 from information_schema.a where 1 != 1", - "Query": "select 1 from information_schema.a" + "Query": "select 1 from information_schema.a", + "Table": "information_schema.a" }, { "OperatorType": "Route", @@ -1856,7 +1861,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "unsharded_", + "TableName": "unsharded, information_schema.a", "Inputs": [ { "OperatorType": "Route", @@ -1877,7 +1882,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select 1 from information_schema.a where 1 != 1", - "Query": "select 1 from information_schema.a" + "Query": "select 1 from information_schema.a", + "Table": "information_schema.a" } ] } @@ -1892,7 +1898,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra_unsharded", + "TableName": "`user`, user_extra, unsharded", "Inputs": [ { "OperatorType": "Subquery", @@ -1905,7 +1911,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1963,7 +1969,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -2002,7 +2008,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "unsharded_a_`user`_user_extra", + "TableName": "unsharded_a, `user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -2025,7 +2031,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -2086,7 +2092,7 @@ Gen4 plan same as above }, "FieldQuery": "select unsharded_a.col from unsharded_a join unsharded_b on :__sq1 where 1 != 1", "Query": "select unsharded_a.col from unsharded_a join unsharded_b on :__sq1", - "Table": "unsharded_a" + "Table": "unsharded_a, unsharded_b" } ] } @@ -2121,7 +2127,7 @@ Gen4 plan same as above }, "FieldQuery": "select unsharded_a.col from unsharded_a join unsharded_b on unsharded_a.col + :__sq1 where 1 != 1", "Query": "select unsharded_a.col from unsharded_a join unsharded_b on unsharded_a.col + :__sq1", - "Table": "unsharded_a" + "Table": "unsharded_a, unsharded_b" } ] } @@ -2156,7 +2162,7 @@ Gen4 plan same as above }, "FieldQuery": "select unsharded_a.col from unsharded_a join unsharded_b on :__sq_has_values1 = 1 and unsharded_a.col in ::__sq1 where 1 != 1", "Query": "select unsharded_a.col from unsharded_a join unsharded_b on :__sq_has_values1 = 1 and unsharded_a.col in ::__sq1", - "Table": "unsharded_a" + "Table": "unsharded_a, unsharded_b" } ] } @@ -2186,7 +2192,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "unsharded_`user`", + "TableName": "unsharded, `user`", "Inputs": [ { "OperatorType": "Route", @@ -2226,7 +2232,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "LeftJoin", "JoinColumnIndexes": "-1", - "TableName": "unsharded_`user`", + "TableName": "unsharded, `user`", "Inputs": [ { "OperatorType": "Route", @@ -2281,7 +2287,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "unsharded_`user`_unsharded_a", + "TableName": "unsharded, `user`, unsharded_a", "Inputs": [ { "OperatorType": "Subquery", @@ -2302,7 +2308,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "unsharded_`user`", + "TableName": "unsharded, `user`", "Inputs": [ { "OperatorType": "Route", @@ -2354,7 +2360,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -2388,7 +2394,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-2,1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -2449,7 +2455,7 @@ Gen4 plan same as above }, "FieldQuery": "select `user`.col from `user` join user_extra on `user`.ID = user_extra.User_Id where 1 != 1", "Query": "select `user`.col from `user` join user_extra on `user`.ID = user_extra.User_Id", - "Table": "`user`" + "Table": "`user`, user_extra" } } { @@ -2484,7 +2490,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -2616,7 +2622,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -2650,7 +2656,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "user_extra_`user`", + "TableName": "user_extra, `user`", "Inputs": [ { "OperatorType": "Route", @@ -2740,7 +2746,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select column_name from information_schema.`columns` where 1 != 1", - "Query": "select column_name from information_schema.`columns` where table_schema = schema()" + "Query": "select column_name from information_schema.`columns` where table_schema = schema()", + "Table": "information_schema.`columns`" } } @@ -2757,7 +2764,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select * from information_schema.a join information_schema.b where 1 != 1", - "Query": "select * from information_schema.a join information_schema.b" + "Query": "select * from information_schema.a join information_schema.b", + "Table": "information_schema.a, information_schema.b" } } @@ -2775,7 +2783,8 @@ Gen4 plan same as above }, "FieldQuery": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name`, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on rc.constraint_schema = fk.constraint_schema and rc.constraint_name = fk.constraint_name where 1 != 1", "Query": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name`, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on rc.constraint_schema = fk.constraint_schema and rc.constraint_name = fk.constraint_name where fk.referenced_column_name is not null and fk.table_schema = database() and fk.table_name = :__vttablename and rc.constraint_schema = database() and rc.table_name = :__vttablename", - "SysTableTableName": "[VARBINARY(\":vtg1\"), VARBINARY(\":vtg1\")]" + "SysTableTableName": "[VARBINARY(\":vtg1\"), VARBINARY(\":vtg1\")]", + "Table": "information_schema.referential_constraints, information_schema.key_column_usage" } } @@ -2793,7 +2802,8 @@ Gen4 plan same as above }, "FieldQuery": "select * from information_schema.schemata where 1 != 1", "Query": "select * from information_schema.schemata where schema_name = :__vtschemaname", - "SysTableTableSchema": "[VARBINARY(\"user\")]" + "SysTableTableSchema": "[VARBINARY(\"user\")]", + "Table": "information_schema.schemata" } } @@ -2812,7 +2822,8 @@ Gen4 plan same as above "FieldQuery": "select table_comment from information_schema.`tables` where 1 != 1", "Query": "select table_comment from information_schema.`tables` where table_schema = :__vtschemaname and table_name = :__vttablename", "SysTableTableName": "[VARBINARY(\"table_name\")]", - "SysTableTableSchema": "[VARBINARY(\"schema_name\")]" + "SysTableTableSchema": "[VARBINARY(\"schema_name\")]", + "Table": "information_schema.`tables`" } } @@ -2831,7 +2842,8 @@ Gen4 plan same as above "FieldQuery": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name`, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on rc.constraint_schema = fk.constraint_schema and rc.constraint_name = fk.constraint_name where 1 != 1", "Query": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name`, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on rc.constraint_schema = fk.constraint_schema and rc.constraint_name = fk.constraint_name where fk.referenced_column_name is not null and fk.table_schema = :__vtschemaname and fk.table_name = :__vttablename and rc.constraint_schema = :__vtschemaname and rc.table_name = :__vttablename", "SysTableTableName": "[VARBINARY(\"table_name\"), VARBINARY(\"table_name\")]", - "SysTableTableSchema": "[VARBINARY(\"table_schema\"), VARBINARY(\"table_schema\")]" + "SysTableTableSchema": "[VARBINARY(\"table_schema\"), VARBINARY(\"table_schema\")]", + "Table": "information_schema.referential_constraints, information_schema.key_column_usage" } } @@ -2850,7 +2862,8 @@ Gen4 plan same as above "FieldQuery": "select cc.constraint_name as `name`, cc.check_clause as expression from information_schema.check_constraints as cc join information_schema.table_constraints as tc on cc.constraint_schema = tc.constraint_schema and cc.constraint_name = tc.constraint_name where 1 != 1", "Query": "select cc.constraint_name as `name`, cc.check_clause as expression from information_schema.check_constraints as cc join information_schema.table_constraints as tc on cc.constraint_schema = tc.constraint_schema and cc.constraint_name = tc.constraint_name where tc.table_schema = :__vtschemaname and tc.table_name = :__vttablename and cc.constraint_schema = :__vtschemaname", "SysTableTableName": "[VARBINARY(\"table_name\")]", - "SysTableTableSchema": "[VARBINARY(\"table_schema\"), VARBINARY(\"constraint_schema\")]" + "SysTableTableSchema": "[VARBINARY(\"table_schema\"), VARBINARY(\"constraint_schema\")]", + "Table": "information_schema.check_constraints, information_schema.table_constraints" } } @@ -2869,7 +2882,8 @@ Gen4 plan same as above "FieldQuery": "select column_name from information_schema.statistics where 1 != 1", "Query": "select column_name from information_schema.statistics where index_name = 'PRIMARY' and table_schema = :__vtschemaname and table_name = :__vttablename order by seq_in_index asc", "SysTableTableName": "[VARBINARY(\"table_name\")]", - "SysTableTableSchema": "[VARBINARY(\"table_schema\")]" + "SysTableTableSchema": "[VARBINARY(\"table_schema\")]", + "Table": "information_schema.statistics" } } @@ -2888,7 +2902,8 @@ Gen4 plan same as above "FieldQuery": "select generation_expression from information_schema.`columns` where 1 != 1", "Query": "select generation_expression from information_schema.`columns` where table_schema = :__vtschemaname and table_name = :__vttablename and column_name = 'column_name'", "SysTableTableName": "[VARBINARY(\"table_name\")]", - "SysTableTableSchema": "[VARBINARY(\"table_schema\")]" + "SysTableTableSchema": "[VARBINARY(\"table_schema\")]", + "Table": "information_schema.`columns`" } } @@ -2905,7 +2920,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select id from information_schema.`processlist` where 1 != 1", - "Query": "select id from information_schema.`processlist` where info like '% FOR UPDATE'" + "Query": "select id from information_schema.`processlist` where info like '% FOR UPDATE'", + "Table": "information_schema.`processlist`" } } @@ -2923,7 +2939,8 @@ Gen4 plan same as above }, "FieldQuery": "select table_name from (select * from information_schema.`tables` where 1 != 1) as _subquery where 1 != 1", "Query": "select table_name from (select * from information_schema.`tables` where table_schema = :__vtschemaname) as _subquery", - "SysTableTableSchema": "[VARBINARY(\"table_schema\")]" + "SysTableTableSchema": "[VARBINARY(\"table_schema\")]", + "Table": "information_schema.`tables`" } } @@ -2942,7 +2959,8 @@ Gen4 plan same as above "FieldQuery": "select table_name from (select * from information_schema.`tables` where 1 != 1) as _subquery where 1 != 1", "Query": "select table_name from (select * from information_schema.`tables` where table_schema = :__vtschemaname) as _subquery where _subquery.table_type = 'table_type' and _subquery.table_name = :__vttablename", "SysTableTableName": "[VARBINARY(\"table_name\")]", - "SysTableTableSchema": "[VARBINARY(\"table_schema\")]" + "SysTableTableSchema": "[VARBINARY(\"table_schema\")]", + "Table": "information_schema.`tables`" } } @@ -2960,7 +2978,8 @@ Gen4 plan same as above }, "FieldQuery": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where 1 != 1", "Query": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where cc.constraint_schema = :__vtschemaname and cc.table_schema = :__vtschemaname", - "SysTableTableSchema": "[VARBINARY(\"a\"), VARBINARY(\"a\")]" + "SysTableTableSchema": "[VARBINARY(\"a\"), VARBINARY(\"a\")]", + "Table": "information_schema.check_constraints" } } @@ -2979,7 +2998,8 @@ Gen4 plan same as above "FieldQuery": "select COUNT(*) from INFORMATION_SCHEMA.`TABLES` where 1 != 1", "Query": "select COUNT(*) from INFORMATION_SCHEMA.`TABLES` where table_schema = :__vtschemaname and table_name = :__vttablename", "SysTableTableName": "[VARBINARY(\"foo\")]", - "SysTableTableSchema": "[VARBINARY(\"performance_schema\")]" + "SysTableTableSchema": "[VARBINARY(\"performance_schema\")]", + "Table": "INFORMATION_SCHEMA.`TABLES`" } } diff --git a/go/vt/vtgate/planbuilder/testdata/large_cases.txt b/go/vt/vtgate/planbuilder/testdata/large_cases.txt index 6db381e46c6..6dc2224cbe3 100644 --- a/go/vt/vtgate/planbuilder/testdata/large_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/large_cases.txt @@ -6,7 +6,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra_user_metadata_music_unsharded_unsharded_a_unsharded_b_unsharded_auto_music_extra", + "TableName": "`user`, user_extra, user_metadata, music, unsharded, unsharded_a, unsharded_b, unsharded_auto, music_extra", "Inputs": [ { "OperatorType": "Route", @@ -22,7 +22,7 @@ { "OperatorType": "Join", "Variant": "Join", - "TableName": "user_extra_user_metadata_music_unsharded_unsharded_a_unsharded_b_unsharded_auto_music_extra", + "TableName": "user_extra, user_metadata, music, unsharded, unsharded_a, unsharded_b, unsharded_auto, music_extra", "Inputs": [ { "OperatorType": "Route", @@ -42,7 +42,7 @@ { "OperatorType": "Join", "Variant": "Join", - "TableName": "user_metadata_music_unsharded_unsharded_a_unsharded_b_unsharded_auto_music_extra", + "TableName": "user_metadata, music, unsharded, unsharded_a, unsharded_b, unsharded_auto, music_extra", "Inputs": [ { "OperatorType": "Route", @@ -62,7 +62,7 @@ { "OperatorType": "Join", "Variant": "Join", - "TableName": "music_unsharded_unsharded_a_unsharded_b_unsharded_auto_music_extra", + "TableName": "music, unsharded, unsharded_a, unsharded_b, unsharded_auto, music_extra", "Inputs": [ { "OperatorType": "Route", @@ -78,7 +78,7 @@ { "OperatorType": "Join", "Variant": "Join", - "TableName": "unsharded_unsharded_a_unsharded_b_unsharded_auto_music_extra", + "TableName": "unsharded, unsharded_a, unsharded_b, unsharded_auto, music_extra", "Inputs": [ { "OperatorType": "Route", @@ -94,7 +94,7 @@ { "OperatorType": "Join", "Variant": "Join", - "TableName": "unsharded_a_unsharded_b_unsharded_auto_music_extra", + "TableName": "unsharded_a, unsharded_b, unsharded_auto, music_extra", "Inputs": [ { "OperatorType": "Route", @@ -110,7 +110,7 @@ { "OperatorType": "Join", "Variant": "Join", - "TableName": "unsharded_b_unsharded_auto_music_extra", + "TableName": "unsharded_b, unsharded_auto, music_extra", "Inputs": [ { "OperatorType": "Route", @@ -126,7 +126,7 @@ { "OperatorType": "Join", "Variant": "Join", - "TableName": "unsharded_auto_music_extra", + "TableName": "unsharded_auto, music_extra", "Inputs": [ { "OperatorType": "Route", @@ -178,7 +178,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "music, music_extra_`user`, user_extra, user_metadata_unsharded, unsharded_a, unsharded_auto, unsharded_b", + "TableName": "music, music_extra, `user`, user_extra, user_metadata, unsharded, unsharded_a, unsharded_auto, unsharded_b", "Inputs": [ { "OperatorType": "Route", @@ -195,7 +195,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`, user_extra, user_metadata_unsharded, unsharded_a, unsharded_auto, unsharded_b", + "TableName": "`user`, user_extra, user_metadata, unsharded, unsharded_a, unsharded_auto, unsharded_b", "Inputs": [ { "OperatorType": "Route", diff --git a/go/vt/vtgate/planbuilder/testdata/memory_sort_cases.txt b/go/vt/vtgate/planbuilder/testdata/memory_sort_cases.txt index 5b256260111..ceb093d78f6 100644 --- a/go/vt/vtgate/planbuilder/testdata/memory_sort_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/memory_sort_cases.txt @@ -22,9 +22,9 @@ "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, count(*), weight_string(b), weight_string(a) from `user` where 1 != 1 group by a", + "FieldQuery": "select a, b, count(*), weight_string(b), weight_string(a) from `user` where 1 != 1 group by a, weight_string(a)", "OrderBy": "0 ASC", - "Query": "select a, b, count(*), weight_string(b), weight_string(a) from `user` group by a order by a asc", + "Query": "select a, b, count(*), weight_string(b), weight_string(a) from `user` group by a, weight_string(a) order by a asc", "ResultColumns": 4, "Table": "`user`" } @@ -57,9 +57,9 @@ "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, count(*) as k, weight_string(a) from `user` where 1 != 1 group by a", + "FieldQuery": "select a, b, count(*) as k, weight_string(a) from `user` where 1 != 1 group by a, weight_string(a)", "OrderBy": "0 ASC", - "Query": "select a, b, count(*) as k, weight_string(a) from `user` group by a order by a asc", + "Query": "select a, b, count(*) as k, weight_string(a) from `user` group by a, weight_string(a) order by a asc", "ResultColumns": 3, "Table": "`user`" } @@ -92,9 +92,9 @@ "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, count(*) as k, weight_string(b), weight_string(a) from `user` where 1 != 1 group by a", + "FieldQuery": "select a, b, count(*) as k, weight_string(b), weight_string(a) from `user` where 1 != 1 group by a, weight_string(a)", "OrderBy": "0 ASC", - "Query": "select a, b, count(*) as k, weight_string(b), weight_string(a) from `user` group by a order by a asc", + "Query": "select a, b, count(*) as k, weight_string(b), weight_string(a) from `user` group by a, weight_string(a) order by a asc", "ResultColumns": 5, "Table": "`user`" } @@ -131,9 +131,9 @@ "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, count(*) as k, weight_string(a) from `user` where 1 != 1 group by a", + "FieldQuery": "select a, b, count(*) as k, weight_string(a) from `user` where 1 != 1 group by a, weight_string(a)", "OrderBy": "0 ASC", - "Query": "select a, b, count(*) as k, weight_string(a) from `user` group by a order by a asc", + "Query": "select a, b, count(*) as k, weight_string(a) from `user` group by a, weight_string(a) order by a asc", "ResultColumns": 3, "Table": "`user`" } @@ -168,9 +168,9 @@ "Name": "user", "Sharded": true }, - "FieldQuery": "select a, b, count(*) as k, weight_string(a) from `user` where 1 != 1 group by a", + "FieldQuery": "select a, b, count(*) as k, weight_string(a) from `user` where 1 != 1 group by a, weight_string(a)", "OrderBy": "0 ASC", - "Query": "select a, b, count(*) as k, weight_string(a) from `user` group by a order by 1 asc", + "Query": "select a, b, count(*) as k, weight_string(a) from `user` group by a, weight_string(a) order by 1 asc", "ResultColumns": 4, "Table": "`user`" } @@ -204,9 +204,9 @@ "Name": "user", "Sharded": true }, - "FieldQuery": "select textcol1 as t, count(*) as k, weight_string(textcol1) from `user` where 1 != 1 group by textcol1", + "FieldQuery": "select textcol1 as t, count(*) as k, weight_string(textcol1) from `user` where 1 != 1 group by textcol1, weight_string(textcol1), weight_string(textcol1), weight_string(textcol1)", "OrderBy": "0 ASC, 0 ASC", - "Query": "select textcol1 as t, count(*) as k, weight_string(textcol1) from `user` group by textcol1 order by textcol1 asc, textcol1 asc", + "Query": "select textcol1 as t, count(*) as k, weight_string(textcol1) from `user` group by textcol1, weight_string(textcol1), weight_string(textcol1), weight_string(textcol1) order by textcol1 asc, textcol1 asc", "ResultColumns": 3, "Table": "`user`" } @@ -236,7 +236,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2,-3", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -282,7 +282,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2,1,2", - "TableName": "`user`_music", + "TableName": "`user`, music", "Inputs": [ { "OperatorType": "Route", @@ -334,7 +334,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2,1,-3,2,-4", - "TableName": "`user`_music", + "TableName": "`user`, music", "Inputs": [ { "OperatorType": "Route", @@ -386,7 +386,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2,1,-3,2", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -430,7 +430,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1,2,-1,3,-2", - "TableName": "unsharded_`user`", + "TableName": "unsharded, `user`", "Inputs": [ { "OperatorType": "Route", @@ -521,7 +521,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_music", + "TableName": "`user`, music", "Inputs": [ { "OperatorType": "Route", diff --git a/go/vt/vtgate/planbuilder/testdata/postprocess_cases.txt b/go/vt/vtgate/planbuilder/testdata/postprocess_cases.txt index e204b6fea3d..b75df79edd9 100644 --- a/go/vt/vtgate/planbuilder/testdata/postprocess_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/postprocess_cases.txt @@ -29,7 +29,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -66,7 +66,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2,1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -450,7 +450,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2,1", - "TableName": "`user`_music", + "TableName": "`user`, music", "Inputs": [ { "OperatorType": "Route", @@ -495,7 +495,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2,1", - "TableName": "`user`_music", + "TableName": "`user`, music", "Inputs": [ { "OperatorType": "Route", @@ -540,7 +540,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2,1", - "TableName": "`user`_music", + "TableName": "`user`, music", "Inputs": [ { "OperatorType": "Route", @@ -638,7 +638,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2,1", - "TableName": "`user`_music", + "TableName": "`user`, music", "Inputs": [ { "OperatorType": "Route", @@ -787,7 +787,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -938,7 +938,7 @@ Gen4 plan same as above }, "FieldQuery": "select * from `user` as u join (select user_id from user_extra where 1 != 1) as eu on u.id = eu.user_id where 1 != 1", "Query": "select * from `user` as u join (select user_id from user_extra where user_id = 5) as eu on u.id = eu.user_id where u.id = 5 order by eu.user_id asc", - "Table": "`user`", + "Table": "`user`, user_extra", "Values": [ 5 ], @@ -1006,7 +1006,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", diff --git a/go/vt/vtgate/planbuilder/testdata/schema_test.json b/go/vt/vtgate/planbuilder/testdata/schema_test.json index 1a0213bd46e..ed9da260abb 100644 --- a/go/vt/vtgate/planbuilder/testdata/schema_test.json +++ b/go/vt/vtgate/planbuilder/testdata/schema_test.json @@ -292,6 +292,54 @@ "tables": { } }, + "zlookup_unique": { + "sharded": true, + "vindexes": { + "hash": { + "type": "hash" + }, + "xxhash": { + "type": "xxhash" + }, + "lookup_t1": { + "type": "lookup_unique", + "params": { + "from": "c2", + "table": "targetkeyspace.lookup_t1_backing", + "to": "keyspace_id", + "write_only": "true" + }, + "owner": "t1" + }, + "lookup_t1_2": { + "type": "lookup_unique", + "params": { + "from": "c3", + "table": "targetkeyspace.lookup_t1_2_backing", + "to": "keyspace_id" + }, + "owner": "t1" + } + }, + "tables": { + "t1": { + "columnVindexes": [ + { + "column": "c1", + "name": "xxhash" + }, + { + "column": "c2", + "name": "lookup_t1" + }, + { + "column": "c3", + "name": "lookup_t1_2" + } + ] + } + } + }, "main": { "tables": { "unsharded": { diff --git a/go/vt/vtgate/planbuilder/testdata/select_cases.txt b/go/vt/vtgate/planbuilder/testdata/select_cases.txt index 46650433aeb..7ac692c6a65 100644 --- a/go/vt/vtgate/planbuilder/testdata/select_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/select_cases.txt @@ -324,7 +324,7 @@ Gen4 plan same as above }, "FieldQuery": "select * from authoritative join `user` on authoritative.user_id = `user`.id where 1 != 1", "Query": "select * from authoritative join `user` on authoritative.user_id = `user`.id", - "Table": "authoritative" + "Table": "authoritative, `user`" } } @@ -342,7 +342,7 @@ Gen4 plan same as above }, "FieldQuery": "select `user`.id, a.user_id, a.col1, a.col2, `user`.col1 from authoritative as a join `user` on a.user_id = `user`.id where 1 != 1", "Query": "select `user`.id, a.user_id, a.col1, a.col2, `user`.col1 from authoritative as a join `user` on a.user_id = `user`.id", - "Table": "authoritative" + "Table": "authoritative, `user`" } } @@ -360,7 +360,7 @@ Gen4 plan same as above }, "FieldQuery": "select col from `user` join user_extra on `user`.id = user_extra.user_id where 1 != 1", "Query": "select col from `user` join user_extra on `user`.id = user_extra.user_id", - "Table": "`user`" + "Table": "`user`, user_extra" } } @@ -377,7 +377,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -518,7 +518,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -556,7 +556,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -594,7 +594,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -632,7 +632,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1,-2", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -670,7 +670,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -707,7 +707,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -744,7 +744,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -781,7 +781,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1131,7 +1131,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1182,7 +1182,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select * from information_schema.a where 1 != 1 union select * from information_schema.b where 1 != 1", - "Query": "select * from information_schema.a union select * from information_schema.b" + "Query": "select * from information_schema.a union select * from information_schema.b", + "Table": "information_schema.a" } } Gen4 plan same as above @@ -1662,7 +1663,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1707,7 +1708,8 @@ Gen4 plan same as above "FieldQuery": "select DELETE_RULE, UPDATE_RULE from INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as RC on KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME where 1 != 1", "Query": "select DELETE_RULE, UPDATE_RULE from INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as RC on KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME where KCU.TABLE_SCHEMA = :__vtschemaname and KCU.TABLE_NAME = :__vttablename and KCU.COLUMN_NAME = 'id' and KCU.REFERENCED_TABLE_SCHEMA = 'test' and KCU.CONSTRAINT_NAME = 'data_type_table_id_fkey' order by KCU.CONSTRAINT_NAME asc, KCU.COLUMN_NAME asc", "SysTableTableName": "[VARBINARY(\"data_type_table\")]", - "SysTableTableSchema": "[VARBINARY(\"test\")]" + "SysTableTableSchema": "[VARBINARY(\"test\")]", + "Table": "INFORMATION_SCHEMA.KEY_COLUMN_USAGE, INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS" } } @@ -1720,7 +1722,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "_", + "TableName": "INFORMATION_SCHEMA.KEY_COLUMN_USAGE, INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS, INFORMATION_SCHEMA.K", "Inputs": [ { "OperatorType": "Route", @@ -1732,7 +1734,8 @@ Gen4 plan same as above "FieldQuery": "select KCU.DELETE_RULE from INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as RC on KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME where 1 != 1", "Query": "select KCU.DELETE_RULE from INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as RC on KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME where KCU.TABLE_SCHEMA = :__vtschemaname and KCU.TABLE_NAME = :__vttablename and KCU.TABLE_NAME = :__vttablename order by KCU.CONSTRAINT_NAME asc, KCU.COLUMN_NAME asc", "SysTableTableName": "[VARBINARY(\"data_type_table\"), VARBINARY(\"data_type_table\")]", - "SysTableTableSchema": "[VARBINARY(\"test\")]" + "SysTableTableSchema": "[VARBINARY(\"test\")]", + "Table": "INFORMATION_SCHEMA.KEY_COLUMN_USAGE, INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS" }, { "OperatorType": "Route", @@ -1744,7 +1747,8 @@ Gen4 plan same as above "FieldQuery": "select S.UPDATE_RULE from INFORMATION_SCHEMA.K as S where 1 != 1", "Query": "select S.UPDATE_RULE from INFORMATION_SCHEMA.K as S where S.TABLE_SCHEMA = :__vtschemaname and S.TABLE_NAME = :__vttablename", "SysTableTableName": "[VARBINARY(\"sc\")]", - "SysTableTableSchema": "[VARBINARY(\"test\")]" + "SysTableTableSchema": "[VARBINARY(\"test\")]", + "Table": "INFORMATION_SCHEMA.K" } ] } @@ -1764,7 +1768,8 @@ Gen4 plan same as above }, "FieldQuery": "select routine_name as `name`, routine_definition as definition from information_schema.routines where 1 != 1", "Query": "select routine_name as `name`, routine_definition as definition from information_schema.routines where ROUTINE_SCHEMA = :__vtschemaname and ROUTINE_TYPE = 'PROCEDURE'", - "SysTableTableSchema": "[:v1]" + "SysTableTableSchema": "[:v1]", + "Table": "information_schema.routines" } } @@ -1782,7 +1787,8 @@ Gen4 plan same as above }, "FieldQuery": "select SUM(data_length + index_length) as size from information_schema.`TABLES` where 1 != 1", "Query": "select SUM(data_length + index_length) as size from information_schema.`TABLES` where table_schema = :__vtschemaname", - "SysTableTableSchema": "[:v1]" + "SysTableTableSchema": "[:v1]", + "Table": "information_schema.`TABLES`" } } @@ -1800,6 +1806,7 @@ Gen4 plan same as above }, "FieldQuery": "select kcu.constraint_name as constraint_name, kcu.column_name as column_name, kcu.referenced_table_name as referenced_table_name, kcu.referenced_column_name as referenced_column_name, kcu.ordinal_position as ordinal_position, kcu.table_name as table_name, rc.delete_rule as delete_rule, rc.update_rule as update_rule from information_schema.key_column_usage as kcu join information_schema.referential_constraints as rc on kcu.constraint_name = rc.constraint_name where 1 != 1", "Query": "select kcu.constraint_name as constraint_name, kcu.column_name as column_name, kcu.referenced_table_name as referenced_table_name, kcu.referenced_column_name as referenced_column_name, kcu.ordinal_position as ordinal_position, kcu.table_name as table_name, rc.delete_rule as delete_rule, rc.update_rule as update_rule from information_schema.key_column_usage as kcu join information_schema.referential_constraints as rc on kcu.constraint_name = rc.constraint_name where kcu.table_schema = :__vtschemaname and rc.constraint_schema = :__vtschemaname and kcu.referenced_column_name is not null order by ordinal_position asc", - "SysTableTableSchema": "[:v1, :v2]" + "SysTableTableSchema": "[:v1, :v2]", + "Table": "information_schema.key_column_usage, information_schema.referential_constraints" } } diff --git a/go/vt/vtgate/planbuilder/testdata/symtab_cases.txt b/go/vt/vtgate/planbuilder/testdata/symtab_cases.txt index bb40820a797..ddd6da0f0e8 100644 --- a/go/vt/vtgate/planbuilder/testdata/symtab_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/symtab_cases.txt @@ -9,7 +9,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_unsharded", + "TableName": "`user`, unsharded", "Inputs": [ { "OperatorType": "Route", diff --git a/go/vt/vtgate/planbuilder/testdata/union_cases.txt b/go/vt/vtgate/planbuilder/testdata/union_cases.txt index 18c159fd044..8709562b7cc 100644 --- a/go/vt/vtgate/planbuilder/testdata/union_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/union_cases.txt @@ -297,7 +297,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select * from information_schema.a where 1 != 1", - "Query": "select * from information_schema.a" + "Query": "select * from information_schema.a", + "Table": "information_schema.a" }, { "OperatorType": "Route", @@ -347,7 +348,8 @@ Gen4 plan same as above "Sharded": false }, "FieldQuery": "select * from information_schema.a where 1 != 1", - "Query": "select * from information_schema.a" + "Query": "select * from information_schema.a", + "Table": "information_schema.a" } ] } @@ -729,7 +731,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -799,7 +801,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", diff --git a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt index 19e52bc5890..47ae2e864ff 100644 --- a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt @@ -439,7 +439,8 @@ Gen4 plan same as above }, "FieldQuery": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where 1 != 1", "Query": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where cc.constraint_schema = :__vtschemaname and cc.table_schema = :__vtschemaname", - "SysTableTableSchema": "[VARBINARY(\"constraint_schema\"), VARBINARY(\"a\")]" + "SysTableTableSchema": "[VARBINARY(\"constraint_schema\"), VARBINARY(\"a\")]", + "Table": "information_schema.check_constraints" } } diff --git a/go/vt/vtgate/planbuilder/testdata/vindex_func_cases.txt b/go/vt/vtgate/planbuilder/testdata/vindex_func_cases.txt index c81faa8c7cb..1491b0786f8 100644 --- a/go/vt/vtgate/planbuilder/testdata/vindex_func_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/vindex_func_cases.txt @@ -114,7 +114,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "_unsharded", + "TableName": ", unsharded", "Inputs": [ { "OperatorType": "VindexFunc", @@ -152,7 +152,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1,-1", - "TableName": "unsharded_", + "TableName": "unsharded, ", "Inputs": [ { "OperatorType": "Route", @@ -190,7 +190,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2,1", - "TableName": "_unsharded", + "TableName": ", unsharded", "Inputs": [ { "OperatorType": "VindexFunc", @@ -230,7 +230,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "_unsharded", + "TableName": ", unsharded", "Inputs": [ { "OperatorType": "VindexFunc", @@ -270,7 +270,7 @@ Gen4 plan same as above "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "_unsharded", + "TableName": ", unsharded", "Inputs": [ { "OperatorType": "VindexFunc", diff --git a/go/vt/vtgate/planbuilder/testdata/wireup_cases.txt b/go/vt/vtgate/planbuilder/testdata/wireup_cases.txt index 80ca3f3367a..27dd6737263 100644 --- a/go/vt/vtgate/planbuilder/testdata/wireup_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/wireup_cases.txt @@ -7,7 +7,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1,-1,2", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -44,7 +44,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1,-1,2", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -81,13 +81,13 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_`user`_`user`", + "TableName": "`user`, `user`, `user`", "Inputs": [ { "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2", - "TableName": "`user`_`user`", + "TableName": "`user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -134,7 +134,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_`user`_`user`", + "TableName": "`user`, `user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -151,7 +151,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-2", - "TableName": "`user`_`user`", + "TableName": "`user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -190,13 +190,13 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_`user`_`user`", + "TableName": "`user`, `user`, `user`", "Inputs": [ { "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_`user`", + "TableName": "`user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -243,7 +243,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_`user`_`user`", + "TableName": "`user`, `user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -259,7 +259,7 @@ { "OperatorType": "Join", "Variant": "Join", - "TableName": "`user`_`user`", + "TableName": "`user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -298,13 +298,13 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_`user`_`user`", + "TableName": "`user`, `user`, `user`", "Inputs": [ { "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2", - "TableName": "`user`_`user`", + "TableName": "`user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -351,7 +351,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_`user`_`user`", + "TableName": "`user`, `user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -368,7 +368,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-2", - "TableName": "`user`_`user`", + "TableName": "`user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -410,19 +410,19 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_`user`_`user`_`user`", + "TableName": "`user`, `user`, `user`, `user`", "Inputs": [ { "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2", - "TableName": "`user`_`user`_`user`", + "TableName": "`user`, `user`, `user`", "Inputs": [ { "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2", - "TableName": "`user`_`user`", + "TableName": "`user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -486,7 +486,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_`user`_`user`_`user`", + "TableName": "`user`, `user`, `user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -503,7 +503,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`user`_`user`_`user`", + "TableName": "`user`, `user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -520,7 +520,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-2", - "TableName": "`user`_`user`", + "TableName": "`user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -565,7 +565,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1", - "TableName": "`user`_`user`_`user`", + "TableName": "`user`, `user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -581,7 +581,7 @@ { "OperatorType": "Join", "Variant": "Join", - "TableName": "`user`_`user`", + "TableName": "`user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -625,13 +625,13 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-2", - "TableName": "`user`_`user`_`user`", + "TableName": "`user`, `user`, `user`", "Inputs": [ { "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,-2", - "TableName": "`user`_`user`", + "TableName": "`user`, `user`", "Inputs": [ { "OperatorType": "Route", @@ -689,7 +689,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`weird``name`_unsharded", + "TableName": "`weird``name`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -723,7 +723,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1,-2", - "TableName": "unsharded_`weird``name`", + "TableName": "unsharded, `weird``name`", "Inputs": [ { "OperatorType": "Route", @@ -764,7 +764,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "1", - "TableName": "`weird``name`_unsharded", + "TableName": "`weird``name`, unsharded", "Inputs": [ { "OperatorType": "Route", @@ -798,7 +798,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-2", - "TableName": "unsharded_`weird``name`", + "TableName": "unsharded, `weird``name`", "Inputs": [ { "OperatorType": "Route", @@ -843,7 +843,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -883,7 +883,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-2,1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -930,7 +930,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", @@ -1005,7 +1005,7 @@ "OperatorType": "Join", "Variant": "Join", "JoinColumnIndexes": "-1,1,-2", - "TableName": "`user`_user_extra", + "TableName": "`user`, user_extra", "Inputs": [ { "OperatorType": "Route", diff --git a/go/vt/vtgate/planbuilder/update.go b/go/vt/vtgate/planbuilder/update.go index 98e53fa56f2..a1e834fc366 100644 --- a/go/vt/vtgate/planbuilder/update.go +++ b/go/vt/vtgate/planbuilder/update.go @@ -41,7 +41,11 @@ func buildUpdatePlan(stmt sqlparser.Statement, reservedVars *sqlparser.ReservedV return eupd, nil } - cvv, ovq, err := buildChangedVindexesValues(upd, eupd.Table, ksidCol) + vindexTable, err := eupd.GetSingleTable() + if err != nil { + return nil, err + } + cvv, ovq, err := buildChangedVindexesValues(upd, vindexTable, ksidCol) if err != nil { return nil, err } diff --git a/go/vt/vtgate/planbuilder/vindex_func.go b/go/vt/vtgate/planbuilder/vindex_func.go index 217c0fc8c46..e3c5f19319a 100644 --- a/go/vt/vtgate/planbuilder/vindex_func.go +++ b/go/vt/vtgate/planbuilder/vindex_func.go @@ -142,7 +142,7 @@ func (err UnsupportedSupplyWeightString) Error() string { } // SupplyWeightString implements the logicalPlan interface -func (vf *vindexFunc) SupplyWeightString(colNumber int) (weightcolNumber int, err error) { +func (vf *vindexFunc) SupplyWeightString(int, bool) (weightcolNumber int, err error) { return 0, UnsupportedSupplyWeightString{Type: "vindex function"} } diff --git a/go/vt/vtgate/querylog.go b/go/vt/vtgate/querylog.go index 8ec0a190b91..d0b53332804 100644 --- a/go/vt/vtgate/querylog.go +++ b/go/vt/vtgate/querylog.go @@ -34,13 +34,17 @@ var ( QueryzHandler = "/debug/queryz" // QueryLogger enables streaming logging of queries - QueryLogger = streamlog.New("VTGate", 10) + QueryLogger *streamlog.StreamLogger // queryLogToFile controls whether query logs are sent to a file queryLogToFile = flag.String("log_queries_to_file", "", "Enable query logging to the specified file") + + // queryLogBufferSize controls how many query logs will be buffered before dropping them if logging is not fast enough + queryLogBufferSize = flag.Int("querylog-buffer-size", 10, "Maximum number of buffered query logs before throttling log output") ) func initQueryLogger(vtg *VTGate) error { + QueryLogger = streamlog.New("VTGate", *queryLogBufferSize) QueryLogger.ServeLogs(QueryLogHandler, streamlog.GetFormatter(QueryLogger)) http.HandleFunc(QueryLogzHandler, func(w http.ResponseWriter, r *http.Request) { diff --git a/go/vt/vtgate/querylogz.go b/go/vt/vtgate/querylogz.go index 69a319d8b1c..837e5ecda9e 100644 --- a/go/vt/vtgate/querylogz.go +++ b/go/vt/vtgate/querylogz.go @@ -39,6 +39,7 @@ var ( Context Effective Caller Immediate Caller + SessionUUID Start End Duration @@ -47,6 +48,7 @@ var ( Commit Time Stmt Type SQL + InTransaction ShardQueries RowsAffected Error @@ -65,6 +67,7 @@ var ( {{.ContextHTML}} {{.EffectiveCaller}} {{.ImmediateCaller}} + {{.SessionUUID}} {{.StartTime | stampMicro}} {{.EndTime | stampMicro}} {{.TotalTime.Seconds}} @@ -73,6 +76,7 @@ var ( {{.CommitTime.Seconds}} {{.StmtType}} {{.SQL | truncateQuery | unquote | cssWrappable}} + {{.InTransaction}} {{.ShardQueries}} {{.RowsAffected}} {{.ErrorStr}} diff --git a/go/vt/vtgate/querylogz_test.go b/go/vt/vtgate/querylogz_test.go index 029e74ff28b..993821f3577 100644 --- a/go/vt/vtgate/querylogz_test.go +++ b/go/vt/vtgate/querylogz_test.go @@ -45,7 +45,7 @@ func TestQuerylogzHandlerInvalidLogStats(t *testing.T) { func TestQuerylogzHandlerFormatting(t *testing.T) { req, _ := http.NewRequest("GET", "/querylogz?timeout=10&limit=1", nil) - logStats := NewLogStats(context.Background(), "Execute", "select name from test_table limit 1000", nil) + logStats := NewLogStats(context.Background(), "Execute", "select name from test_table limit 1000", "suuid", nil) logStats.StmtType = "select" logStats.RowsAffected = 1000 logStats.ShardQueries = 1 @@ -66,6 +66,7 @@ func TestQuerylogzHandlerFormatting(t *testing.T) { ``, `effective-caller`, `immediate-caller`, + `suuid`, `Nov 29 13:33:09.000000`, `Nov 29 13:33:09.001000`, `0.001`, @@ -74,6 +75,7 @@ func TestQuerylogzHandlerFormatting(t *testing.T) { `0.003`, `select`, `select name from test_table limit 1000`, + `false`, `1`, `1000`, ``, @@ -95,6 +97,7 @@ func TestQuerylogzHandlerFormatting(t *testing.T) { ``, `effective-caller`, `immediate-caller`, + `suuid`, `Nov 29 13:33:09.000000`, `Nov 29 13:33:09.020000`, `0.02`, @@ -103,6 +106,7 @@ func TestQuerylogzHandlerFormatting(t *testing.T) { `0.003`, `select`, `select name from test_table limit 1000`, + `false`, `1`, `1000`, ``, @@ -124,6 +128,7 @@ func TestQuerylogzHandlerFormatting(t *testing.T) { ``, `effective-caller`, `immediate-caller`, + `suuid`, `Nov 29 13:33:09.000000`, `Nov 29 13:33:09.500000`, `0.5`, @@ -132,6 +137,7 @@ func TestQuerylogzHandlerFormatting(t *testing.T) { `0.003`, `select`, `select name from test_table limit 1000`, + `false`, `1`, `1000`, ``, diff --git a/go/vt/vtgate/vindexes/binary_test.go b/go/vt/vtgate/vindexes/binary_test.go index 167a05e8ef2..0399c1687bc 100644 --- a/go/vt/vtgate/vindexes/binary_test.go +++ b/go/vt/vtgate/vindexes/binary_test.go @@ -18,6 +18,8 @@ package vindexes import ( "bytes" + "encoding/hex" + "fmt" "reflect" "testing" @@ -69,13 +71,17 @@ func TestBinaryMap(t *testing.T) { } func TestBinaryVerify(t *testing.T) { - ids := []sqltypes.Value{sqltypes.NewVarBinary("1"), sqltypes.NewVarBinary("2")} - ksids := [][]byte{[]byte("1"), []byte("1")} + hexValStr := "8a1e" + hexValStrSQL := fmt.Sprintf("x'%s'", hexValStr) + hexNumStrSQL := fmt.Sprintf("0x%s", hexValStr) + hexBytes, _ := hex.DecodeString(hexValStr) + ids := []sqltypes.Value{sqltypes.NewVarBinary("1"), sqltypes.NewVarBinary("2"), sqltypes.NewHexVal([]byte(hexValStrSQL)), sqltypes.NewHexNum([]byte(hexNumStrSQL))} + ksids := [][]byte{[]byte("1"), []byte("1"), hexBytes, hexBytes} got, err := binOnlyVindex.Verify(nil, ids, ksids) if err != nil { t.Fatal(err) } - want := []bool{true, false} + want := []bool{true, false, true, true} if !reflect.DeepEqual(got, want) { t.Errorf("binary.Verify: %v, want %v", got, want) } diff --git a/go/vt/vtgate/vindexes/binarymd5_test.go b/go/vt/vtgate/vindexes/binarymd5_test.go index 5dfd3ae770f..58fb485abe3 100644 --- a/go/vt/vtgate/vindexes/binarymd5_test.go +++ b/go/vt/vtgate/vindexes/binarymd5_test.go @@ -17,6 +17,7 @@ limitations under the License. package vindexes import ( + "encoding/hex" "fmt" "reflect" "testing" @@ -72,13 +73,17 @@ func TestBinaryMD5Map(t *testing.T) { } func TestBinaryMD5Verify(t *testing.T) { - ids := []sqltypes.Value{sqltypes.NewVarBinary("Test"), sqltypes.NewVarBinary("TEst")} - ksids := [][]byte{[]byte("\f\xbcf\x11\xf5T\vЀ\x9a8\x8d\xc9Za["), []byte("\f\xbcf\x11\xf5T\vЀ\x9a8\x8d\xc9Za[")} + hexValStr := "21cf" + hexValStrSQL := fmt.Sprintf("x'%s'", hexValStr) + hexNumStrSQL := fmt.Sprintf("0x%s", hexValStr) + hexBytes, _ := hex.DecodeString(hexValStr) + ids := []sqltypes.Value{sqltypes.NewVarBinary("Test"), sqltypes.NewVarBinary("TEst"), sqltypes.NewHexVal([]byte(hexValStrSQL)), sqltypes.NewHexNum([]byte(hexNumStrSQL))} + ksids := [][]byte{[]byte("\f\xbcf\x11\xf5T\vЀ\x9a8\x8d\xc9Za["), []byte("\f\xbcf\x11\xf5T\vЀ\x9a8\x8d\xc9Za["), vMD5Hash(hexBytes), vMD5Hash(hexBytes)} got, err := binVindex.Verify(nil, ids, ksids) if err != nil { t.Fatal(err) } - want := []bool{true, false} + want := []bool{true, false, true, true} if !reflect.DeepEqual(got, want) { t.Errorf("binaryMD5.Verify: %v, want %v", got, want) } diff --git a/go/vt/vtgate/vindexes/consistent_lookup.go b/go/vt/vtgate/vindexes/consistent_lookup.go index 82c3889755c..d06acece445 100644 --- a/go/vt/vtgate/vindexes/consistent_lookup.go +++ b/go/vt/vtgate/vindexes/consistent_lookup.go @@ -384,3 +384,8 @@ func (lu *clCommon) addWhere(buf *bytes.Buffer, cols []string) { buf.WriteString(column + " = :" + lu.lkp.FromColumns[colIdx]) } } + +// IsBackfilling implements the LookupBackfill interface +func (lu *ConsistentLookupUnique) IsBackfilling() bool { + return lu.writeOnly +} diff --git a/go/vt/vtgate/vindexes/consistent_lookup_test.go b/go/vt/vtgate/vindexes/consistent_lookup_test.go index 268b89b368b..b4df8cd2c11 100644 --- a/go/vt/vtgate/vindexes/consistent_lookup_test.go +++ b/go/vt/vtgate/vindexes/consistent_lookup_test.go @@ -451,7 +451,6 @@ func TestConsistentLookupUpdateBecauseUncomparableTypes(t *testing.T) { {querypb.Type_TEXT, "some string"}, {querypb.Type_VARCHAR, "some string"}, {querypb.Type_CHAR, "some string"}, - {querypb.Type_BIT, "some string"}, {querypb.Type_GEOMETRY, "some string"}, } diff --git a/go/vt/vtgate/vindexes/lookup.go b/go/vt/vtgate/vindexes/lookup.go index 589f5942705..d06881e8a12 100644 --- a/go/vt/vtgate/vindexes/lookup.go +++ b/go/vt/vtgate/vindexes/lookup.go @@ -286,3 +286,8 @@ func (lu *LookupUnique) Delete(vcursor VCursor, rowsColValues [][]sqltypes.Value func (lu *LookupUnique) MarshalJSON() ([]byte, error) { return json.Marshal(lu.lkp) } + +// IsBackfilling implements the LookupBackfill interface +func (lu *LookupUnique) IsBackfilling() bool { + return lu.writeOnly +} diff --git a/go/vt/vtgate/vindexes/lookup_hash.go b/go/vt/vtgate/vindexes/lookup_hash.go index 2f76db4df7a..df34f841122 100644 --- a/go/vt/vtgate/vindexes/lookup_hash.go +++ b/go/vt/vtgate/vindexes/lookup_hash.go @@ -344,3 +344,8 @@ func (lhu *LookupHashUnique) Update(vcursor VCursor, oldValues []sqltypes.Value, func (lhu *LookupHashUnique) MarshalJSON() ([]byte, error) { return json.Marshal(lhu.lkp) } + +// IsBackfilling implements the LookupBackfill interface +func (lhu *LookupHashUnique) IsBackfilling() bool { + return lhu.writeOnly +} diff --git a/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash.go b/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash.go index d3a2c8b00c7..66a8c343799 100644 --- a/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash.go +++ b/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash.go @@ -381,6 +381,11 @@ func (lhu *LookupUnicodeLooseMD5HashUnique) MarshalJSON() ([]byte, error) { return json.Marshal(lhu.lkp) } +// IsBackfilling implements the LookupBackfill interface +func (lhu *LookupUnicodeLooseMD5HashUnique) IsBackfilling() bool { + return lhu.writeOnly +} + func unicodeHashValue(value sqltypes.Value) (sqltypes.Value, error) { hash, err := unicodeHash(vMD5Hash, value) if err != nil { diff --git a/go/vt/vtgate/vindexes/vindex.go b/go/vt/vtgate/vindexes/vindex.go index 6152d75bbe0..45564f3b2b1 100644 --- a/go/vt/vtgate/vindexes/vindex.go +++ b/go/vt/vtgate/vindexes/vindex.go @@ -128,6 +128,11 @@ type Lookup interface { Update(vc VCursor, oldValues []sqltypes.Value, ksid []byte, newValues []sqltypes.Value) error } +// LookupBackfill interfaces all lookup vindexes that can backfill rows, such as LookupUnique. +type LookupBackfill interface { + IsBackfilling() bool +} + // WantOwnerInfo defines the interface that a vindex must // satisfy to request info about the owner table. This information can // be used to query the owner's table for the owning row's presence. diff --git a/go/vt/vtgate/vindexes/vschema.go b/go/vt/vtgate/vindexes/vschema.go index 53ed49ad870..81a7d78e015 100644 --- a/go/vt/vtgate/vindexes/vschema.go +++ b/go/vt/vtgate/vindexes/vschema.go @@ -58,7 +58,7 @@ const ( // used for building routing plans. type VSchema struct { RoutingRules map[string]*RoutingRule `json:"routing_rules"` - uniqueTables map[string]*Table + UniqueTables map[string]*Table uniqueVindexes map[string]Vindex Keyspaces map[string]*KeyspaceSchema `json:"keyspaces"` } @@ -165,7 +165,7 @@ type AutoIncrement struct { func BuildVSchema(source *vschemapb.SrvVSchema) (vschema *VSchema) { vschema = &VSchema{ RoutingRules: make(map[string]*RoutingRule), - uniqueTables: make(map[string]*Table), + UniqueTables: make(map[string]*Table), uniqueVindexes: make(map[string]Vindex), Keyspaces: make(map[string]*KeyspaceSchema), } @@ -189,7 +189,7 @@ func BuildKeyspaceSchema(input *vschemapb.Keyspace, keyspace string) (*KeyspaceS }, } vschema := &VSchema{ - uniqueTables: make(map[string]*Table), + UniqueTables: make(map[string]*Table), uniqueVindexes: make(map[string]Vindex), Keyspaces: make(map[string]*KeyspaceSchema), } @@ -335,10 +335,10 @@ func buildTables(ks *vschemapb.Keyspace, vschema *VSchema, ksvschema *KeyspaceSc // Add the table to the map entries. // If the keyspace requires explicit routing, don't include it in global routing if !ks.RequireExplicitRouting { - if _, ok := vschema.uniqueTables[tname]; ok { - vschema.uniqueTables[tname] = nil + if _, ok := vschema.UniqueTables[tname]; ok { + vschema.UniqueTables[tname] = nil } else { - vschema.uniqueTables[tname] = t + vschema.UniqueTables[tname] = t } } ksvschema.Tables[tname] = t @@ -362,7 +362,7 @@ func resolveAutoIncrement(source *vschemapb.SrvVSchema, vschema *VSchema) { if err != nil { // Better to remove the table than to leave it partially initialized. delete(ksvschema.Tables, tname) - delete(vschema.uniqueTables, tname) + delete(vschema.UniqueTables, tname) ksvschema.Error = fmt.Errorf("cannot resolve sequence %s: %v", table.AutoIncrement.Sequence, err) continue } @@ -391,7 +391,7 @@ func addDual(vschema *VSchema) { // the keyspaces. For consistency, we'll always use the // first keyspace by lexical ordering. first = ksname - vschema.uniqueTables["dual"] = t + vschema.UniqueTables["dual"] = t } } } @@ -464,7 +464,7 @@ func (vschema *VSchema) FindTable(keyspace, tablename string) (*Table, error) { // findTable is like FindTable, but does not return an error if a table is not found. func (vschema *VSchema) findTable(keyspace, tablename string) (*Table, error) { if keyspace == "" { - table, ok := vschema.uniqueTables[tablename] + table, ok := vschema.UniqueTables[tablename] if table == nil { if ok { return nil, fmt.Errorf("ambiguous table reference: %s", tablename) diff --git a/go/vt/vtgate/vindexes/vschema_test.go b/go/vt/vtgate/vindexes/vschema_test.go index daf0708cc5f..660e8fb7fe3 100644 --- a/go/vt/vtgate/vindexes/vschema_test.go +++ b/go/vt/vtgate/vindexes/vschema_test.go @@ -223,7 +223,7 @@ func TestUnshardedVSchema(t *testing.T) { } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, - uniqueTables: map[string]*Table{ + UniqueTables: map[string]*Table{ "t1": t1, "dual": dual, }, @@ -285,7 +285,7 @@ func TestVSchemaColumns(t *testing.T) { } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, - uniqueTables: map[string]*Table{ + UniqueTables: map[string]*Table{ "t1": t1, "dual": dual, }, @@ -349,7 +349,7 @@ func TestVSchemaColumnListAuthoritative(t *testing.T) { } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, - uniqueTables: map[string]*Table{ + UniqueTables: map[string]*Table{ "t1": t1, "dual": dual, }, @@ -428,7 +428,7 @@ func TestVSchemaPinned(t *testing.T) { } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, - uniqueTables: map[string]*Table{ + UniqueTables: map[string]*Table{ "t1": t1, "dual": dual, }, @@ -530,7 +530,7 @@ func TestShardedVSchemaOwned(t *testing.T) { } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, - uniqueTables: map[string]*Table{ + UniqueTables: map[string]*Table{ "t1": t1, "dual": dual, }, @@ -778,7 +778,7 @@ func TestVSchemaRoutingRules(t *testing.T) { Error: errors.New("table t2 not found"), }, }, - uniqueTables: map[string]*Table{ + UniqueTables: map[string]*Table{ "t1": t1, "t2": t2, "dual": dual1, @@ -1195,7 +1195,7 @@ func TestShardedVSchemaMultiColumnVindex(t *testing.T) { } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, - uniqueTables: map[string]*Table{ + UniqueTables: map[string]*Table{ "t1": t1, "dual": dual, }, @@ -1293,7 +1293,7 @@ func TestShardedVSchemaNotOwned(t *testing.T) { } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, - uniqueTables: map[string]*Table{ + UniqueTables: map[string]*Table{ "t1": t1, "dual": dual, }, @@ -1425,7 +1425,7 @@ func TestBuildVSchemaDupSeq(t *testing.T) { } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, - uniqueTables: map[string]*Table{ + UniqueTables: map[string]*Table{ "t1": nil, "dual": duala, }, @@ -1498,7 +1498,7 @@ func TestBuildVSchemaDupTable(t *testing.T) { } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, - uniqueTables: map[string]*Table{ + UniqueTables: map[string]*Table{ "t1": nil, "dual": duala, }, @@ -1632,7 +1632,7 @@ func TestBuildVSchemaDupVindex(t *testing.T) { } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, - uniqueTables: map[string]*Table{ + UniqueTables: map[string]*Table{ "t1": nil, "dual": duala, }, @@ -1949,7 +1949,7 @@ func TestSequence(t *testing.T) { } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, - uniqueTables: map[string]*Table{ + UniqueTables: map[string]*Table{ "seq": seq, "t1": t1, "t2": t2, diff --git a/go/vt/vtgate/vindexes/xxhash_test.go b/go/vt/vtgate/vindexes/xxhash_test.go index 1586f9a4d89..7ccfdc5da6d 100644 --- a/go/vt/vtgate/vindexes/xxhash_test.go +++ b/go/vt/vtgate/vindexes/xxhash_test.go @@ -18,6 +18,7 @@ package vindexes import ( "bytes" + "encoding/hex" "fmt" "reflect" "testing" @@ -94,13 +95,17 @@ func TestXXHashMap(t *testing.T) { } func TestXXHashVerify(t *testing.T) { - ids := []sqltypes.Value{sqltypes.NewUint64(1), sqltypes.NewUint64(2)} - ksids := [][]byte{{0xd4, 0x64, 0x5, 0x36, 0x76, 0x12, 0xb4, 0xb7}, {0xd4, 0x64, 0x5, 0x36, 0x76, 0x12, 0xb4, 0xb7}} + hexValStr := "9efa" + hexValStrSQL := fmt.Sprintf("x'%s'", hexValStr) + hexNumStrSQL := fmt.Sprintf("0x%s", hexValStr) + hexBytes, _ := hex.DecodeString(hexValStr) + ids := []sqltypes.Value{sqltypes.NewUint64(1), sqltypes.NewUint64(2), sqltypes.NewHexVal([]byte(hexValStrSQL)), sqltypes.NewHexNum([]byte(hexNumStrSQL))} + ksids := [][]byte{{0xd4, 0x64, 0x5, 0x36, 0x76, 0x12, 0xb4, 0xb7}, {0xd4, 0x64, 0x5, 0x36, 0x76, 0x12, 0xb4, 0xb7}, vXXHash(hexBytes), vXXHash(hexBytes)} got, err := xxHash.Verify(nil, ids, ksids) if err != nil { t.Fatal(err) } - want := []bool{true, false} + want := []bool{true, false, true, true} if !reflect.DeepEqual(got, want) { t.Errorf("xxHash.Verify: %v, want %v", got, want) } diff --git a/go/vt/vtgate/vstream_manager.go b/go/vt/vtgate/vstream_manager.go index 9c1115018f8..7f4f3f302fd 100644 --- a/go/vt/vtgate/vstream_manager.go +++ b/go/vt/vtgate/vstream_manager.go @@ -23,11 +23,14 @@ import ( "sync" "time" + "vitess.io/vitess/go/vt/discovery" + querypb "vitess.io/vitess/go/vt/proto/query" + "vitess.io/vitess/go/vt/topo" + vtgatepb "vitess.io/vitess/go/vt/proto/vtgate" "google.golang.org/protobuf/proto" - "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/log" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -57,8 +60,10 @@ type vstream struct { journaler map[int64]*journalEvent // err can only be set once. - once sync.Once - err error + // errMu protects err by ensuring its value is read or written by only one goroutine at a time. + once sync.Once + err error + errMu sync.Mutex // Other input parameters tabletType topodatapb.TabletType @@ -73,6 +78,11 @@ type vstream struct { // about the same time as each other. Note that there is no exact ordering of events across shards minimizeSkew bool + // this flag is set by the client, default false + // if true when a reshard is detected the client will send the corresponding journal event to the client + // default behavior is to automatically migrate the resharded streams from the old to the new shards + stopOnReshard bool + // mutex used to synchronize access to skew detection parameters skewMu sync.Mutex // channel is created whenever there is a skew detected. closing it implies the current skew has been fixed @@ -92,6 +102,7 @@ type vstream struct { eventCh chan []*binlogdatapb.VEvent heartbeatInterval uint32 + ts *topo.Server } type journalEvent struct { @@ -114,6 +125,14 @@ func (vsm *vstreamManager) VStream(ctx context.Context, tabletType topodatapb.Ta if err != nil { return err } + ts, err := vsm.toposerv.GetTopoServer() + if err != nil { + return err + } + if ts == nil { + log.Errorf("unable to get topo server in VStream()") + return fmt.Errorf("unable to get topo server") + } vs := &vstream{ vgtid: vgtid, tabletType: tabletType, @@ -122,11 +141,13 @@ func (vsm *vstreamManager) VStream(ctx context.Context, tabletType topodatapb.Ta resolver: vsm.resolver, journaler: make(map[int64]*journalEvent), minimizeSkew: flags.GetMinimizeSkew(), + stopOnReshard: flags.GetStopOnReshard(), skewTimeoutSeconds: 10 * 60, timestamps: make(map[string]int64), vsm: vsm, eventCh: make(chan []*binlogdatapb.VEvent), heartbeatInterval: flags.GetHeartbeatInterval(), + ts: ts, } return vs.stream(ctx) } @@ -205,6 +226,7 @@ func (vsm *vstreamManager) RecordStreamDelay() { func (vsm *vstreamManager) GetTotalStreamDelay() int64 { return vstreamSkewDelayCount.Get() } + func (vs *vstream) stream(ctx context.Context) error { ctx, vs.cancel = context.WithCancel(ctx) defer vs.cancel() @@ -217,7 +239,8 @@ func (vs *vstream) stream(ctx context.Context) error { vs.startOneStream(ctx, sgtid) } vs.wg.Wait() - return vs.err + + return vs.getError() } func (vs *vstream) sendEvents(ctx context.Context) { @@ -239,7 +262,7 @@ func (vs *vstream) sendEvents(ctx context.Context) { send := func(evs []*binlogdatapb.VEvent) error { if err := vs.send(evs); err != nil { vs.once.Do(func() { - vs.err = err + vs.setError(err) }) return err } @@ -249,13 +272,13 @@ func (vs *vstream) sendEvents(ctx context.Context) { select { case <-ctx.Done(): vs.once.Do(func() { - vs.err = fmt.Errorf("context canceled") + vs.setError(fmt.Errorf("context canceled")) }) return case evs := <-vs.eventCh: if err := send(evs); err != nil { vs.once.Do(func() { - vs.err = err + vs.setError(err) }) return } @@ -269,7 +292,7 @@ func (vs *vstream) sendEvents(ctx context.Context) { }} if err := send(evs); err != nil { vs.once.Do(func() { - vs.err = err + vs.setError(err) }) return } @@ -286,8 +309,9 @@ func (vs *vstream) startOneStream(ctx context.Context, sgtid *binlogdatapb.Shard // Set the error on exit. First one wins. if err != nil { + log.Errorf("Error in vstream for %+v: %s", sgtid, err) vs.once.Do(func() { - vs.err = err + vs.setError(err) vs.cancel() }) } @@ -404,25 +428,64 @@ func (vs *vstream) streamFromTablet(ctx context.Context, sgtid *binlogdatapb.Sha var eventss [][]*binlogdatapb.VEvent var err error - rss := vs.rss - if vs.resolver != nil { - rss, err = vs.resolver.ResolveDestination(ctx, sgtid.Keyspace, vs.tabletType, key.DestinationShard(sgtid.Shard)) - if err != nil { - return err - } + tp, err := discovery.NewTabletPicker(vs.ts, []string{vs.vsm.cell}, sgtid.Keyspace, sgtid.Shard, vs.tabletType.String()) + if err != nil { + log.Errorf(err.Error()) + return err } - if len(rss) != 1 { - // Unreachable. - return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unexpected number or shards: %v", rss) + tablet, err := tp.PickForStreaming(ctx) + if err != nil { + log.Errorf(err.Error()) + return err } + log.Infof("Picked tablet %s for for %s/%s/%s/%s", tablet.Alias.String(), vs.vsm.cell, sgtid.Keyspace, sgtid.Shard, vs.tabletType.String()) + target := &querypb.Target{ + Keyspace: sgtid.Keyspace, + Shard: sgtid.Shard, + TabletType: vs.tabletType, + Cell: vs.vsm.cell, + } + tabletConn, err := vs.vsm.resolver.GetGateway().QueryServiceByAlias(tablet.Alias, target) + if err != nil { + log.Errorf(err.Error()) + return err + } + + errCh := make(chan error, 1) + go func() { + _ = tabletConn.StreamHealth(ctx, func(shr *querypb.StreamHealthResponse) error { + var err error + if ctx.Err() != nil { + err = fmt.Errorf("context has ended") + } else if shr == nil || shr.RealtimeStats == nil || shr.Target == nil { + err = fmt.Errorf("health check failed") + } else if vs.tabletType != shr.Target.TabletType { + err = fmt.Errorf("tablet type has changed from %s to %s, restarting vstream", + vs.tabletType, shr.Target.TabletType) + } else if shr.RealtimeStats.HealthError != "" { + err = fmt.Errorf("tablet %s is no longer healthy: %s, restarting vstream", + tablet.Alias, shr.RealtimeStats.HealthError) + } + if err != nil { + errCh <- err + return err + } + return nil + }) + }() + + log.Infof("Starting to vstream from %s", tablet.Alias.String()) // Safe to access sgtid.Gtid here (because it can't change until streaming begins). - err = rss[0].Gateway.VStream(ctx, rss[0].Target, sgtid.Gtid, sgtid.TablePKs, vs.filter, func(events []*binlogdatapb.VEvent) error { + err = tabletConn.VStream(ctx, target, sgtid.Gtid, sgtid.TablePKs, vs.filter, func(events []*binlogdatapb.VEvent) error { // We received a valid event. Reset error count. errCount = 0 select { case <-ctx.Done(): return ctx.Err() + case streamErr := <-errCh: + log.Warningf("Tablet state changed: %s, attempting to restart", streamErr) + return vterrors.New(vtrpcpb.Code_UNAVAILABLE, streamErr.Error()) case <-journalDone: // Unreachable. // This can happen if a server misbehaves and does not end @@ -454,7 +517,7 @@ func (vs *vstream) streamFromTablet(ctx context.Context, sgtid *binlogdatapb.Sha return err } - if err := vs.sendAll(sgtid, eventss); err != nil { + if err := vs.sendAll(ctx, sgtid, eventss); err != nil { return err } eventss = nil @@ -469,7 +532,16 @@ func (vs *vstream) streamFromTablet(ctx context.Context, sgtid *binlogdatapb.Sha case binlogdatapb.VEventType_JOURNAL: journal := event.Journal - // Journal events are not sent to clients. + // Journal events are not sent to clients by default, but only when StopOnReshard is set + if vs.stopOnReshard && journal.MigrationType == binlogdatapb.MigrationType_SHARDS { + sendevents = append(sendevents, event) + eventss = append(eventss, sendevents) + if err := vs.sendAll(ctx, sgtid, eventss); err != nil { + return err + } + eventss = nil + sendevents = nil + } je, err := vs.getJournalEvent(ctx, sgtid, journal) if err != nil { return err @@ -517,14 +589,14 @@ func (vs *vstream) streamFromTablet(ctx context.Context, sgtid *binlogdatapb.Sha } // sendAll sends a group of events together while holding the lock. -func (vs *vstream) sendAll(sgtid *binlogdatapb.ShardGtid, eventss [][]*binlogdatapb.VEvent) error { +func (vs *vstream) sendAll(ctx context.Context, sgtid *binlogdatapb.ShardGtid, eventss [][]*binlogdatapb.VEvent) error { vs.mu.Lock() defer vs.mu.Unlock() // Send all chunks while holding the lock. for _, events := range eventss { - if vs.err != nil { - return vs.err + if err := vs.getError(); err != nil { + return err } // convert all gtids to vgtids. This should be done here while holding the lock. for j, event := range events { @@ -564,11 +636,27 @@ func (vs *vstream) sendAll(sgtid *binlogdatapb.ShardGtid, eventss [][]*binlogdat } } } - vs.eventCh <- events + select { + case <-ctx.Done(): + return nil + case vs.eventCh <- events: + } } return nil } +func (vs *vstream) getError() error { + vs.errMu.Lock() + defer vs.errMu.Unlock() + return vs.err +} + +func (vs *vstream) setError(err error) { + vs.errMu.Lock() + defer vs.errMu.Unlock() + vs.err = err +} + // getJournalEvent returns a journalEvent. The caller has to wait on its done channel. // Once it closes, the caller has to return (end their stream). // The function has three parts: @@ -591,7 +679,7 @@ func (vs *vstream) getJournalEvent(ctx context.Context, sgtid *binlogdatapb.Shar je, ok := vs.journaler[journal.Id] if !ok { - log.Infof("Journal encountered: %v", journal) + log.Infof("Journal event received: %v", journal) // Identify the list of ShardGtids that match the participants of the journal. je = &journalEvent{ journal: journal, @@ -647,24 +735,27 @@ func (vs *vstream) getJournalEvent(ctx context.Context, sgtid *binlogdatapb.Shar return je, nil } } - // All participants are waiting. Replace old shard gtids with new ones. - newsgtids := make([]*binlogdatapb.ShardGtid, 0, len(vs.vgtid.ShardGtids)-len(je.participants)+len(je.journal.ShardGtids)) - log.Infof("Removing shard gtids: %v", je.participants) - for _, cursgtid := range vs.vgtid.ShardGtids { - if je.participants[cursgtid] { - continue - } - newsgtids = append(newsgtids, cursgtid) - } - log.Infof("Adding shard gtids: %v", je.journal.ShardGtids) - for _, sgtid := range je.journal.ShardGtids { - newsgtids = append(newsgtids, sgtid) - // It's ok to start the streams eventhough ShardGtids is not updated yet. - // This is because we're still holding the lock. - vs.startOneStream(ctx, sgtid) + if !vs.stopOnReshard { // stop streaming from current shards and start streaming the new shards + // All participants are waiting. Replace old shard gtids with new ones. + newsgtids := make([]*binlogdatapb.ShardGtid, 0, len(vs.vgtid.ShardGtids)-len(je.participants)+len(je.journal.ShardGtids)) + log.Infof("Removing shard gtids: %v", je.participants) + for _, cursgtid := range vs.vgtid.ShardGtids { + if je.participants[cursgtid] { + continue + } + newsgtids = append(newsgtids, cursgtid) + } + + log.Infof("Adding shard gtids: %v", je.journal.ShardGtids) + for _, sgtid := range je.journal.ShardGtids { + newsgtids = append(newsgtids, sgtid) + // It's ok to start the streams even though ShardGtids are not updated yet. + // This is because we're still holding the lock. + vs.startOneStream(ctx, sgtid) + } + vs.vgtid.ShardGtids = newsgtids } - vs.vgtid.ShardGtids = newsgtids close(je.done) return je, nil } diff --git a/go/vt/vtgate/vstream_manager_test.go b/go/vt/vtgate/vstream_manager_test.go index d51ef388fd5..ec79285a03d 100644 --- a/go/vt/vtgate/vstream_manager_test.go +++ b/go/vt/vtgate/vstream_manager_test.go @@ -23,6 +23,8 @@ import ( "testing" "time" + "vitess.io/vitess/go/vt/topo" + vtgatepb "vitess.io/vitess/go/vt/proto/vtgate" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" @@ -45,29 +47,6 @@ import ( var mu sync.Mutex -func getVEvents(shard string, count, idx int64) []*binlogdatapb.VEvent { - mu.Lock() - defer mu.Unlock() - var vevents []*binlogdatapb.VEvent - var i int64 - currentTime := time.Now().Unix() - for i = count; i > 0; i-- { - j := i + idx - vevents = append(vevents, &binlogdatapb.VEvent{ - Type: binlogdatapb.VEventType_GTID, Gtid: fmt.Sprintf("gtid-%s-%d", shard, j), - Timestamp: currentTime - j, - CurrentTime: currentTime * 1e9, - }) - - vevents = append(vevents, &binlogdatapb.VEvent{ - Type: binlogdatapb.VEventType_COMMIT, - Timestamp: currentTime - j, - CurrentTime: currentTime * 1e9, - }) - } - return vevents -} - func TestVStreamSkew(t *testing.T) { stream := func(conn *sandboxconn.SandboxConn, shard string, count, idx int64) { vevents := getVEvents(shard, count, idx) @@ -94,33 +73,36 @@ func TestVStreamSkew(t *testing.T) { previousDelays := int64(0) vstreamSkewDelayCount = stats.NewCounter("VStreamEventsDelayedBySkewAlignment", "Number of events that had to wait because the skew across shards was too high") + + cell := "aa" for idx, tcase := range tcases { t.Run("", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - name := fmt.Sprintf("TestVStreamSkew-%d", idx) - _ = createSandbox(name) + ks := fmt.Sprintf("TestVStreamSkew-%d", idx) + _ = createSandbox(ks) hc := discovery.NewFakeHealthCheck() - vsm := newTestVStreamManager(hc, new(sandboxTopo), "aa") - shard0 := "-20" - shard1 := "20-40" + st := getSandboxTopo(ctx, cell, ks, []string{"-20", "20-40"}) + vsm := newTestVStreamManager(hc, st, cell) vgtid := &binlogdatapb.VGtid{ShardGtids: []*binlogdatapb.ShardGtid{}} want := int64(0) var sbc0, sbc1 *sandboxconn.SandboxConn if tcase.shard0idx != 0 { - sbc0 = hc.AddTestTablet("aa", "1.1.1.1", 1001, name, shard0, topodatapb.TabletType_MASTER, true, 1, nil) + sbc0 = hc.AddTestTablet(cell, "1.1.1.1", 1001, ks, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-20", sbc0.Tablet()) sbc0.VStreamCh = make(chan *binlogdatapb.VEvent) want += 2 * tcase.numEventsPerShard - vgtid.ShardGtids = append(vgtid.ShardGtids, &binlogdatapb.ShardGtid{Keyspace: name, Gtid: "pos", Shard: "-20"}) - go stream(sbc0, shard0, tcase.numEventsPerShard, tcase.shard0idx) + vgtid.ShardGtids = append(vgtid.ShardGtids, &binlogdatapb.ShardGtid{Keyspace: ks, Gtid: "pos", Shard: "-20"}) + go stream(sbc0, "-20", tcase.numEventsPerShard, tcase.shard0idx) } if tcase.shard1idx != 0 { - sbc1 = hc.AddTestTablet("aa", "1.1.1.1", 1002, name, shard1, topodatapb.TabletType_MASTER, true, 1, nil) + sbc1 = hc.AddTestTablet(cell, "1.1.1.1", 1002, ks, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "20-40", sbc1.Tablet()) sbc1.VStreamCh = make(chan *binlogdatapb.VEvent) want += 2 * tcase.numEventsPerShard - vgtid.ShardGtids = append(vgtid.ShardGtids, &binlogdatapb.ShardGtid{Keyspace: name, Gtid: "pos", Shard: "20-40"}) - go stream(sbc1, shard1, tcase.numEventsPerShard, tcase.shard1idx) + vgtid.ShardGtids = append(vgtid.ShardGtids, &binlogdatapb.ShardGtid{Keyspace: ks, Gtid: "pos", Shard: "20-40"}) + go stream(sbc1, "20-40", tcase.numEventsPerShard, tcase.shard1idx) } ch := startVStream(ctx, t, vsm, vgtid, &vtgatepb.VStreamFlags{MinimizeSkew: true}) var receivedEvents []*binlogdatapb.VEvent @@ -142,12 +124,15 @@ func TestVStreamSkew(t *testing.T) { func TestVStreamEvents(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - - name := "TestVStream" - _ = createSandbox(name) + cell := "aa" + ks := "TestVStream" + _ = createSandbox(ks) hc := discovery.NewFakeHealthCheck() - vsm := newTestVStreamManager(hc, new(sandboxTopo), "aa") - sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + st := getSandboxTopo(ctx, cell, ks, []string{"-20"}) + + vsm := newTestVStreamManager(hc, st, cell) + sbc0 := hc.AddTestTablet(cell, "1.1.1.1", 1001, ks, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-20", sbc0.Tablet()) send1 := []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_GTID, Gtid: "gtid01"}, @@ -158,7 +143,7 @@ func TestVStreamEvents(t *testing.T) { want1 := &binlogdatapb.VStreamResponse{Events: []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_VGTID, Vgtid: &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "gtid01", }}, @@ -176,7 +161,7 @@ func TestVStreamEvents(t *testing.T) { want2 := &binlogdatapb.VStreamResponse{Events: []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_VGTID, Vgtid: &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "gtid02", }}, @@ -187,7 +172,7 @@ func TestVStreamEvents(t *testing.T) { vgtid := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "pos", }}, @@ -217,12 +202,16 @@ func TestVStreamChunks(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - name := "TestVStream" - _ = createSandbox(name) + ks := "TestVStream" + cell := "aa" + _ = createSandbox(ks) hc := discovery.NewFakeHealthCheck() - vsm := newTestVStreamManager(hc, new(sandboxTopo), "aa") - sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - sbc1 := hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + st := getSandboxTopo(ctx, cell, ks, []string{"-20", "20-40"}) + vsm := newTestVStreamManager(hc, st, cell) + sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, ks, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-20", sbc0.Tablet()) + sbc1 := hc.AddTestTablet("aa", "1.1.1.1", 1002, ks, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "20-40", sbc1.Tablet()) for i := 0; i < 100; i++ { sbc0.AddVStreamEvents([]*binlogdatapb.VEvent{{Type: binlogdatapb.VEventType_DDL}}, nil) @@ -236,11 +225,11 @@ func TestVStreamChunks(t *testing.T) { ddlCount := 0 vgtid := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "pos", }, { - Keyspace: name, + Keyspace: ks, Shard: "20-40", Gtid: "pos", }}, @@ -286,13 +275,16 @@ func TestVStreamChunks(t *testing.T) { func TestVStreamMulti(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - - name := "TestVStream" - _ = createSandbox(name) + cell := "aa" + ks := "TestVStream" + _ = createSandbox(ks) hc := discovery.NewFakeHealthCheck() - vsm := newTestVStreamManager(hc, new(sandboxTopo), "aa") - sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - sbc1 := hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + st := getSandboxTopo(ctx, cell, ks, []string{"-20", "20-40"}) + vsm := newTestVStreamManager(hc, st, "aa") + sbc0 := hc.AddTestTablet(cell, "1.1.1.1", 1001, ks, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-20", sbc0.Tablet()) + sbc1 := hc.AddTestTablet(cell, "1.1.1.1", 1002, ks, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "20-40", sbc1.Tablet()) send0 := []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_GTID, Gtid: "gtid01"}, @@ -308,11 +300,11 @@ func TestVStreamMulti(t *testing.T) { vgtid := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "pos", }, { - Keyspace: name, + Keyspace: ks, Shard: "20-40", Gtid: "pos", }}, @@ -328,11 +320,11 @@ func TestVStreamMulti(t *testing.T) { } want := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "gtid01", }, { - Keyspace: name, + Keyspace: ks, Shard: "20-40", Gtid: "gtid02", }}, @@ -346,11 +338,15 @@ func TestVStreamRetry(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - name := "TestVStream" - _ = createSandbox(name) + cell := "aa" + ks := "TestVStream" + _ = createSandbox(ks) hc := discovery.NewFakeHealthCheck() - vsm := newTestVStreamManager(hc, new(sandboxTopo), "aa") - sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + + st := getSandboxTopo(ctx, cell, ks, []string{"-20"}) + vsm := newTestVStreamManager(hc, st, "aa") + sbc0 := hc.AddTestTablet(cell, "1.1.1.1", 1001, ks, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-20", sbc0.Tablet()) commit := []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_COMMIT}, } @@ -363,7 +359,7 @@ func TestVStreamRetry(t *testing.T) { count := 0 vgtid := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "pos", }}, @@ -383,12 +379,14 @@ func TestVStreamRetry(t *testing.T) { func TestVStreamShouldNotSendSourceHeartbeats(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - - name := "TestVStream" - _ = createSandbox(name) + cell := "aa" + ks := "TestVStream" + _ = createSandbox(ks) hc := discovery.NewFakeHealthCheck() - vsm := newTestVStreamManager(hc, new(sandboxTopo), "aa") - sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + st := getSandboxTopo(ctx, cell, ks, []string{"-20"}) + vsm := newTestVStreamManager(hc, st, cell) + sbc0 := hc.AddTestTablet(cell, "1.1.1.1", 1001, ks, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-20", sbc0.Tablet()) send0 := []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_HEARTBEAT}, @@ -406,7 +404,7 @@ func TestVStreamShouldNotSendSourceHeartbeats(t *testing.T) { want := &binlogdatapb.VStreamResponse{Events: []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_VGTID, Vgtid: &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "gtid01", }}, @@ -419,7 +417,7 @@ func TestVStreamShouldNotSendSourceHeartbeats(t *testing.T) { vgtid := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "pos", }}, @@ -431,14 +429,18 @@ func TestVStreamShouldNotSendSourceHeartbeats(t *testing.T) { func TestVStreamJournalOneToMany(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - - name := "TestVStream" - _ = createSandbox(name) + cell := "aa" + ks := "TestVStream" + _ = createSandbox(ks) hc := discovery.NewFakeHealthCheck() - vsm := newTestVStreamManager(hc, new(sandboxTopo), "aa") - sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - sbc1 := hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "-10", topodatapb.TabletType_MASTER, true, 1, nil) - sbc2 := hc.AddTestTablet("aa", "1.1.1.1", 1003, name, "10-20", topodatapb.TabletType_MASTER, true, 1, nil) + st := getSandboxTopo(ctx, cell, ks, []string{"-20", "-10", "10-20"}) + vsm := newTestVStreamManager(hc, st, "aa") + sbc0 := hc.AddTestTablet(cell, "1.1.1.1", 1001, ks, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-20", sbc0.Tablet()) + sbc1 := hc.AddTestTablet(cell, "1.1.1.1", 1002, ks, "-10", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-10", sbc1.Tablet()) + sbc2 := hc.AddTestTablet(cell, "1.1.1.1", 1003, ks, "10-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "10-20", sbc2.Tablet()) send1 := []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_GTID, Gtid: "gtid01"}, @@ -449,7 +451,7 @@ func TestVStreamJournalOneToMany(t *testing.T) { want1 := &binlogdatapb.VStreamResponse{Events: []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_VGTID, Vgtid: &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "gtid01", }}, @@ -465,16 +467,16 @@ func TestVStreamJournalOneToMany(t *testing.T) { Id: 1, MigrationType: binlogdatapb.MigrationType_SHARDS, ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-10", Gtid: "pos10", }, { - Keyspace: name, + Keyspace: ks, Shard: "10-20", Gtid: "pos1020", }}, Participants: []*binlogdatapb.KeyspaceShard{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", }}, }}, @@ -501,7 +503,7 @@ func TestVStreamJournalOneToMany(t *testing.T) { vgtid := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "pos", }}, @@ -517,11 +519,11 @@ func TestVStreamJournalOneToMany(t *testing.T) { Type: binlogdatapb.VEventType_VGTID, Vgtid: &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-10", Gtid: "gtid03", }, { - Keyspace: name, + Keyspace: ks, Shard: "10-20", Gtid: "gtid04", }}, @@ -537,13 +539,18 @@ func TestVStreamJournalManyToOne(t *testing.T) { defer cancel() // Variable names are maintained like in OneToMany, but order is different. - name := "TestVStream" - _ = createSandbox(name) + ks := "TestVStream" + cell := "aa" + _ = createSandbox(ks) hc := discovery.NewFakeHealthCheck() - vsm := newTestVStreamManager(hc, new(sandboxTopo), "aa") - sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - sbc1 := hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "-10", topodatapb.TabletType_MASTER, true, 1, nil) - sbc2 := hc.AddTestTablet("aa", "1.1.1.1", 1003, name, "10-20", topodatapb.TabletType_MASTER, true, 1, nil) + st := getSandboxTopo(ctx, cell, ks, []string{"-20", "-10", "10-20"}) + vsm := newTestVStreamManager(hc, st, cell) + sbc0 := hc.AddTestTablet(cell, "1.1.1.1", 1001, ks, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-20", sbc0.Tablet()) + sbc1 := hc.AddTestTablet(cell, "1.1.1.1", 1002, ks, "-10", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-10", sbc1.Tablet()) + sbc2 := hc.AddTestTablet(cell, "1.1.1.1", 1003, ks, "10-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "10-20", sbc2.Tablet()) send3 := []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_GTID, Gtid: "gtid03"}, @@ -566,15 +573,15 @@ func TestVStreamJournalManyToOne(t *testing.T) { Id: 1, MigrationType: binlogdatapb.MigrationType_SHARDS, ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "pos20", }}, Participants: []*binlogdatapb.KeyspaceShard{{ - Keyspace: name, + Keyspace: ks, Shard: "-10", }, { - Keyspace: name, + Keyspace: ks, Shard: "10-20", }}, }}, @@ -594,7 +601,7 @@ func TestVStreamJournalManyToOne(t *testing.T) { want1 := &binlogdatapb.VStreamResponse{Events: []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_VGTID, Vgtid: &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "gtid01", }}, @@ -608,11 +615,11 @@ func TestVStreamJournalManyToOne(t *testing.T) { vgtid := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-10", Gtid: "pos10", }, { - Keyspace: name, + Keyspace: ks, Shard: "10-20", Gtid: "pos1020", }}, @@ -626,11 +633,11 @@ func TestVStreamJournalManyToOne(t *testing.T) { Type: binlogdatapb.VEventType_VGTID, Vgtid: &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-10", Gtid: "gtid03", }, { - Keyspace: name, + Keyspace: ks, Shard: "10-20", Gtid: "gtid04", }}, @@ -646,11 +653,14 @@ func TestVStreamJournalNoMatch(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - name := "TestVStream" - _ = createSandbox(name) + ks := "TestVStream" + cell := "aa" + _ = createSandbox(ks) hc := discovery.NewFakeHealthCheck() - vsm := newTestVStreamManager(hc, new(sandboxTopo), "aa") - sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + st := getSandboxTopo(ctx, cell, ks, []string{"-20"}) + vsm := newTestVStreamManager(hc, st, "aa") + sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, ks, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-20", sbc0.Tablet()) send1 := []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_GTID, Gtid: "gtid01"}, @@ -661,7 +671,7 @@ func TestVStreamJournalNoMatch(t *testing.T) { want1 := &binlogdatapb.VStreamResponse{Events: []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_VGTID, Vgtid: &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "gtid01", }}, @@ -683,7 +693,7 @@ func TestVStreamJournalNoMatch(t *testing.T) { wantjn1 := &binlogdata.VStreamResponse{Events: []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_VGTID, Vgtid: &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "jn1", }}, @@ -699,7 +709,7 @@ func TestVStreamJournalNoMatch(t *testing.T) { want2 := &binlogdatapb.VStreamResponse{Events: []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_VGTID, Vgtid: &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "gtid02", }}, @@ -713,15 +723,15 @@ func TestVStreamJournalNoMatch(t *testing.T) { Id: 2, MigrationType: binlogdatapb.MigrationType_SHARDS, ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "c0-", Gtid: "posc0", }}, Participants: []*binlogdatapb.KeyspaceShard{{ - Keyspace: name, + Keyspace: ks, Shard: "c0-e0", }, { - Keyspace: name, + Keyspace: ks, Shard: "e0-", }}, }}, @@ -731,7 +741,7 @@ func TestVStreamJournalNoMatch(t *testing.T) { wantjn2 := &binlogdata.VStreamResponse{Events: []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_VGTID, Vgtid: &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "jn2", }}, @@ -747,7 +757,7 @@ func TestVStreamJournalNoMatch(t *testing.T) { want3 := &binlogdatapb.VStreamResponse{Events: []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_VGTID, Vgtid: &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "gtid03", }}, @@ -758,7 +768,7 @@ func TestVStreamJournalNoMatch(t *testing.T) { vgtid := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "pos", }}, @@ -772,27 +782,31 @@ func TestVStreamJournalPartialMatch(t *testing.T) { defer cancel() // Variable names are maintained like in OneToMany, but order is different.1 - name := "TestVStream" - _ = createSandbox(name) + ks := "TestVStream" + cell := "aa" + _ = createSandbox(ks) hc := discovery.NewFakeHealthCheck() - vsm := newTestVStreamManager(hc, new(sandboxTopo), "aa") - _ = hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "-10", topodatapb.TabletType_MASTER, true, 1, nil) - sbc2 := hc.AddTestTablet("aa", "1.1.1.1", 1003, name, "10-20", topodatapb.TabletType_MASTER, true, 1, nil) + st := getSandboxTopo(ctx, cell, ks, []string{"-20", "-10", "10-20"}) + vsm := newTestVStreamManager(hc, st, "aa") + sbc1 := hc.AddTestTablet("aa", "1.1.1.1", 1002, ks, "-10", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-10", sbc1.Tablet()) + sbc2 := hc.AddTestTablet("aa", "1.1.1.1", 1003, ks, "10-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "10-20", sbc2.Tablet()) send := []*binlogdatapb.VEvent{ {Type: binlogdatapb.VEventType_JOURNAL, Journal: &binlogdatapb.Journal{ Id: 1, MigrationType: binlogdatapb.MigrationType_SHARDS, ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "10-30", Gtid: "pos1040", }}, Participants: []*binlogdatapb.KeyspaceShard{{ - Keyspace: name, + Keyspace: ks, Shard: "10-20", }, { - Keyspace: name, + Keyspace: ks, Shard: "20-30", }}, }}, @@ -801,11 +815,11 @@ func TestVStreamJournalPartialMatch(t *testing.T) { vgtid := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-10", Gtid: "pos10", }, { - Keyspace: name, + Keyspace: ks, Shard: "10-20", Gtid: "pos1020", }}, @@ -825,15 +839,15 @@ func TestVStreamJournalPartialMatch(t *testing.T) { Id: 1, MigrationType: binlogdatapb.MigrationType_SHARDS, ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "10-30", Gtid: "pos1040", }}, Participants: []*binlogdatapb.KeyspaceShard{{ - Keyspace: name, + Keyspace: ks, Shard: "20-30", }, { - Keyspace: name, + Keyspace: ks, Shard: "10-20", }}, }}, @@ -994,14 +1008,17 @@ func TestResolveVStreamParams(t *testing.T) { } func TestVStreamIdleHeartbeat(t *testing.T) { - name := "TestVStream" - _ = createSandbox(name) + cell := "aa" + ks := "TestVStream" + _ = createSandbox(ks) hc := discovery.NewFakeHealthCheck() - vsm := newTestVStreamManager(hc, new(sandboxTopo), "aa") - hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + st := getSandboxTopo(ctx, cell, ks, []string{"-20"}) + vsm := newTestVStreamManager(hc, st, cell) + sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, ks, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + addTabletToSandboxTopo(t, st, ks, "-20", sbc0.Tablet()) vgtid := &binlogdatapb.VGtid{ ShardGtids: []*binlogdatapb.ShardGtid{{ - Keyspace: name, + Keyspace: ks, Shard: "-20", Gtid: "pos", }}, @@ -1069,6 +1086,7 @@ func verifyEvents(t *testing.T, ch <-chan *binlogdatapb.VStreamResponse, wants . t.Helper() for i, want := range wants { got := <-ch + require.NotNil(t, got) for _, event := range got.Events { event.Timestamp = 0 } @@ -1077,3 +1095,47 @@ func verifyEvents(t *testing.T, ch <-chan *binlogdatapb.VStreamResponse, wants . } } } + +func getVEvents(shard string, count, idx int64) []*binlogdatapb.VEvent { + mu.Lock() + defer mu.Unlock() + var vevents []*binlogdatapb.VEvent + var i int64 + currentTime := time.Now().Unix() + for i = count; i > 0; i-- { + j := i + idx + vevents = append(vevents, &binlogdatapb.VEvent{ + Type: binlogdatapb.VEventType_GTID, Gtid: fmt.Sprintf("gtid-%s-%d", shard, j), + Timestamp: currentTime - j, + CurrentTime: currentTime * 1e9, + }) + + vevents = append(vevents, &binlogdatapb.VEvent{ + Type: binlogdatapb.VEventType_COMMIT, + Timestamp: currentTime - j, + CurrentTime: currentTime * 1e9, + }) + } + return vevents +} + +func getSandboxTopo(ctx context.Context, cell string, keyspace string, shards []string) *sandboxTopo { + st := newSandboxForCells([]string{cell}) + ts := st.topoServer + ts.CreateCellInfo(ctx, cell, &topodatapb.CellInfo{}) + ts.CreateKeyspace(ctx, keyspace, &topodatapb.Keyspace{}) + for _, shard := range shards { + ts.CreateShard(ctx, keyspace, shard) + } + return st +} + +func addTabletToSandboxTopo(t *testing.T, st *sandboxTopo, ks, shard string, tablet *topodatapb.Tablet) { + _, err := st.topoServer.UpdateShardFields(ctx, ks, shard, func(si *topo.ShardInfo) error { + si.MasterAlias = tablet.Alias + return nil + }) + require.NoError(t, err) + err = st.topoServer.CreateTablet(ctx, tablet) + require.NoError(t, err) +} diff --git a/go/vt/vtgate/vtgate.go b/go/vt/vtgate/vtgate.go index e3aaf49fd18..938f191a31d 100644 --- a/go/vt/vtgate/vtgate.go +++ b/go/vt/vtgate/vtgate.go @@ -25,6 +25,7 @@ import ( "os" "strings" "time" + "vitess.io/vitess/go/vt/vtgate/boost" "vitess.io/vitess/go/vt/key" @@ -79,7 +80,7 @@ var ( warnPayloadSize = flag.Int("warn_payload_size", 0, "The warning threshold for query payloads in bytes. A payload greater than this threshold will cause the VtGateWarnings.WarnPayloadSizeExceeded counter to be incremented.") // Put set-passthrough under a flag. - sysVarSetEnabled = flag.Bool("enable_system_settings", true, "This will enable the system settings to be changed per session at the database connection level") + sysVarSetEnabled = flag.Bool("enable_system_settings", false, "This will enable the system settings to be changed per session at the database connection level") plannerVersion = flag.String("planner_version", "v3", "Sets the default planner to use when the session has not changed it. Valid values are: V3, Gen4, Gen4Greedy and Gen4Fallback. Gen4Fallback tries the new gen4 planner and falls back to the V3 planner if the gen4 fails. All Gen4 versions should be considered experimental!") // lockHeartbeatTime is used to set the next heartbeat time. @@ -157,7 +158,7 @@ type RegisterVTGate func(vtgateservice.VTGateService) var RegisterVTGates []RegisterVTGate // Init initializes VTGate server. -func Init(ctx context.Context, serv srvtopo.Server, cell string, tabletTypesToWait []topodatapb.TabletType) *VTGate { +func Init(ctx context.Context, serv srvtopo.Server, cell string, tabletTypesToWait []topodatapb.TabletType, boostQueryFilterConfigPath *string) *VTGate { if rpcVTGate != nil { log.Fatalf("VTGate already initialized") } @@ -214,7 +215,9 @@ func Init(ctx context.Context, serv srvtopo.Server, cell string, tabletTypesToWa LFU: *queryPlanCacheLFU, } - executor := NewExecutor(ctx, serv, cell, resolver, *normalizeQueries, *warnShardedOnly, *streamBufferSize, cacheCfg, si) + queryFilterConfigs, _ := boost.Load(boostQueryFilterConfigPath) + + executor := NewExecutor(ctx, serv, cell, resolver, *normalizeQueries, *warnShardedOnly, *streamBufferSize, cacheCfg, si, queryFilterConfigs) // connect the schema tracker with the vschema manager if *enableSchemaChangeSignal { @@ -617,8 +620,11 @@ func LegacyInit(ctx context.Context, hc discovery.LegacyHealthCheck, serv srvtop LFU: *queryPlanCacheLFU, } + //queryFilterConfigs := boost.Load() + queryFilterConfigs := &boost.QueryFilterConfigs{} + rpcVTGate = &VTGate{ - executor: NewExecutor(ctx, serv, cell, resolver, *normalizeQueries, *warnShardedOnly, *streamBufferSize, cacheCfg, nil), + executor: NewExecutor(ctx, serv, cell, resolver, *normalizeQueries, *warnShardedOnly, *streamBufferSize, cacheCfg, nil, queryFilterConfigs), resolver: resolver, vsm: vsm, txConn: tc, diff --git a/go/vt/vttablet/endtoend/vstreamer_test.go b/go/vt/vttablet/endtoend/vstreamer_test.go index cacb2e102bc..3fefa15b80b 100644 --- a/go/vt/vttablet/endtoend/vstreamer_test.go +++ b/go/vt/vttablet/endtoend/vstreamer_test.go @@ -98,7 +98,7 @@ func TestSchemaVersioning(t *testing.T) { { query: "insert into vitess_version values(1, 10)", output: []string{ - `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"}}`, `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 values:"110"}}}`, `gtid`, }, @@ -113,7 +113,7 @@ func TestSchemaVersioning(t *testing.T) { }, { query: "insert into vitess_version values(2, 20, 200)", output: []string{ - `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63} fields:{name:"id3" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:11 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id3" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:11 charset:63 column_type:"int(11)"}}`, `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 values:"220200"}}}`, `gtid`, }, @@ -128,7 +128,7 @@ func TestSchemaVersioning(t *testing.T) { }, { query: "insert into vitess_version values(3, 30, 'TTT')", output: []string{ - `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63 column_type:"varbinary(16)"}}`, `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 values:"330TTT"}}}`, `gtid`, }, @@ -179,7 +179,7 @@ func TestSchemaVersioning(t *testing.T) { }, { query: "insert into vitess_version values(4, 40, 'FFF', 'GGGG' )", output: []string{ - `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63} fields:{name:"id4" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id4" column_length:16 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63 column_type:"varbinary(16)"} fields:{name:"id4" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id4" column_length:16 charset:63 column_type:"varbinary(16)"}}`, `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 lengths:4 values:"440FFFGGGG"}}}`, `gtid`, }, @@ -223,26 +223,26 @@ func TestSchemaVersioning(t *testing.T) { getSchemaVersionTableCreationEvents()...), `version`, `gtid`, - `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"}}`, `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 values:"110"}}}`, `gtid`, `gtid`, `type:DDL statement:"alter table vitess_version add column id3 int"`, `version`, `gtid`, - `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63} fields:{name:"id3" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:11 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id3" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:11 charset:63 column_type:"varbinary(16)"}}`, `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 values:"220200"}}}`, `gtid`, `gtid`, `type:DDL statement:"alter table vitess_version modify column id3 varbinary(16)"`, `version`, `gtid`, - `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63 column_type:"varbinary(16)"}}`, `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 values:"330TTT"}}}`, `gtid`, `gtid`, `type:DDL statement:"/**/alter table vitess_version add column id4 varbinary(16)"`, - `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63} fields:{name:"id4" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id4" column_length:16 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63 column_type:"varbinary(16)"} fields:{name:"id4" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id4" column_length:16 charset:63 column_type:"varbinary(16)"}}`, `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 lengths:4 values:"440FFFGGGG"}}}`, `gtid`, ) @@ -287,7 +287,7 @@ func TestSchemaVersioning(t *testing.T) { getSchemaVersionTableCreationEvents()...), `version`, `gtid`, - `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"}}`, `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 values:"110"}}}`, `gtid`, `gtid`, @@ -304,12 +304,12 @@ func TestSchemaVersioning(t *testing.T) { `gtid`, /*at this point we only have latest schema so we have types (int32, int32, varbinary, varbinary), but the three fields below match the first three types in the latest, so the field names are correct*/ - `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63 column_type:"varbinary(16)"}}`, `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 values:"330TTT"}}}`, `gtid`, `gtid`, `type:DDL statement:"/**/alter table vitess_version add column id4 varbinary(16)"`, - `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63} fields:{name:"id4" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id4" column_length:16 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63 column_type:"varbinary(16)"} fields:{name:"id4" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id4" column_length:16 charset:63 column_type:"varbinary(16)"}}`, `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 lengths:4 values:"440FFFGGGG"}}}`, `gtid`, ) diff --git a/go/vt/vttablet/onlineddl/executor.go b/go/vt/vttablet/onlineddl/executor.go index 9ec3ac42c0a..db5431d6659 100644 --- a/go/vt/vttablet/onlineddl/executor.go +++ b/go/vt/vttablet/onlineddl/executor.go @@ -227,14 +227,14 @@ func (e *Executor) initSchema(ctx context.Context) error { defer e.env.LogError() - conn, err := e.pool.Get(ctx) + conn, err := dbconnpool.NewDBConnection(ctx, e.env.Config().DB.DbaConnector()) if err != nil { return err } - defer conn.Recycle() + defer conn.Close() for _, ddl := range ApplyDDL { - _, err := conn.Exec(ctx, ddl, math.MaxInt32, false) + _, err := conn.ExecuteFetch(ddl, math.MaxInt32, false) if mysql.IsSchemaApplyError(err) { continue } @@ -420,15 +420,9 @@ func (e *Executor) dropOnlineDDLUser(ctx context.Context) error { // tableExists checks if a given table exists. func (e *Executor) tableExists(ctx context.Context, tableName string) (bool, error) { - conn, err := e.pool.Get(ctx) - if err != nil { - return false, err - } - defer conn.Recycle() - tableName = strings.ReplaceAll(tableName, `_`, `\_`) parsed := sqlparser.BuildParsedQuery(sqlShowTablesLike, tableName) - rs, err := conn.Exec(ctx, parsed.Query, 1, true) + rs, err := e.execQuery(ctx, parsed.Query) if err != nil { return false, err } @@ -1052,7 +1046,6 @@ exit $exit_code return err } // Migration successful! - os.RemoveAll(tempDir) successfulMigrations.Add(1) log.Infof("+ OK") return nil @@ -1276,7 +1269,6 @@ export MYSQL_PWD return err } // Migration successful! - os.RemoveAll(tempDir) successfulMigrations.Add(1) log.Infof("+ OK") return nil @@ -2315,15 +2307,13 @@ func (e *Executor) reviewStaleMigrations(ctx context.Context) error { e.migrationMutex.Lock() defer e.migrationMutex.Unlock() - parsed := sqlparser.BuildParsedQuery(sqlSelectStaleMigrations, ":minutes") - bindVars := map[string]*querypb.BindVariable{ - "minutes": sqltypes.Int64BindVariable(staleMigrationMinutes), - } - bound, err := parsed.GenerateQuery(bindVars, nil) + query, err := sqlparser.ParseAndBind(sqlSelectStaleMigrations, + sqltypes.Int64BindVariable(staleMigrationMinutes), + ) if err != nil { return err } - r, err := e.execQuery(ctx, bound) + r, err := e.execQuery(ctx, query) if err != nil { return err } @@ -2350,6 +2340,10 @@ func (e *Executor) reviewStaleMigrations(ctx context.Context) error { if err := e.updateMigrationStatus(ctx, onlineDDL.UUID, schema.OnlineDDLStatusFailed); err != nil { return err } + _ = e.updateMigrationStartedTimestamp(ctx, uuid) + if err := e.updateMigrationTimestamp(ctx, "completed_timestamp", uuid); err != nil { + return err + } _ = e.updateMigrationMessage(ctx, onlineDDL.UUID, "stale migration") } @@ -2364,7 +2358,7 @@ func (e *Executor) retryTabletFailureMigrations(ctx context.Context) error { } // gcArtifactTable garbage-collects a single table -func (e *Executor) gcArtifactTable(ctx context.Context, artifactTable, uuid string) error { +func (e *Executor) gcArtifactTable(ctx context.Context, artifactTable, uuid string, t time.Time) error { tableExists, err := e.tableExists(ctx, artifactTable) if err != nil { return err @@ -2374,17 +2368,11 @@ func (e *Executor) gcArtifactTable(ctx context.Context, artifactTable, uuid stri } // We've already concluded in gcArtifacts() that this table was held for long enough. // We therefore move it into PURGE state. - renameStatement, _, err := schema.GenerateRenameStatementWithUUID(artifactTable, schema.PurgeTableGCState, schema.OnlineDDLToGCUUID(uuid), time.Now().UTC()) - if err != nil { - return err - } - conn, err := e.pool.Get(ctx) + renameStatement, _, err := schema.GenerateRenameStatementWithUUID(artifactTable, schema.PurgeTableGCState, schema.OnlineDDLToGCUUID(uuid), t) if err != nil { return err } - defer conn.Recycle() - - _, err = conn.Exec(ctx, renameStatement, 1, true) + _, err = e.execQuery(ctx, renameStatement) return err } @@ -2393,6 +2381,13 @@ func (e *Executor) gcArtifacts(ctx context.Context) error { e.migrationMutex.Lock() defer e.migrationMutex.Unlock() + if _, err := e.execQuery(ctx, sqlFixCompletedTimestamp); err != nil { + // This query fixes a bug where stale migrations were marked as 'failed' without updating 'completed_timestamp' + // see https://github.com/vitessio/vitess/issues/8499 + // Running this query retroactively sets completed_timestamp + // This 'if' clause can be removed in version v13 + return err + } query, err := sqlparser.ParseAndBind(sqlSelectUncollectedArtifacts, sqltypes.Int64BindVariable(int64((*retainOnlineDDLTables).Seconds())), ) @@ -2406,14 +2401,32 @@ func (e *Executor) gcArtifacts(ctx context.Context) error { for _, row := range r.Named().Rows { uuid := row["migration_uuid"].ToString() artifacts := row["artifacts"].ToString() + logPath := row["log_path"].ToString() + // Remove tables: artifactTables := textutil.SplitDelimitedList(artifacts) - for _, artifactTable := range artifactTables { - if err := e.gcArtifactTable(ctx, artifactTable, uuid); err != nil { + + timeNow := time.Now() + for i, artifactTable := range artifactTables { + // We wish to generate distinct timestamp values for each table in this UUID, + // because all tables will be renamed as _something_UUID_timestamp. Since UUID + // is shared for all artifacts in this loop, we differentiate via timestamp + t := timeNow.Add(time.Duration(i) * time.Second).UTC() + if err := e.gcArtifactTable(ctx, artifactTable, uuid, t); err != nil { return err } log.Infof("Executor.gcArtifacts: renamed away artifact %s", artifactTable) } + + // Remove logs: + { + // logPath is in 'hostname:/path/to/logs' format + tokens := strings.SplitN(logPath, ":", 2) + logPath = tokens[len(tokens)-1] + if err := os.RemoveAll(logPath); err != nil { + return err + } + } if err := e.updateMigrationTimestamp(ctx, "cleanup_timestamp", uuid); err != nil { return err } @@ -2504,10 +2517,12 @@ func (e *Executor) updateMigrationTimestamp(ctx context.Context, timestampColumn return err } -func (e *Executor) updateMigrationLogPath(ctx context.Context, uuid string, hostname, path string) error { - logPath := fmt.Sprintf("%s:%s", hostname, path) +func (e *Executor) updateMigrationLogPath(ctx context.Context, uuid string, hostname, logPath string) error { + logFile := path.Join(logPath, migrationLogFileName) + hostLogPath := fmt.Sprintf("%s:%s", hostname, logPath) query, err := sqlparser.ParseAndBind(sqlUpdateMigrationLogPath, - sqltypes.StringBindVariable(logPath), + sqltypes.StringBindVariable(hostLogPath), + sqltypes.StringBindVariable(logFile), sqltypes.StringBindVariable(uuid), ) if err != nil { @@ -2792,6 +2807,39 @@ func (e *Executor) SubmitMigration( return e.execQuery(ctx, query) } +// ShowMigrationLogs reads the migration log for a given migration +func (e *Executor) ShowMigrationLogs(ctx context.Context, stmt *sqlparser.ShowMigrationLogs) (result *sqltypes.Result, err error) { + if !e.isOpen { + return nil, vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "online ddl is disabled") + } + _, row, err := e.readMigration(ctx, stmt.UUID) + if err != nil { + return nil, err + } + logFile := row["log_file"].ToString() + if logFile == "" { + return nil, vterrors.Errorf(vtrpcpb.Code_NOT_FOUND, "No log file for migration %v", stmt.UUID) + } + content, err := ioutil.ReadFile(logFile) + if err != nil { + return nil, err + } + + result = &sqltypes.Result{ + Fields: []*querypb.Field{ + { + Name: "migration_log", + Type: sqltypes.VarChar, + }, + }, + Rows: [][]sqltypes.Value{}, + } + result.Rows = append(result.Rows, []sqltypes.Value{ + sqltypes.NewVarChar(string(content)), + }) + return result, nil +} + // onSchemaMigrationStatus is called when a status is set/changed for a running migration func (e *Executor) onSchemaMigrationStatus(ctx context.Context, uuid string, status schema.OnlineDDLStatus, dryRun bool, progressPct float64, etaSeconds int64, rowsCopied int64) (err error) { diff --git a/go/vt/vttablet/onlineddl/schema.go b/go/vt/vttablet/onlineddl/schema.go index 0ffe9c42b9c..ff311a71a9e 100644 --- a/go/vt/vttablet/onlineddl/schema.go +++ b/go/vt/vttablet/onlineddl/schema.go @@ -58,6 +58,7 @@ const ( alterSchemaMigrationsTableETASeconds = "ALTER TABLE _vt.schema_migrations add column eta_seconds bigint NOT NULL DEFAULT -1" alterSchemaMigrationsTableRowsCopied = "ALTER TABLE _vt.schema_migrations add column rows_copied bigint unsigned NOT NULL DEFAULT 0" alterSchemaMigrationsTableTableRows = "ALTER TABLE _vt.schema_migrations add column table_rows bigint NOT NULL DEFAULT 0" + alterSchemaMigrationsTableLogFile = "ALTER TABLE _vt.schema_migrations add column log_file varchar(1024) NOT NULL DEFAULT ''" sqlInsertMigration = `INSERT IGNORE INTO _vt.schema_migrations ( migration_uuid, @@ -112,8 +113,9 @@ const ( WHERE migration_uuid=%a ` - sqlUpdateMigrationStartedTimestamp = `UPDATE _vt.schema_migrations - SET started_timestamp=IFNULL(started_timestamp, NOW()) + sqlUpdateMigrationStartedTimestamp = `UPDATE _vt.schema_migrations SET + started_timestamp =IFNULL(started_timestamp, NOW()), + liveness_timestamp=IFNULL(liveness_timestamp, NOW()) WHERE migration_uuid=%a ` @@ -123,12 +125,12 @@ const ( migration_uuid=%a ` sqlUpdateMigrationLogPath = `UPDATE _vt.schema_migrations - SET log_path=%a + SET log_path=%a, log_file=%a WHERE migration_uuid=%a ` sqlUpdateArtifacts = `UPDATE _vt.schema_migrations - SET artifacts=concat(%a, ',', artifacts) + SET artifacts=concat(%a, ',', artifacts), cleanup_timestamp=NULL WHERE migration_uuid=%a ` @@ -256,13 +258,22 @@ const ( ` sqlSelectUncollectedArtifacts = `SELECT migration_uuid, - artifacts + artifacts, + log_path FROM _vt.schema_migrations WHERE migration_status IN ('complete', 'failed') AND cleanup_timestamp IS NULL AND completed_timestamp <= NOW() - INTERVAL %a SECOND ` + sqlFixCompletedTimestamp = `UPDATE _vt.schema_migrations + SET + completed_timestamp=NOW() + WHERE + migration_status='failed' + AND cleanup_timestamp IS NULL + AND completed_timestamp IS NULL + ` sqlSelectMigration = `SELECT id, migration_uuid, @@ -280,6 +291,7 @@ const ( completed_timestamp, migration_status, log_path, + log_file, retries, ddl_action, artifacts, @@ -306,6 +318,7 @@ const ( completed_timestamp, migration_status, log_path, + log_file, retries, ddl_action, artifacts, @@ -433,4 +446,5 @@ var ApplyDDL = []string{ alterSchemaMigrationsTableETASeconds, alterSchemaMigrationsTableRowsCopied, alterSchemaMigrationsTableTableRows, + alterSchemaMigrationsTableLogFile, } diff --git a/go/vt/vttablet/onlineddl/vrepl.go b/go/vt/vttablet/onlineddl/vrepl.go index 851fbdd3ffb..2aa3df7deb8 100644 --- a/go/vt/vttablet/onlineddl/vrepl.go +++ b/go/vt/vttablet/onlineddl/vrepl.go @@ -167,7 +167,7 @@ func (v *VRepl) readTableColumns(ctx context.Context, conn *dbconnpool.DBConnect columnNames = append(columnNames, columnName) extra := row.AsString("Extra", "") - if strings.Contains(extra, "VIRTUAL") || strings.Contains(extra, "GENERATED") { + if strings.Contains(extra, "STORED GENERATED") || strings.Contains(extra, "VIRTUAL GENERATED") { virtualColumnNames = append(virtualColumnNames, columnName) } diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index ccaef04a22f..f371e510981 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -51,7 +51,7 @@ func (tm *TabletManager) ReplicationStatus(ctx context.Context) (*replicationdat return mysql.ReplicationStatusToProto(status), nil } -// MasterStatus returns the replication status fopr a master tablet. +// MasterStatus returns the replication status for a master tablet. func (tm *TabletManager) MasterStatus(ctx context.Context) (*replicationdatapb.MasterStatus, error) { return tm.PrimaryStatus(ctx) } @@ -81,6 +81,7 @@ func (tm *TabletManager) PrimaryPosition(ctx context.Context) (string, error) { // WaitForPosition waits until replication reaches the desired position func (tm *TabletManager) WaitForPosition(ctx context.Context, pos string) error { + log.Infof("WaitForPosition: %v", pos) mpos, err := mysql.DecodePosition(pos) if err != nil { return err @@ -91,6 +92,7 @@ func (tm *TabletManager) WaitForPosition(ctx context.Context, pos string) error // StopReplication will stop the mysql. Works both when Vitess manages // replication or not (using hook if not). func (tm *TabletManager) StopReplication(ctx context.Context) error { + log.Infof("StopReplication") if err := tm.lock(ctx); err != nil { return err } @@ -143,6 +145,7 @@ func (tm *TabletManager) stopIOThreadLocked(ctx context.Context) error { // provided position. Works both when Vitess manages // replication or not (using hook if not). func (tm *TabletManager) StopReplicationMinimum(ctx context.Context, position string, waitTime time.Duration) (string, error) { + log.Infof("StopReplicationMinimum: position: %v waitTime: %v", position, waitTime) if err := tm.lock(ctx); err != nil { return "", err } @@ -170,6 +173,7 @@ func (tm *TabletManager) StopReplicationMinimum(ctx context.Context, position st // StartReplication will start the mysql. Works both when Vitess manages // replication or not (using hook if not). func (tm *TabletManager) StartReplication(ctx context.Context) error { + log.Infof("StartReplication") if err := tm.lock(ctx); err != nil { return err } @@ -197,6 +201,7 @@ func (tm *TabletManager) StartReplication(ctx context.Context) error { // StartReplicationUntilAfter will start the replication and let it catch up // until and including the transactions in `position` func (tm *TabletManager) StartReplicationUntilAfter(ctx context.Context, position string, waitTime time.Duration) error { + log.Infof("StartReplicationUntilAfter: position: %v waitTime: %v", position, waitTime) if err := tm.lock(ctx); err != nil { return err } @@ -221,6 +226,7 @@ func (tm *TabletManager) GetReplicas(ctx context.Context) ([]string, error) { // ResetReplication completely resets the replication on the host. // All binary and relay logs are flushed. All replication positions are reset. func (tm *TabletManager) ResetReplication(ctx context.Context) error { + log.Infof("ResetReplication") if err := tm.lock(ctx); err != nil { return err } @@ -237,6 +243,7 @@ func (tm *TabletManager) InitMaster(ctx context.Context) (string, error) { // InitPrimary enables writes and returns the replication position. func (tm *TabletManager) InitPrimary(ctx context.Context) (string, error) { + log.Infof("InitPrimary") if err := tm.lock(ctx); err != nil { return "", err } @@ -276,6 +283,7 @@ func (tm *TabletManager) InitPrimary(ctx context.Context) (string, error) { // PopulateReparentJournal adds an entry into the reparent_journal table. func (tm *TabletManager) PopulateReparentJournal(ctx context.Context, timeCreatedNS int64, actionName string, masterAlias *topodatapb.TabletAlias, position string) error { + log.Infof("PopulateReparentJournal: action: %v parent: %v position: %v", actionName, masterAlias, position) pos, err := mysql.DecodePosition(position) if err != nil { return err @@ -289,6 +297,7 @@ func (tm *TabletManager) PopulateReparentJournal(ctx context.Context, timeCreate // InitReplica sets replication master and position, and waits for the // reparent_journal table entry up to context timeout func (tm *TabletManager) InitReplica(ctx context.Context, parent *topodatapb.TabletAlias, position string, timeCreatedNS int64) error { + log.Infof("InitReplica: parent: %v position: %v", parent, position) if err := tm.lock(ctx); err != nil { return err } @@ -352,6 +361,7 @@ func (tm *TabletManager) InitReplica(ctx context.Context, parent *topodatapb.Tab // // If a step fails in the middle, it will try to undo any changes it made. func (tm *TabletManager) DemotePrimary(ctx context.Context) (*replicationdatapb.MasterStatus, error) { + log.Infof("DemotePrimary") // The public version always reverts on partial failure. return tm.demotePrimary(ctx, true /* revertPartialFailure */) } @@ -468,6 +478,7 @@ func (tm *TabletManager) UndoDemoteMaster(ctx context.Context) error { // it sets read-only to false, fixes semi-sync // and returns its master position. func (tm *TabletManager) UndoDemotePrimary(ctx context.Context) error { + log.Infof("UndoDemotePrimary") if err := tm.lock(ctx); err != nil { return err } @@ -504,12 +515,14 @@ func (tm *TabletManager) UndoDemotePrimary(ctx context.Context) error { // ReplicaWasPromoted promotes a replica to master, no questions asked. func (tm *TabletManager) ReplicaWasPromoted(ctx context.Context) error { + log.Infof("ReplicaWasPromoted") return tm.ChangeType(ctx, topodatapb.TabletType_MASTER) } // SetReplicationSource sets replication master, and waits for the // reparent_journal table entry up to context timeout func (tm *TabletManager) SetReplicationSource(ctx context.Context, parentAlias *topodatapb.TabletAlias, timeCreatedNS int64, waitPosition string, forceStartReplication bool) error { + log.Infof("SetReplicationSource: parent: %v position: %v force: %v", parentAlias, waitPosition, forceStartReplication) if err := tm.lock(ctx); err != nil { return err } @@ -649,6 +662,8 @@ func (tm *TabletManager) setReplicationSourceLocked(ctx context.Context, parentA return err } } + // Clear replication sentinel flag for this replica + tm.replManager.setReplicationStopped(false) } return nil @@ -656,6 +671,7 @@ func (tm *TabletManager) setReplicationSourceLocked(ctx context.Context, parentA // ReplicaWasRestarted updates the parent record for a tablet. func (tm *TabletManager) ReplicaWasRestarted(ctx context.Context, parent *topodatapb.TabletAlias) error { + log.Infof("ReplicaWasRestarted: parent: %v", parent) if err := tm.lock(ctx); err != nil { return err } @@ -673,6 +689,7 @@ func (tm *TabletManager) ReplicaWasRestarted(ctx context.Context, parent *topoda // StopReplicationAndGetStatus stops MySQL replication, and returns the // current status. func (tm *TabletManager) StopReplicationAndGetStatus(ctx context.Context, stopReplicationMode replicationdatapb.StopReplicationMode) (StopReplicationAndGetStatusResponse, error) { + log.Infof("StopReplicationAndGetStatus: mode: %v", stopReplicationMode) if err := tm.lock(ctx); err != nil { return StopReplicationAndGetStatusResponse{}, err } @@ -763,6 +780,7 @@ type StopReplicationAndGetStatusResponse struct { // PromoteReplica makes the current tablet the master func (tm *TabletManager) PromoteReplica(ctx context.Context) (string, error) { + log.Infof("PromoteReplica") if err := tm.lock(ctx); err != nil { return "", err } @@ -782,6 +800,10 @@ func (tm *TabletManager) PromoteReplica(ctx context.Context) (string, error) { return "", err } + // Clear replication sentinel flag for this master, + // or we might block replication the next time we demote it + tm.replManager.setReplicationStopped(false) + return mysql.EncodePosition(pos), nil } diff --git a/go/vt/vttablet/tabletmanager/vreplication/controller.go b/go/vt/vttablet/tabletmanager/vreplication/controller.go index 3f9c5430cc6..8776a37a131 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/controller.go +++ b/go/vt/vttablet/tabletmanager/vreplication/controller.go @@ -160,7 +160,7 @@ func (ct *controller) run(ctx context.Context) { return default: } - log.Errorf("stream %v: %v, retrying after %v", ct.id, err, *retryDelay) + binlogplayer.LogError(fmt.Sprintf("error in stream %v, retrying after %v", ct.id, *retryDelay), err) ct.blpStats.ErrorCounts.Add([]string{"Stream Error"}, 1) timer := time.NewTimer(*retryDelay) select { diff --git a/go/vt/vttablet/tabletmanager/vreplication/framework_test.go b/go/vt/vttablet/tabletmanager/vreplication/framework_test.go index 54734de4746..29969fad8da 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/framework_test.go +++ b/go/vt/vttablet/tabletmanager/vreplication/framework_test.go @@ -188,6 +188,7 @@ func addTablet(id int) *topodatapb.Tablet { if err := env.TopoServ.CreateTablet(context.Background(), tablet); err != nil { panic(err) } + env.SchemaEngine.Reload(context.Background()) return tablet } @@ -208,6 +209,7 @@ func addOtherTablet(id int, keyspace, shard string) *topodatapb.Tablet { if err := env.TopoServ.CreateTablet(context.Background(), tablet); err != nil { panic(err) } + env.SchemaEngine.Reload(context.Background()) return tablet } @@ -215,6 +217,7 @@ func deleteTablet(tablet *topodatapb.Tablet) { env.TopoServ.DeleteTablet(context.Background(), tablet.Alias) // This is not automatically removed from shard replication, which results in log spam. topo.DeleteTabletReplicationData(context.Background(), env.TopoServ, tablet) + env.SchemaEngine.Reload(context.Background()) } // fakeTabletConn implement TabletConn interface. We only care about the diff --git a/go/vt/vttablet/tabletmanager/vreplication/stats.go b/go/vt/vttablet/tabletmanager/vreplication/stats.go index 4cb4a9fe3c1..df447482315 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/stats.go +++ b/go/vt/vttablet/tabletmanager/vreplication/stats.go @@ -329,7 +329,7 @@ func (st *vrStats) register() { stats.NewCountersFuncWithMultiLabels( "VReplicationErrors", "Errors during vreplication", - []string{"workflow", "type"}, + []string{"workflow", "id", "type"}, func() map[string]int64 { st.mu.Lock() defer st.mu.Unlock() diff --git a/go/vt/vttablet/tabletmanager/vreplication/utils.go b/go/vt/vttablet/tabletmanager/vreplication/utils.go index 9f542b8d153..c381142adad 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/utils.go +++ b/go/vt/vttablet/tabletmanager/vreplication/utils.go @@ -20,6 +20,9 @@ import ( "context" "encoding/json" "fmt" + "strconv" + + "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/vtgate/evalengine" @@ -68,41 +71,43 @@ const ( LogError = "Error" ) -func getLastLog(dbClient *vdbClient, vreplID uint32) (int64, string, string, string, error) { +func getLastLog(dbClient *vdbClient, vreplID uint32) (id int64, typ, state, message string, err error) { var qr *sqltypes.Result - var err error query := fmt.Sprintf("select id, type, state, message from _vt.vreplication_log where vrepl_id = %d order by id desc limit 1", vreplID) if qr, err = withDDL.Exec(context.Background(), query, dbClient.ExecuteFetch); err != nil { return 0, "", "", "", err } - if len(qr.Rows) != 1 || len(qr.Rows[0]) != 4 { + if len(qr.Rows) != 1 { return 0, "", "", "", nil } row := qr.Rows[0] - id, _ := evalengine.ToInt64(row[0]) - typ := row[1].ToString() - state := row[2].ToString() - message := row[3].ToString() + id, _ = evalengine.ToInt64(row[0]) + typ = row[1].ToString() + state = row[2].ToString() + message = row[3].ToString() return id, typ, state, message, nil } func insertLog(dbClient *vdbClient, typ string, vreplID uint32, state, message string) error { - var query string - - // getLastLog returns the last log for a stream. During insertion, if the id/type/state/message match we do not insert + // getLastLog returns the last log for a stream. During insertion, if the type/state/message match we do not insert // a new log but increment the count. This prevents spamming of the log table in case the same message is logged continuously. - id, currentType, currentState, currentMessage, err := getLastLog(dbClient, vreplID) + id, _, lastLogState, lastLogMessage, err := getLastLog(dbClient, vreplID) if err != nil { return err } - - if id > 0 && typ == currentType && state == currentState && message == currentMessage { + if typ == LogStateChange && state == lastLogState { + // handles case where current state is Running, controller restarts after an error and initializes the state Running + return nil + } + var query string + if id > 0 && message == lastLogMessage { query = fmt.Sprintf("update _vt.vreplication_log set count = count + 1 where id = %d", id) } else { - query = `insert into _vt.vreplication_log(vrepl_id, type, state, message) values(%d, '%s', '%s', %s)` - query = fmt.Sprintf(query, vreplID, typ, state, encodeString(message)) + buf := sqlparser.NewTrackedBuffer(nil) + buf.Myprintf("insert into _vt.vreplication_log(vrepl_id, type, state, message) values(%s, %s, %s, %s)", + strconv.Itoa(int(vreplID)), encodeString(typ), encodeString(state), encodeString(message)) + query = buf.ParsedQuery().Query } - if _, err = withDDL.Exec(context.Background(), query, dbClient.ExecuteFetch); err != nil { return fmt.Errorf("could not insert into log table: %v: %v", query, err) } diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go index 9fb4b28333e..81842fadbdf 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go @@ -484,8 +484,8 @@ func (vp *vplayer) applyEvent(ctx context.Context, event *binlogdatapb.VEvent, m if sql == "" { sql = event.Dml } - // If the event is for one of the AWS RDS "special" tables, we skip - if !strings.Contains(sql, " mysql.rds_") { + // If the event is for one of the AWS RDS "special" or pt-table-checksum tables, we skip + if !strings.Contains(sql, " mysql.rds_") && !strings.Contains(sql, " percona.checksums") { // This is a player using statement based replication if err := vp.vr.dbClient.Begin(); err != nil { return err diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go index 8a49f8e44b4..8a1f355d563 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go @@ -410,7 +410,7 @@ func TestPlayerStatementModeWithFilter(t *testing.T) { output := []string{ "begin", "rollback", - "/update _vt.vreplication set message='Error: filter rules are not supported for SBR", + "/update _vt.vreplication set message='filter rules are not supported for SBR", } execStatements(t, input) @@ -1568,7 +1568,7 @@ func TestPlayerDDL(t *testing.T) { execStatements(t, []string{"alter table t1 add column val2 varchar(128)"}) expectDBClientQueries(t, []string{ "alter table t1 add column val2 varchar(128)", - "/update _vt.vreplication set message='Error: Duplicate", + "/update _vt.vreplication set message='Duplicate", }) cancel() @@ -2362,7 +2362,7 @@ func TestRestartOnVStreamEnd(t *testing.T) { streamerEngine.Close() expectDBClientQueries(t, []string{ - "/update _vt.vreplication set message='Error: vstream ended'", + "/update _vt.vreplication set message='vstream ended'", }) streamerEngine.Open() diff --git a/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go b/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go index 2c12568f527..fe0547cf8c3 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go @@ -19,9 +19,12 @@ package vreplication import ( "flag" "fmt" + "strconv" "strings" "time" + "vitess.io/vitess/go/vt/sqlparser" + querypb "vitess.io/vitess/go/vt/proto/query" "vitess.io/vitess/go/vt/vtgate/evalengine" @@ -145,9 +148,8 @@ func newVReplicator(id uint32, source *binlogdatapb.BinlogSource, sourceVStreame func (vr *vreplicator) Replicate(ctx context.Context) error { err := vr.replicate(ctx) if err != nil { - log.Errorf("Replicate error: %s", err.Error()) - if err := vr.setMessage(fmt.Sprintf("Error: %s", err.Error())); err != nil { - log.Errorf("Failed to set error state: %v", err) + if err := vr.setMessage(err.Error()); err != nil { + binlogplayer.LogError("Failed to set error state", err) } } return err @@ -293,7 +295,7 @@ func (vr *vreplicator) buildColInfoMap(ctx context.Context) (map[string][]*Colum } } extra := strings.ToLower(row[5].ToString()) - if strings.Contains(extra, "generated") || strings.Contains(extra, "virtual") { + if strings.Contains(extra, "stored generated") || strings.Contains(extra, "virtual generated") { isGenerated = true } colInfo = append(colInfo, &ColumnInfo{ @@ -333,11 +335,14 @@ func (vr *vreplicator) readSettings(ctx context.Context) (settings binlogplayer. } func (vr *vreplicator) setMessage(message string) error { + message = binlogplayer.MessageTruncate(message) vr.stats.History.Add(&binlogplayer.StatsHistoryRecord{ Time: time.Now(), Message: message, }) - query := fmt.Sprintf("update _vt.vreplication set message=%v where id=%v", encodeString(binlogplayer.MessageTruncate(message)), vr.id) + buf := sqlparser.NewTrackedBuffer(nil) + buf.Myprintf("update _vt.vreplication set message=%s where id=%s", encodeString(message), strconv.Itoa(int(vr.id))) + query := buf.ParsedQuery().Query if _, err := vr.dbClient.Execute(query); err != nil { return fmt.Errorf("could not set message: %v: %v", query, err) } diff --git a/go/vt/vttablet/tabletserver/planbuilder/permission.go b/go/vt/vttablet/tabletserver/planbuilder/permission.go index 325f555c676..45bf90bfa20 100644 --- a/go/vt/vttablet/tabletserver/planbuilder/permission.go +++ b/go/vt/vttablet/tabletserver/planbuilder/permission.go @@ -51,7 +51,7 @@ func BuildPermissions(stmt sqlparser.Statement) []Permission { for _, t := range node.AffectedTables() { permissions = buildTableNamePermissions(t, tableacl.ADMIN, permissions) } - case *sqlparser.AlterMigration, *sqlparser.RevertMigration: + case *sqlparser.AlterMigration, *sqlparser.RevertMigration, *sqlparser.ShowMigrationLogs: permissions = []Permission{} // TODO(shlomi) what are the correct permissions here? Table is unknown case *sqlparser.Flush: for _, t := range node.TableNames { diff --git a/go/vt/vttablet/tabletserver/planbuilder/plan.go b/go/vt/vttablet/tabletserver/planbuilder/plan.go index ffe3d3dfb6d..2e144e78c33 100644 --- a/go/vt/vttablet/tabletserver/planbuilder/plan.go +++ b/go/vt/vttablet/tabletserver/planbuilder/plan.go @@ -74,6 +74,7 @@ const ( PlanCallProc PlanAlterMigration PlanRevertMigration + PlanShowMigrationLogs NumPlans ) @@ -105,6 +106,7 @@ var planName = []string{ "CallProcedure", "AlterMigration", "RevertMigration", + "ShowMigrationLogs", } func (pt PlanType) String() string { @@ -220,6 +222,8 @@ func Build(statement sqlparser.Statement, tables map[string]*schema.Table, isRes plan, err = &Plan{PlanID: PlanAlterMigration, FullStmt: stmt}, nil case *sqlparser.RevertMigration: plan, err = &Plan{PlanID: PlanRevertMigration, FullStmt: stmt}, nil + case *sqlparser.ShowMigrationLogs: + plan, err = &Plan{PlanID: PlanShowMigrationLogs, FullStmt: stmt}, nil case *sqlparser.Show: plan, err = analyzeShow(stmt, dbName) case *sqlparser.OtherRead, sqlparser.Explain: diff --git a/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt b/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt index b0d571b0156..e7ec2cd817d 100644 --- a/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt +++ b/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt @@ -939,3 +939,17 @@ options:PassthroughDMLs "TableName": "", "FullQuery": "call getAllTheThings()" } + +# create table with function as a default value +"create table function_default (x varchar(25) DEFAULT (TRIM(' check ')))" +{ + "PlanID": "DDL", + "TableName": "", + "Permissions": [ + { + "TableName": "function_default", + "Role": 2 + } + ], + "FullQuery": "create table function_default (\n\tx varchar(25) default (TRIM(' check '))\n)" +} diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go index ff548cc7beb..c4c43d6c79e 100644 --- a/go/vt/vttablet/tabletserver/query_executor.go +++ b/go/vt/vttablet/tabletserver/query_executor.go @@ -179,6 +179,8 @@ func (qre *QueryExecutor) Execute() (reply *sqltypes.Result, err error) { return qre.execAlterMigration() case p.PlanRevertMigration: return qre.execRevertMigration() + case p.PlanShowMigrationLogs: + return qre.execShowMigrationLogs() } return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "[BUG] %s unexpected plan type", qre.plan.PlanID.String()) } @@ -850,6 +852,13 @@ func (qre *QueryExecutor) execRevertMigration() (*sqltypes.Result, error) { return qre.tsv.onlineDDLExecutor.SubmitMigration(qre.ctx, qre.plan.FullStmt) } +func (qre *QueryExecutor) execShowMigrationLogs() (*sqltypes.Result, error) { + if showMigrationLogsStmt, ok := qre.plan.FullStmt.(*sqlparser.ShowMigrationLogs); ok { + return qre.tsv.onlineDDLExecutor.ShowMigrationLogs(qre.ctx, showMigrationLogsStmt) + } + return nil, vterrors.New(vtrpcpb.Code_INTERNAL, "Expecting SHOW VITESS_MIGRATION plan") +} + func (qre *QueryExecutor) drainResultSetOnConn(conn *connpool.DBConn) error { more := true for more { diff --git a/go/vt/vttablet/tabletserver/schema/engine.go b/go/vt/vttablet/tabletserver/schema/engine.go index 281b35250a4..82c6e328502 100644 --- a/go/vt/vttablet/tabletserver/schema/engine.go +++ b/go/vt/vttablet/tabletserver/schema/engine.go @@ -339,10 +339,18 @@ func (se *Engine) reload(ctx context.Context) error { se.tableFileSizeGauge.Set(tableName, int64(fileSize)) se.tableAllocatedSizeGauge.Set(tableName, int64(allocatedSize)) - // TODO(sougou); find a better way detect changed tables. This method - // seems unreliable. The endtoend test flags all tables as changed. + // Table schemas are cached by tabletserver. For each table we cache `information_schema.tables.create_time` (`tbl.CreateTime`). + // We also record the last time the schema was loaded (`se.lastChange`). Both are in seconds. We reload a table only when: + // 1. A table's underlying mysql metadata has changed: `se.lastChange >= createTime`. This can happen if a table was directly altered. + // Note that we also reload if `se.lastChange == createTime` since it is possible, especially in unit tests, + // that a table might be changed multiple times within the same second. + // + // 2. A table was swapped in by Online DDL: `createTime != tbl.CreateTime`. When an Online DDL migration is completed the temporary table is + // renamed to the table being altered. `se.lastChange` is updated every time the schema is reloaded (default: 30m). + // Online DDL can take hours. So it is possible that the `create_time` of the temporary table is before se.lastChange. Hence, + // #1 will not identify the renamed table as a changed one. tbl, isInTablesMap := se.tables[tableName] - if isInTablesMap && createTime < se.lastChange { + if isInTablesMap && createTime == tbl.CreateTime && createTime < se.lastChange { tbl.FileSize = fileSize tbl.AllocatedSize = allocatedSize continue @@ -356,6 +364,7 @@ func (se *Engine) reload(ctx context.Context) error { } table.FileSize = fileSize table.AllocatedSize = allocatedSize + table.CreateTime = createTime changedTables[tableName] = table if isInTablesMap { altered = append(altered, tableName) @@ -373,6 +382,10 @@ func (se *Engine) reload(ctx context.Context) error { if !curTables[tableName] { dropped = append(dropped, tableName) delete(se.tables, tableName) + // We can't actually delete the label from the stats, but we can set it to 0. + // Many monitoring tools will drop zero-valued metrics. + se.tableFileSizeGauge.Reset(tableName) + se.tableAllocatedSizeGauge.Reset(tableName) } } @@ -381,7 +394,7 @@ func (se *Engine) reload(ctx context.Context) error { return err } - // Update se.tables and se.lastChange + // Update se.tables for k, t := range changedTables { se.tables[k] = t } diff --git a/go/vt/vttablet/tabletserver/schema/engine_test.go b/go/vt/vttablet/tabletserver/schema/engine_test.go index 5c16bcfddc6..6d7bb9b0a1a 100644 --- a/go/vt/vttablet/tabletserver/schema/engine_test.go +++ b/go/vt/vttablet/tabletserver/schema/engine_test.go @@ -17,6 +17,7 @@ limitations under the License. package schema import ( + "context" "expvar" "fmt" "net/http" @@ -28,8 +29,6 @@ import ( "vitess.io/vitess/go/test/utils" - "context" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -70,7 +69,7 @@ func TestOpenAndReload(t *testing.T) { StatusFlags: 0, }) - // pre-advance to above the default 1427325875. + // advance to one second after the default 1427325875. db.AddQuery("select unix_timestamp()", sqltypes.MakeTestResult(sqltypes.MakeTestFields( "t", "int64"), @@ -84,6 +83,8 @@ func TestOpenAndReload(t *testing.T) { want := initialSchema() mustMatch(t, want, se.GetSchema()) + assert.Equal(t, int64(100), se.tableFileSizeGauge.Counts()["msg"]) + assert.Equal(t, int64(150), se.tableAllocatedSizeGauge.Counts()["msg"]) // Advance time some more. db.AddQuery("select unix_timestamp()", sqltypes.MakeTestResult(sqltypes.MakeTestFields( @@ -92,6 +93,7 @@ func TestOpenAndReload(t *testing.T) { "1427325877", )) assert.EqualValues(t, firstReadRowsValue, se.innoDbReadRowsGauge.Get()) + // Modify test_table_03 // Add test_table_04 // Drop msg @@ -104,7 +106,7 @@ func TestOpenAndReload(t *testing.T) { { sqltypes.MakeTrusted(sqltypes.VarChar, []byte("test_table_03")), // table_name sqltypes.MakeTrusted(sqltypes.VarChar, []byte("BASE TABLE")), // table_type - sqltypes.MakeTrusted(sqltypes.Int64, []byte("1427325877")), // unix_timestamp(t.create_time) // Match the timestamp. + sqltypes.MakeTrusted(sqltypes.Int64, []byte("1427325877")), // unix_timestamp(t.create_time) sqltypes.MakeTrusted(sqltypes.VarChar, []byte("")), // table_comment sqltypes.MakeTrusted(sqltypes.Int64, []byte("128")), // file_size sqltypes.MakeTrusted(sqltypes.Int64, []byte("256")), // allocated_size @@ -180,6 +182,7 @@ func TestOpenAndReload(t *testing.T) { Type: sqltypes.Int32, }}, PKColumns: []int{0, 1}, + CreateTime: 1427325877, FileSize: 128, AllocatedSize: 256, } @@ -190,11 +193,14 @@ func TestOpenAndReload(t *testing.T) { Type: sqltypes.Int32, }}, PKColumns: []int{0}, + CreateTime: 1427325875, FileSize: 100, AllocatedSize: 150, } delete(want, "msg") assert.Equal(t, want, se.GetSchema()) + assert.Equal(t, int64(0), se.tableAllocatedSizeGauge.Counts()["msg"]) + assert.Equal(t, int64(0), se.tableFileSizeGauge.Counts()["msg"]) //ReloadAt tests pos1, err := mysql.DecodePosition("MariaDB/0-41983-20") @@ -217,7 +223,6 @@ func TestOpenAndReload(t *testing.T) { Rows: [][]sqltypes.Value{ mysql.BaseShowTablesRow("test_table_01", false, ""), mysql.BaseShowTablesRow("test_table_02", false, ""), - // test_table_04 will in spite of older timestamp because it doesn't exist yet. mysql.BaseShowTablesRow("test_table_04", false, ""), mysql.BaseShowTablesRow("seq", false, "vitess_sequence"), }, @@ -241,65 +246,172 @@ func TestOpenAndReload(t *testing.T) { assert.Equal(t, want, se.GetSchema()) } -func TestOpenFailedDueToMissMySQLTime(t *testing.T) { +func TestReloadWithSwappedTables(t *testing.T) { db := fakesqldb.New(t) defer db.Close() - db.AddQuery("select unix_timestamp()", &sqltypes.Result{ - // Make this query fail by returning 2 values. - Fields: []*querypb.Field{ - {Type: sqltypes.Uint64}, - }, + for query, result := range schematest.Queries() { + db.AddQuery(query, result) + } + db.AddQueryPattern(baseShowTablesPattern, + &sqltypes.Result{ + Fields: mysql.BaseShowTablesFields, + RowsAffected: 0, + InsertID: 0, + Rows: [][]sqltypes.Value{ + mysql.BaseShowTablesRow("test_table_01", false, ""), + mysql.BaseShowTablesRow("test_table_02", false, ""), + mysql.BaseShowTablesRow("test_table_03", false, ""), + mysql.BaseShowTablesRow("seq", false, "vitess_sequence"), + mysql.BaseShowTablesRow("msg", false, "vitess_message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30"), + }, + SessionStateChanges: "", + StatusFlags: 0, + }) + firstReadRowsValue := 12 + AddFakeInnoDBReadRowsResult(db, firstReadRowsValue) + + se := newEngine(10, 10*time.Second, 10*time.Second, db) + se.Open() + defer se.Close() + want := initialSchema() + mustMatch(t, want, se.GetSchema()) + + // Add test_table_04 with a newer timestamp + // Advance time some more. + db.AddQuery("select unix_timestamp()", sqltypes.MakeTestResult(sqltypes.MakeTestFields( + "t", + "int64"), + "1427325876", + )) + db.ClearQueryPattern() + db.AddQueryPattern(baseShowTablesPattern, &sqltypes.Result{ + Fields: mysql.BaseShowTablesFields, Rows: [][]sqltypes.Value{ - {sqltypes.NewVarBinary("1427325875")}, - {sqltypes.NewVarBinary("1427325875")}, + mysql.BaseShowTablesRow("test_table_01", false, ""), + mysql.BaseShowTablesRow("test_table_02", false, ""), + mysql.BaseShowTablesRow("test_table_03", false, ""), + { + sqltypes.MakeTrusted(sqltypes.VarChar, []byte("test_table_04")), + sqltypes.MakeTrusted(sqltypes.VarChar, []byte("BASE TABLE")), + sqltypes.MakeTrusted(sqltypes.Int64, []byte("1427325877")), // unix_timestamp(create_time) + sqltypes.MakeTrusted(sqltypes.VarChar, []byte("")), + sqltypes.MakeTrusted(sqltypes.Int64, []byte("128")), // file_size + sqltypes.MakeTrusted(sqltypes.Int64, []byte("256")), // allocated_size + }, + mysql.BaseShowTablesRow("seq", false, "vitess_sequence"), + mysql.BaseShowTablesRow("msg", false, "vitess_message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30"), }, }) - se := newEngine(10, 1*time.Second, 1*time.Second, db) - err := se.Open() - want := "could not get MySQL time" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("se.Open: %v, want %s", err, want) - } -} - -func TestOpenFailedDueToIncorrectMysqlRowNum(t *testing.T) { - db := fakesqldb.New(t) - defer db.Close() - db.AddQuery("select unix_timestamp()", &sqltypes.Result{ + db.AddQuery("select * from test_table_04 where 1 != 1", &sqltypes.Result{ Fields: []*querypb.Field{{ - Type: sqltypes.Uint64, + Name: "mypk", + Type: sqltypes.Int32, }}, + }) + db.AddQuery(mysql.BaseShowPrimary, &sqltypes.Result{ + Fields: mysql.ShowPrimaryFields, Rows: [][]sqltypes.Value{ - // make this query fail by returning NULL - {sqltypes.NULL}, + mysql.ShowPrimaryRow("test_table_01", "pk"), + mysql.ShowPrimaryRow("test_table_02", "pk"), + mysql.ShowPrimaryRow("test_table_03", "pk"), + mysql.ShowPrimaryRow("test_table_04", "mypk"), + mysql.ShowPrimaryRow("seq", "id"), + mysql.ShowPrimaryRow("msg", "id"), }, }) - se := newEngine(10, 1*time.Second, 1*time.Second, db) - err := se.Open() - want := "unexpected result for MySQL time" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("se.Open: %v, want %s", err, want) + err := se.Reload(context.Background()) + require.NoError(t, err) + want["test_table_04"] = &Table{ + Name: sqlparser.NewTableIdent("test_table_04"), + Fields: []*querypb.Field{{ + Name: "mypk", + Type: sqltypes.Int32, + }}, + PKColumns: []int{0}, + CreateTime: 1427325877, + FileSize: 128, + AllocatedSize: 256, } -} -func TestOpenFailedDueToInvalidTimeFormat(t *testing.T) { - db := fakesqldb.New(t) - defer db.Close() - db.AddQuery("select unix_timestamp()", &sqltypes.Result{ + mustMatch(t, want, se.GetSchema()) + + // swap test_table_03 and test_table_04 + // Advance time some more. + db.AddQuery("select unix_timestamp()", sqltypes.MakeTestResult(sqltypes.MakeTestFields( + "t", + "int64"), + "1427325877", + )) + db.ClearQueryPattern() + db.AddQueryPattern(baseShowTablesPattern, &sqltypes.Result{ + Fields: mysql.BaseShowTablesFields, + Rows: [][]sqltypes.Value{ + mysql.BaseShowTablesRow("test_table_01", false, ""), + mysql.BaseShowTablesRow("test_table_02", false, ""), + { + sqltypes.MakeTrusted(sqltypes.VarChar, []byte("test_table_03")), + sqltypes.MakeTrusted(sqltypes.VarChar, []byte("BASE TABLE")), + sqltypes.MakeTrusted(sqltypes.Int64, []byte("1427325877")), // unix_timestamp(create_time) + sqltypes.MakeTrusted(sqltypes.VarChar, []byte("")), + sqltypes.MakeTrusted(sqltypes.Int64, []byte("128")), // file_size + sqltypes.MakeTrusted(sqltypes.Int64, []byte("256")), // allocated_size + }, + mysql.BaseShowTablesRow("test_table_04", false, ""), + mysql.BaseShowTablesRow("seq", false, "vitess_sequence"), + mysql.BaseShowTablesRow("msg", false, "vitess_message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30"), + }, + }) + db.AddQuery("select * from test_table_03 where 1 != 1", &sqltypes.Result{ Fields: []*querypb.Field{{ - Type: sqltypes.VarChar, + Name: "mypk", + Type: sqltypes.Int32, }}, + }) + db.AddQuery("select * from test_table_04 where 1 != 1", &sqltypes.Result{ + Fields: []*querypb.Field{{ + Name: "pk", + Type: sqltypes.Int32, + }}, + }) + db.AddQuery(mysql.BaseShowPrimary, &sqltypes.Result{ + Fields: mysql.ShowPrimaryFields, Rows: [][]sqltypes.Value{ - // make safety check fail, invalid time format - {sqltypes.NewVarBinary("invalid_time")}, + mysql.ShowPrimaryRow("test_table_01", "pk"), + mysql.ShowPrimaryRow("test_table_02", "pk"), + mysql.ShowPrimaryRow("test_table_03", "mypk"), + mysql.ShowPrimaryRow("test_table_04", "pk"), + mysql.ShowPrimaryRow("seq", "id"), + mysql.ShowPrimaryRow("msg", "id"), }, }) - se := newEngine(10, 1*time.Second, 1*time.Second, db) - err := se.Open() - want := "could not parse time" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("se.Open: %v, want %s", err, want) + err = se.Reload(context.Background()) + require.NoError(t, err) + + delete(want, "test_table_03") + delete(want, "test_table_04") + want["test_table_03"] = &Table{ + Name: sqlparser.NewTableIdent("test_table_03"), + Fields: []*querypb.Field{{ + Name: "mypk", + Type: sqltypes.Int32, + }}, + PKColumns: []int{0}, + CreateTime: 1427325877, + FileSize: 128, + AllocatedSize: 256, } + want["test_table_04"] = &Table{ + Name: sqlparser.NewTableIdent("test_table_04"), + Fields: []*querypb.Field{{ + Name: "pk", + Type: sqltypes.Int32, + }}, + PKColumns: []int{0}, + CreateTime: 1427325875, + FileSize: 100, + AllocatedSize: 150, + } + mustMatch(t, want, se.GetSchema()) } func TestOpenFailedDueToExecErr(t *testing.T) { @@ -409,6 +521,7 @@ func initialSchema() map[string]*Table { Type: sqltypes.Int32, }}, PKColumns: []int{0}, + CreateTime: 1427325875, FileSize: 0x64, AllocatedSize: 0x96, }, @@ -419,6 +532,7 @@ func initialSchema() map[string]*Table { Type: sqltypes.Int32, }}, PKColumns: []int{0}, + CreateTime: 1427325875, FileSize: 0x64, AllocatedSize: 0x96, }, @@ -429,6 +543,7 @@ func initialSchema() map[string]*Table { Type: sqltypes.Int32, }}, PKColumns: []int{0}, + CreateTime: 1427325875, FileSize: 0x64, AllocatedSize: 0x96, }, @@ -449,6 +564,7 @@ func initialSchema() map[string]*Table { Type: sqltypes.Int64, }}, PKColumns: []int{0}, + CreateTime: 1427325875, FileSize: 0x64, AllocatedSize: 0x96, SequenceInfo: &SequenceInfo{}, @@ -476,6 +592,7 @@ func initialSchema() map[string]*Table { Type: sqltypes.Int64, }}, PKColumns: []int{0}, + CreateTime: 1427325875, FileSize: 0x64, AllocatedSize: 0x96, MessageInfo: &MessageInfo{ diff --git a/go/vt/vttablet/tabletserver/schema/schema.go b/go/vt/vttablet/tabletserver/schema/schema.go index 69aae6387ac..a46377caa3e 100644 --- a/go/vt/vttablet/tabletserver/schema/schema.go +++ b/go/vt/vttablet/tabletserver/schema/schema.go @@ -53,6 +53,7 @@ type Table struct { // MessageInfo contains info for message tables. MessageInfo *MessageInfo + CreateTime int64 FileSize uint64 AllocatedSize uint64 } diff --git a/go/vt/vttablet/tabletserver/schema/tracker.go b/go/vt/vttablet/tabletserver/schema/tracker.go index dc3362d957d..161e6be0300 100644 --- a/go/vt/vttablet/tabletserver/schema/tracker.go +++ b/go/vt/vttablet/tabletserver/schema/tracker.go @@ -294,18 +294,21 @@ func MustReloadSchemaOnDDL(sql string, dbname string) bool { case sqlparser.DBDDLStatement: return false case sqlparser.DDLStatement: - table := stmt.GetTable() - if table.IsEmpty() { - return false - } - if !table.Qualifier.IsEmpty() && table.Qualifier.String() != dbname { - return false - } - tableName := table.Name.String() - if schema.IsOnlineDDLTableName(tableName) { - return false + tables := []sqlparser.TableName{stmt.GetTable()} + tables = append(tables, stmt.GetToTables()...) + for _, table := range tables { + if table.IsEmpty() { + continue + } + if !table.Qualifier.IsEmpty() && table.Qualifier.String() != dbname { + continue + } + tableName := table.Name.String() + if schema.IsOnlineDDLTableName(tableName) { + continue + } + return true } - return true } return false } diff --git a/go/vt/vttablet/tabletserver/schema/tracker_test.go b/go/vt/vttablet/tabletserver/schema/tracker_test.go index 39d97dc46a6..2b30ee47e55 100644 --- a/go/vt/vttablet/tabletserver/schema/tracker_test.go +++ b/go/vt/vttablet/tabletserver/schema/tracker_test.go @@ -160,6 +160,7 @@ func TestMustReloadSchemaOnDDL(t *testing.T) { {"create table x(i int);", db1, true}, {"bad", db2, false}, {"create table db2.x(i int);", db2, true}, + {"rename table db2.x to db2.y;", db2, true}, {"create table db1.x(i int);", db2, false}, {"create table _vt.x(i int);", db1, false}, {"DROP VIEW IF EXISTS `pseudo_gtid`.`_pseudo_gtid_hint__asc:55B364E3:0000000000056EE2:6DD57B85`", db2, false}, diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go index ae769250036..d06dfa5330e 100644 --- a/go/vt/vttablet/tabletserver/tabletserver.go +++ b/go/vt/vttablet/tabletserver/tabletserver.go @@ -1251,7 +1251,7 @@ func (tsv *TabletServer) execRequest( logStats := tabletenv.NewLogStats(ctx, requestName) logStats.Target = target logStats.OriginalSQL = sql - logStats.BindVariables = bindVariables + logStats.BindVariables = sqltypes.CopyBindVariables(bindVariables) defer tsv.handlePanicAndSendLogStats(sql, bindVariables, logStats) if err = tsv.sm.StartRequest(ctx, target, allowOnShutdown); err != nil { return err diff --git a/go/vt/vttablet/tabletserver/vstreamer/engine.go b/go/vt/vttablet/tabletserver/vstreamer/engine.go index 6c604355e15..4432cccf54d 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/engine.go +++ b/go/vt/vttablet/tabletserver/vstreamer/engine.go @@ -23,6 +23,7 @@ import ( "errors" "net/http" "sync" + "sync/atomic" "vitess.io/vitess/go/vt/servenv" @@ -60,7 +61,7 @@ type Engine struct { wg sync.WaitGroup mu sync.Mutex - isOpen bool + isOpen int32 // 0 or 1 in place of atomic.Bool added in go 1.19 streamIdx int streamers map[int]*uvstreamer rowStreamers map[int]*rowStreamer @@ -79,6 +80,7 @@ type Engine struct { // vstreamer metrics vstreamerPhaseTimings *servenv.TimingsWrapper + vstreamerCount *stats.Gauge vstreamerEventsStreamed *stats.Counter vstreamerPacketSize *stats.GaugeFunc vstreamerNumPackets *stats.Counter @@ -114,6 +116,7 @@ func NewEngine(env tabletenv.Env, ts srvtopo.Server, se *schema.Engine, lagThrot vschemaUpdates: env.Exporter().NewCounter("VSchemaUpdates", "Count of VSchema updates. Does not include errors"), vstreamerPhaseTimings: env.Exporter().NewTimings("VStreamerPhaseTiming", "Time taken for different phases during vstream copy", "phase-timing"), + vstreamerCount: env.Exporter().NewGauge("VStreamerCount", "Current number of vstreamers"), vstreamerEventsStreamed: env.Exporter().NewCounter("VStreamerEventsStreamed", "Count of events streamed in VStream API"), vstreamerPacketSize: env.Exporter().NewGaugeFunc("VStreamPacketSize", "Max packet size for sending vstreamer events", getPacketSize), vstreamerNumPackets: env.Exporter().NewCounter("VStreamerNumPackets", "Number of packets in vstreamer"), @@ -136,30 +139,24 @@ func (vse *Engine) InitDBConfig(keyspace string) { // Open starts the Engine service. func (vse *Engine) Open() { - vse.mu.Lock() - defer vse.mu.Unlock() - if vse.isOpen { - return - } log.Info("VStreamer: opening") - vse.isOpen = true + // If it's not already open, then open it now. + atomic.CompareAndSwapInt32(&vse.isOpen, 0, 1) } // IsOpen checks if the engine is opened func (vse *Engine) IsOpen() bool { - vse.mu.Lock() - defer vse.mu.Unlock() - return vse.isOpen + return atomic.LoadInt32(&vse.isOpen) == 1 } // Close closes the Engine service. func (vse *Engine) Close() { func() { - vse.mu.Lock() - defer vse.mu.Unlock() - if !vse.isOpen { + if atomic.LoadInt32(&vse.isOpen) == 0 { return } + vse.mu.Lock() + defer vse.mu.Unlock() // cancels are non-blocking. for _, s := range vse.streamers { s.Cancel() @@ -170,7 +167,7 @@ func (vse *Engine) Close() { for _, s := range vse.resultStreamers { s.Cancel() } - vse.isOpen = false + atomic.StoreInt32(&vse.isOpen, 0) }() // Wait only after releasing the lock because the end of every @@ -195,11 +192,12 @@ func (vse *Engine) Stream(ctx context.Context, startPos string, tablePKs []*binl // Create stream and add it to the map. streamer, idx, err := func() (*uvstreamer, int, error) { - vse.mu.Lock() - defer vse.mu.Unlock() - if !vse.isOpen { + if atomic.LoadInt32(&vse.isOpen) == 0 { return nil, 0, errors.New("VStreamer is not open") } + vse.env.Config().DB.AppWithDB() + vse.mu.Lock() + defer vse.mu.Unlock() streamer := newUVStreamer(ctx, vse, vse.env.Config().DB.AppWithDB(), vse.se, startPos, tablePKs, filter, vse.lvschema, send) idx := vse.streamIdx vse.streamers[idx] = streamer @@ -236,11 +234,11 @@ func (vse *Engine) StreamRows(ctx context.Context, query string, lastpk []sqltyp // Create stream and add it to the map. rowStreamer, idx, err := func() (*rowStreamer, int, error) { - vse.mu.Lock() - defer vse.mu.Unlock() - if !vse.isOpen { + if atomic.LoadInt32(&vse.isOpen) == 0 { return nil, 0, errors.New("VStreamer is not open") } + vse.mu.Lock() + defer vse.mu.Unlock() rowStreamer := newRowStreamer(ctx, vse.env.Config().DB.AppWithDB(), vse.se, query, lastpk, vse.lvschema, send, vse) idx := vse.streamIdx @@ -271,11 +269,11 @@ func (vse *Engine) StreamRows(ctx context.Context, query string, lastpk []sqltyp func (vse *Engine) StreamResults(ctx context.Context, query string, send func(*binlogdatapb.VStreamResultsResponse) error) error { // Create stream and add it to the map. resultStreamer, idx, err := func() (*resultStreamer, int, error) { - vse.mu.Lock() - defer vse.mu.Unlock() - if !vse.isOpen { + if atomic.LoadInt32(&vse.isOpen) == 0 { return nil, 0, errors.New("VStreamer is not open") } + vse.mu.Lock() + defer vse.mu.Unlock() resultStreamer := newResultStreamer(ctx, vse.env.Config().DB.AppWithDB(), query, send, vse) idx := vse.streamIdx vse.resultStreamers[idx] = resultStreamer diff --git a/go/vt/vttablet/tabletserver/vstreamer/rowstreamer_test.go b/go/vt/vttablet/tabletserver/vstreamer/rowstreamer_test.go index d809bd8b183..2a9ac5a47ff 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/rowstreamer_test.go +++ b/go/vt/vttablet/tabletserver/vstreamer/rowstreamer_test.go @@ -234,6 +234,7 @@ func TestStreamRowsKeyRange(t *testing.T) { if testing.Short() { t.Skip() } + engine.se.Reload(context.Background()) if err := env.SetVSchema(shardedVSchema); err != nil { t.Fatal(err) diff --git a/go/vt/vttablet/tabletserver/vstreamer/testenv/testenv.go b/go/vt/vttablet/tabletserver/vstreamer/testenv/testenv.go index 8ceae9f9416..bb548dce080 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/testenv/testenv.go +++ b/go/vt/vttablet/tabletserver/vstreamer/testenv/testenv.go @@ -21,6 +21,9 @@ import ( "context" "fmt" "os" + "regexp" + "strconv" + "strings" "vitess.io/vitess/go/json2" "vitess.io/vitess/go/vt/dbconfigs" @@ -52,6 +55,11 @@ type Env struct { Mysqld *mysqlctl.Mysqld SchemaEngine *schema.Engine Flavor string + // MySQL and Percona are considered equivalent here and both called mysql + DBType string + DBMajorVersion int + DBMinorVersion int + DBPatchVersion int } // Init initializes an Env. @@ -102,6 +110,27 @@ func Init() (*Env, error) { te.Mysqld = mysqlctl.NewMysqld(te.Dbcfgs) pos, _ := te.Mysqld.PrimaryPosition() te.Flavor = pos.GTIDSet.Flavor() + if strings.HasPrefix(strings.ToLower(te.Flavor), string(mysqlctl.FlavorMariaDB)) { + te.DBType = string(mysqlctl.FlavorMariaDB) + } else { + // MySQL and Percona are equivalent for the tests + te.DBType = string(mysqlctl.FlavorMySQL) + } + dbVersionStr := te.Mysqld.GetVersionString() + dbVersionStrParts := strings.Split(dbVersionStr, ".") + var err error + te.DBMajorVersion, err = strconv.Atoi(dbVersionStrParts[0]) + if err != nil { + return nil, fmt.Errorf("could not parse database major version from '%s': %v", dbVersionStr, err) + } + te.DBMinorVersion, err = strconv.Atoi(dbVersionStrParts[1]) + if err != nil { + return nil, fmt.Errorf("could not parse database minor version from '%s': %v", dbVersionStr, err) + } + te.DBPatchVersion, err = strconv.Atoi(dbVersionStrParts[2]) + if err != nil { + return nil, fmt.Errorf("could not parse database patch version from '%s': %v", dbVersionStr, err) + } te.SchemaEngine = schema.NewEngine(te.TabletEnv) te.SchemaEngine.InitDBConfig(te.Dbcfgs.DbaWithDB()) @@ -137,5 +166,27 @@ func (te *Env) SetVSchema(vs string) error { if err := te.TopoServ.SaveVSchema(ctx, te.KeyspaceName, &kspb); err != nil { return err } + te.SchemaEngine.Reload(ctx) return te.TopoServ.RebuildSrvVSchema(ctx, te.Cells) } + +// In MySQL 8.0 and later information_schema no longer contains the display width for integer types and +// as of 8.0.19 for year types as this was an unnecessary headache because it can only serve to confuse +// if the display width is less than the type width (8.0 no longer supports the 2 digit YEAR). So if the +// test is running against MySQL 8.0 or later then you should use this function to replace e.g. +// `int([0-9]*)` with `int` in the expected results string that we define in the test. +func (te *Env) RemoveAnyDeprecatedDisplayWidths(orig string) string { + if te.DBType != string(mysqlctl.FlavorMySQL) || te.DBMajorVersion < 8 { + return orig + } + var adjusted string + baseIntType := "int" + intRE := regexp.MustCompile(`(i)?int\(([0-9]*)?\)`) + adjusted = intRE.ReplaceAllString(orig, baseIntType) + if (te.DBMajorVersion > 8 || te.DBMinorVersion > 0) || te.DBPatchVersion >= 19 { + baseYearType := "year" + yearRE := regexp.MustCompile(`(i)?year\(([0-9]*)?\)`) + adjusted = yearRE.ReplaceAllString(adjusted, baseYearType) + } + return adjusted +} diff --git a/go/vt/vttablet/tabletserver/vstreamer/uvstreamer_test.go b/go/vt/vttablet/tabletserver/vstreamer/uvstreamer_test.go index 801745cf6e4..f1c91f4e964 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/uvstreamer_test.go +++ b/go/vt/vttablet/tabletserver/vstreamer/uvstreamer_test.go @@ -171,6 +171,7 @@ func TestVStreamCopyCompleteFlow(t *testing.T) { } ctx, cancel := context.WithCancel(context.Background()) defer cancel() + engine.se.Reload(context.Background()) defer execStatements(t, []string{ "drop table t1", @@ -296,7 +297,7 @@ func validateReceivedEvents(t *testing.T) { } } got := ev.String() - want := expectedEvents[i] + want := env.RemoveAnyDeprecatedDisplayWidths(expectedEvents[i]) if !strings.HasPrefix(got, want) { printAllEvents("Events not received in the right order") t.Fatalf("Event %d did not match, want %s, got %s", i, want, got) @@ -446,7 +447,7 @@ func startVStreamCopy(ctx context.Context, t *testing.T, filter *binlogdatapb.Fi var expectedEvents = []string{ "type:OTHER gtid:\"Copy Start t1\"", "type:BEGIN", - "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:GTID", "type:ROW row_event:{table_name:\"t1\" row_changes:{after:{lengths:1 lengths:2 values:\"110\"}}}", "type:ROW row_event:{table_name:\"t1\" row_changes:{after:{lengths:1 lengths:2 values:\"220\"}}}", @@ -464,18 +465,18 @@ var expectedEvents = []string{ "type:LASTPK last_p_k_event:{table_last_p_k:{table_name:\"t1\"} completed:true}", "type:COMMIT", "type:BEGIN", - "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:ROW row_event:{table_name:\"t1\" row_changes:{after:{lengths:2 lengths:3 values:\"11110\"}}}", "type:GTID", "type:COMMIT", //insert for t2 done along with t1 does not generate an event since t2 is not yet copied "type:OTHER gtid:\"Copy Start t2\"", "type:BEGIN", - "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:ROW row_event:{table_name:\"t1\" row_changes:{after:{lengths:2 lengths:3 values:\"12120\"}}}", "type:GTID", "type:COMMIT", "type:BEGIN", - "type:FIELD field_event:{table_name:\"t2\" fields:{name:\"id21\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id21\" column_length:11 charset:63} fields:{name:\"id22\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id22\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t2\" fields:{name:\"id21\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id21\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id22\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id22\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:ROW row_event:{table_name:\"t2\" row_changes:{after:{lengths:1 lengths:2 values:\"120\"}}}", "type:ROW row_event:{table_name:\"t2\" row_changes:{after:{lengths:1 lengths:2 values:\"240\"}}}", "type:ROW row_event:{table_name:\"t2\" row_changes:{after:{lengths:1 lengths:2 values:\"360\"}}}", @@ -494,17 +495,17 @@ var expectedEvents = []string{ "type:COMMIT", "type:OTHER gtid:\"Copy Start t3\"", "type:BEGIN", - "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:ROW row_event:{table_name:\"t1\" row_changes:{after:{lengths:2 lengths:3 values:\"13130\"}}}", "type:GTID", "type:COMMIT", "type:BEGIN", - "type:FIELD field_event:{table_name:\"t2\" fields:{name:\"id21\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id21\" column_length:11 charset:63} fields:{name:\"id22\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id22\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t2\" fields:{name:\"id21\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id21\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id22\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id22\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:ROW row_event:{table_name:\"t2\" row_changes:{after:{lengths:2 lengths:3 values:\"12240\"}}}", "type:GTID", "type:COMMIT", "type:BEGIN", - "type:FIELD field_event:{table_name:\"t3\" fields:{name:\"id31\" type:INT32 table:\"t3\" org_table:\"t3\" database:\"vttest\" org_name:\"id31\" column_length:11 charset:63} fields:{name:\"id32\" type:INT32 table:\"t3\" org_table:\"t3\" database:\"vttest\" org_name:\"id32\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t3\" fields:{name:\"id31\" type:INT32 table:\"t3\" org_table:\"t3\" database:\"vttest\" org_name:\"id31\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id32\" type:INT32 table:\"t3\" org_table:\"t3\" database:\"vttest\" org_name:\"id32\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:ROW row_event:{table_name:\"t3\" row_changes:{after:{lengths:1 lengths:2 values:\"130\"}}}", "type:ROW row_event:{table_name:\"t3\" row_changes:{after:{lengths:1 lengths:2 values:\"260\"}}}", "type:ROW row_event:{table_name:\"t3\" row_changes:{after:{lengths:1 lengths:2 values:\"390\"}}}", @@ -522,17 +523,17 @@ var expectedEvents = []string{ "type:COMMIT", "type:OTHER gtid:\"Copy Done\"", "type:BEGIN", - "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:ROW row_event:{table_name:\"t1\" row_changes:{after:{lengths:2 lengths:3 values:\"14140\"}}}", "type:GTID", "type:COMMIT", "type:BEGIN", - "type:FIELD field_event:{table_name:\"t2\" fields:{name:\"id21\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id21\" column_length:11 charset:63} fields:{name:\"id22\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id22\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t2\" fields:{name:\"id21\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id21\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id22\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id22\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:ROW row_event:{table_name:\"t2\" row_changes:{after:{lengths:2 lengths:3 values:\"13260\"}}}", "type:GTID", "type:COMMIT", "type:BEGIN", - "type:FIELD field_event:{table_name:\"t3\" fields:{name:\"id31\" type:INT32 table:\"t3\" org_table:\"t3\" database:\"vttest\" org_name:\"id31\" column_length:11 charset:63} fields:{name:\"id32\" type:INT32 table:\"t3\" org_table:\"t3\" database:\"vttest\" org_name:\"id32\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t3\" fields:{name:\"id31\" type:INT32 table:\"t3\" org_table:\"t3\" database:\"vttest\" org_name:\"id31\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id32\" type:INT32 table:\"t3\" org_table:\"t3\" database:\"vttest\" org_name:\"id32\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:ROW row_event:{table_name:\"t3\" row_changes:{after:{lengths:2 lengths:3 values:\"12360\"}}}", "type:SAVEPOINT statement:\"SAVEPOINT `a`\"", "type:SAVEPOINT statement:\"SAVEPOINT `b`\"", diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go index 1d0e3d32733..877c44b93f9 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go +++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go @@ -21,7 +21,6 @@ import ( "context" "fmt" "io" - "strings" "time" "google.golang.org/protobuf/encoding/prototext" @@ -132,6 +131,12 @@ func (vs *vstreamer) SetVSchema(vschema *localVSchema) { select { case vs.vevents <- vschema: case <-vs.ctx.Done(): + default: // if there is a pending vschema in the channel, drain it and update it with the latest one + select { + case <-vs.vevents: + vs.vevents <- vschema + default: + } } } @@ -144,7 +149,11 @@ func (vs *vstreamer) Cancel() { func (vs *vstreamer) Stream() error { //defer vs.cancel() ctx := context.Background() - defer ctx.Done() + vs.vse.vstreamerCount.Add(1) + defer func() { + ctx.Done() + vs.vse.vstreamerCount.Add(-1) + }() vs.vse.vstreamersCreated.Add(1) log.Infof("Starting Stream() with startPos %s", vs.startPos) pos, err := mysql.DecodePosition(vs.startPos) @@ -271,16 +280,31 @@ func (vs *vstreamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog for { // check throttler. if !vs.vse.throttlerClient.ThrottleCheckOKOrWait(ctx) { + select { + // make sure to leave if context is cancelled + case <-ctx.Done(): + return + default: + // do nothing special + } continue } - - ev, ok := <-events - if ok { - throttledEvents <- ev - } else { - close(throttledEvents) + select { + case ev, ok := <-events: + if ok { + select { + case throttledEvents <- ev: + case <-ctx.Done(): + return + } + } else { + close(throttledEvents) + return + } + case <-ctx.Done(): return } + } }() for { @@ -316,11 +340,16 @@ func (vs *vstreamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog } } case vs.vschema = <-vs.vevents: - if err := vs.rebuildPlans(); err != nil { - return err + select { + case <-ctx.Done(): + return nil + default: + if err := vs.rebuildPlans(); err != nil { + return err + } + // Increment this counter for testing. + vschemaUpdateCount.Add(1) } - // Increment this counter for testing. - vschemaUpdateCount.Add(1) case <-ctx.Done(): return nil case <-timer.C: @@ -497,14 +526,23 @@ func (vs *vstreamer) parseEvent(ev mysql.BinlogEvent) ([]*binlogdatapb.VEvent, e // will generate a new plan and FIELD event. id := ev.TableID(vs.format) - if _, ok := vs.plans[id]; ok { - return nil, nil - } - tm, err := ev.TableMap(vs.format) if err != nil { return nil, err } + + if plan, ok := vs.plans[id]; ok { + // When the underlying mysql server restarts the table map can change. + // Usually the vstreamer will also error out when this happens, and vstreamer re-initializes its table map. + // But if the vstreamer is not aware of the restart, we could get an id that matches one in the cache, but + // is for a different table. We then invalidate and recompute the plan for this id. + if plan == nil || plan.Table.Name == tm.Name { + return nil, nil + } + vs.plans[id] = nil + log.Infof("table map changed: id %d for %s has changed to %s", id, plan.Table.Name, tm.Name) + } + if tm.Database == "_vt" && tm.Name == "resharding_journal" { // A journal is a special case that generates a JOURNAL event. return nil, vs.buildJournalPlan(id, tm) @@ -713,11 +751,13 @@ func (vs *vstreamer) buildTableColumns(tm *mysql.TableMap) ([]*querypb.Field, er return nil, err } for _, field := range fields { - typ := strings.ToLower(field.Type.String()) - if typ == "enum" || typ == "set" { - if extColInfo, ok := extColInfos[field.Name]; ok { - field.ColumnType = extColInfo.columnType - } + // we want the MySQL column type info so that we can properly handle + // ambiguous binlog events and other cases where the internal types + // don't match the MySQL column type. One example being that in binlog + // events CHAR columns with a binary collation are indistinguishable + // from BINARY columns. + if extColInfo, ok := extColInfos[field.Name]; ok { + field.ColumnType = extColInfo.columnType } } return fields, nil @@ -868,14 +908,13 @@ func (vs *vstreamer) extractRowAndFilter(plan *streamerPlan, data []byte, dataCo valueIndex++ continue } - value, l, err := mysql.CellValue(data, pos, plan.TableMap.Types[colNum], plan.TableMap.Metadata[colNum], plan.Table.Fields[colNum].Type) + value, l, err := mysql.CellValue(data, pos, plan.TableMap.Types[colNum], plan.TableMap.Metadata[colNum], plan.Table.Fields[colNum]) if err != nil { log.Errorf("extractRowAndFilter: %s, table: %s, colNum: %d, fields: %+v, current values: %+v", err, plan.Table.Name, colNum, plan.Table.Fields, values) return false, nil, err } pos += l - values[colNum] = value valueIndex++ } diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go index fe1c7343226..b4e48fc501f 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go +++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go @@ -99,8 +99,8 @@ func TestSetAndEnum(t *testing.T) { table: "t1", db: "vttest", cols: []*TestColumn{ - {name: "id", dataType: "INT32", colType: "", len: 11, charset: 63}, - {name: "val", dataType: "BINARY", colType: "", len: 4, charset: 63}, + {name: "id", dataType: "INT32", colType: "int(11)", len: 11, charset: 63}, + {name: "val", dataType: "BINARY", colType: "binary(4)", len: 4, charset: 63}, {name: "color", dataType: "SET", colType: "set('red','green','blue')", len: 42, charset: 33}, {name: "size", dataType: "ENUM", colType: "enum('S','M','L')", len: 3, charset: 33}, }, @@ -126,10 +126,12 @@ func TestCellValuePadding(t *testing.T) { execStatements(t, []string{ "create table t1(id int, val binary(4), primary key(val))", "create table t2(id int, val char(4), primary key(val))", + "create table t3(id int, val char(4) collate utf8mb4_bin, primary key(val))", }) defer execStatements(t, []string{ "drop table t1", "drop table t2", + "drop table t3", }) engine.se.Reload(context.Background()) queries := []string{ @@ -140,6 +142,9 @@ func TestCellValuePadding(t *testing.T) { "insert into t2 values (1, 'aaa')", "insert into t2 values (2, 'bbb')", "update t2 set id = 11 where val = 'aaa'", + "insert into t3 values (1, 'aaa')", + "insert into t3 values (2, 'bb')", + "update t3 set id = 11 where val = 'aaa'", "commit", } @@ -147,14 +152,18 @@ func TestCellValuePadding(t *testing.T) { input: queries, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"t1" fields:{name:"id" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:BINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:4 charset:63}}`, + `type:FIELD field_event:{table_name:"t1" fields:{name:"id" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:BINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:4 charset:63 column_type:"binary(4)"}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:4 values:"1aaa\x00"}}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:4 values:"2bbb\x00"}}}`, `type:ROW row_event:{table_name:"t1" row_changes:{before:{lengths:1 lengths:4 values:"1aaa\x00"} after:{lengths:2 lengths:4 values:"11aaa\x00"}}}`, - `type:FIELD field_event:{table_name:"t2" fields:{name:"id" type:INT32 table:"t2" org_table:"t2" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:CHAR table:"t2" org_table:"t2" database:"vttest" org_name:"val" column_length:12 charset:33}}`, + `type:FIELD field_event:{table_name:"t2" fields:{name:"id" type:INT32 table:"t2" org_table:"t2" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:CHAR table:"t2" org_table:"t2" database:"vttest" org_name:"val" column_length:12 charset:33 column_type:"char(4)"}}`, `type:ROW row_event:{table_name:"t2" row_changes:{after:{lengths:1 lengths:3 values:"1aaa"}}}`, `type:ROW row_event:{table_name:"t2" row_changes:{after:{lengths:1 lengths:3 values:"2bbb"}}}`, `type:ROW row_event:{table_name:"t2" row_changes:{before:{lengths:1 lengths:3 values:"1aaa"} after:{lengths:2 lengths:3 values:"11aaa"}}}`, + `type:FIELD field_event:{table_name:"t3" fields:{name:"id" type:INT32 table:"t3" org_table:"t3" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:BINARY table:"t3" org_table:"t3" database:"vttest" org_name:"val" column_length:12 charset:33 column_type:"char(4)"}}`, + `type:ROW row_event:{table_name:"t3" row_changes:{after:{lengths:1 lengths:3 values:"1aaa"}}}`, + `type:ROW row_event:{table_name:"t3" row_changes:{after:{lengths:1 lengths:2 values:"2bb"}}}`, + `type:ROW row_event:{table_name:"t3" row_changes:{before:{lengths:1 lengths:3 values:"1aaa"} after:{lengths:2 lengths:3 values:"11aaa"}}}`, `gtid`, `commit`, }}, @@ -172,6 +181,7 @@ func TestSetStatement(t *testing.T) { log.Info("Cannot test SetStatement on this flavor") return } + engine.se.Reload(context.Background()) execStatements(t, []string{ "create table t1(id int, val varbinary(128), primary key(id))", @@ -191,7 +201,7 @@ func TestSetStatement(t *testing.T) { input: queries, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"t1" fields:{name:"id" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"t1" fields:{name:"id" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:3 values:"1aaa"}}}`, `gtid`, `commit`, @@ -226,7 +236,7 @@ func TestStmtComment(t *testing.T) { input: queries, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"t1" fields:{name:"id" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"t1" fields:{name:"id" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:3 values:"1aaa"}}}`, `gtid`, `commit`, @@ -317,6 +327,7 @@ func TestMissingTables(t *testing.T) { if testing.Short() { t.Skip() } + engine.se.Reload(context.Background()) execStatements(t, []string{ "create table t1(id11 int, id12 int, primary key(id11))", "create table shortlived(id31 int, id32 int, primary key(id31))", @@ -359,7 +370,7 @@ func TestMissingTables(t *testing.T) { }, { "begin", - "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:ROW row_event:{table_name:\"t1\" row_changes:{after:{lengths:3 lengths:4 values:\"1011010\"}}}", "gtid", "commit", @@ -422,13 +433,13 @@ func TestVStreamCopySimpleFlow(t *testing.T) { insertEvents1 := []string{ "begin", - "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t1\" fields:{name:\"id11\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id11\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id12\" type:INT32 table:\"t1\" org_table:\"t1\" database:\"vttest\" org_name:\"id12\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:ROW row_event:{table_name:\"t1\" row_changes:{after:{lengths:3 lengths:4 values:\"1011010\"}}}", "gtid", "commit"} insertEvents2 := []string{ "begin", - "type:FIELD field_event:{table_name:\"t2\" fields:{name:\"id21\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id21\" column_length:11 charset:63} fields:{name:\"id22\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id22\" column_length:11 charset:63}}", + "type:FIELD field_event:{table_name:\"t2\" fields:{name:\"id21\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id21\" column_length:11 charset:63 column_type:\"int(11)\"} fields:{name:\"id22\" type:INT32 table:\"t2\" org_table:\"t2\" database:\"vttest\" org_name:\"id22\" column_length:11 charset:63 column_type:\"int(11)\"}}", "type:ROW row_event:{table_name:\"t2\" row_changes:{after:{lengths:3 lengths:4 values:\"2022020\"}}}", "gtid", "commit"} @@ -524,6 +535,9 @@ func TestVStreamCopyWithDifferentFilters(t *testing.T) { wg.Add(1) ctx2, cancel2 := context.WithDeadline(ctx, time.Now().Add(10*time.Second)) defer cancel2() + // BACKPORT: required for backport of https://github.com/vitessio/vitess/pull/9355 + // Taken from https://github.com/vitessio/vitess/commit/01c0abfd975ee42b58c53f46cbbcc451a79466b0#diff-eeecb1b9a8e699bf997463778bc971d0742f0c478f7dba68dfb8cfceb3dab29bR525-R565 + var errGoroutine error go func() { defer wg.Done() engine.Stream(ctx2, "", nil, filter, func(evs []*binlogdatapb.VEvent) error { @@ -545,7 +559,8 @@ func TestVStreamCopyWithDifferentFilters(t *testing.T) { got := ev.String() want := expectedEvents[i] if !strings.HasPrefix(got, want) { - t.Fatalf("Event %d did not match, want %s, got %s", i, want, got) + errGoroutine = fmt.Errorf("Event %d did not match, want %s, got %s", i, want, got) + return errGoroutine } } @@ -555,6 +570,9 @@ func TestVStreamCopyWithDifferentFilters(t *testing.T) { }) }() wg.Wait() + if errGoroutine != nil { + t.Fatalf(errGoroutine.Error()) + } } func TestFilteredVarBinary(t *testing.T) { @@ -594,7 +612,7 @@ func TestFilteredVarBinary(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"t1" fields:{name:"id1" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"t1" fields:{name:"id1" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:6 values:"2newton"}}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:6 values:"3newton"}}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:6 values:"5newton"}}}`, @@ -614,6 +632,7 @@ func TestFilteredInt(t *testing.T) { if testing.Short() { t.Skip() } + engine.se.Reload(context.Background()) execStatements(t, []string{ "create table t1(id1 int, id2 int, val varbinary(128), primary key(id1))", @@ -647,7 +666,7 @@ func TestFilteredInt(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"t1" fields:{name:"id1" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"t1" fields:{name:"id1" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:3 values:"2bbb"}}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:3 values:"4ddd"}}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:3 values:"5eee"}}}`, @@ -691,7 +710,7 @@ func TestSavepoint(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"stream1" fields:{name:"id" type:INT32 table:"stream1" org_table:"stream1" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"stream1" org_table:"stream1" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"stream1" fields:{name:"id" type:INT32 table:"stream1" org_table:"stream1" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"stream1" org_table:"stream1" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"stream1" row_changes:{after:{lengths:1 lengths:3 values:"1aaa"}}}`, "type:SAVEPOINT statement:\"SAVEPOINT `a`\"", "type:SAVEPOINT statement:\"SAVEPOINT `b`\"", @@ -727,7 +746,7 @@ func TestStatements(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"stream1" fields:{name:"id" type:INT32 table:"stream1" org_table:"stream1" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"stream1" org_table:"stream1" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"stream1" fields:{name:"id" type:INT32 table:"stream1" org_table:"stream1" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"stream1" org_table:"stream1" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"stream1" row_changes:{after:{lengths:1 lengths:3 values:"1aaa"}}}`, `type:ROW row_event:{table_name:"stream1" row_changes:{before:{lengths:1 lengths:3 values:"1aaa"} after:{lengths:1 lengths:3 values:"1bbb"}}}`, `gtid`, @@ -759,9 +778,9 @@ func TestStatements(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"stream1" fields:{name:"id" type:INT32 table:"stream1" org_table:"stream1" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"stream1" org_table:"stream1" database:"vttest" org_name:"val" column_length:256 charset:63}}`, + `type:FIELD field_event:{table_name:"stream1" fields:{name:"id" type:INT32 table:"stream1" org_table:"stream1" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"stream1" org_table:"stream1" database:"vttest" org_name:"val" column_length:256 charset:63 column_type:"varbinary(256)"}}`, `type:ROW row_event:{table_name:"stream1" row_changes:{after:{lengths:1 lengths:3 values:"2bbb"}}}`, - `type:FIELD field_event:{table_name:"stream2" fields:{name:"id" type:INT32 table:"stream2" org_table:"stream2" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"stream2" org_table:"stream2" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"stream2" fields:{name:"id" type:INT32 table:"stream2" org_table:"stream2" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"stream2" org_table:"stream2" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"stream2" row_changes:{after:{lengths:1 lengths:3 values:"1aaa"}}}`, `type:ROW row_event:{table_name:"stream1" ` + `row_changes:{before:{lengths:1 lengths:3 values:"1bbb"} after:{lengths:1 lengths:3 values:"1ccc"}} ` + @@ -795,6 +814,7 @@ func TestStatements(t *testing.T) { in.Flavor = "FilePos" return in }) + defer engine.Close() runCases(t, nil, testcases, "current", nil) } @@ -902,7 +922,7 @@ func TestRegexp(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"yes_stream" fields:{name:"id" type:INT32 table:"yes_stream" org_table:"yes_stream" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"yes_stream" org_table:"yes_stream" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"yes_stream" fields:{name:"id" type:INT32 table:"yes_stream" org_table:"yes_stream" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"yes_stream" org_table:"yes_stream" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"yes_stream" row_changes:{after:{lengths:1 lengths:3 values:"1aaa"}}}`, `type:ROW row_event:{table_name:"yes_stream" row_changes:{before:{lengths:1 lengths:3 values:"1aaa"} after:{lengths:1 lengths:3 values:"1bbb"}}}`, `gtid`, @@ -958,11 +978,11 @@ func TestREKeyRange(t *testing.T) { execStatements(t, input) expectLog(ctx, t, input, ch, [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"t1" fields:{name:"id1" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"id2" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id2" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63}}`, - `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:1 lengths:3 values:"14aaa"}}}`, - `type:ROW row_event:{table_name:"t1" row_changes:{before:{lengths:1 lengths:1 lengths:3 values:"14aaa"} after:{lengths:1 lengths:1 lengths:3 values:"24aaa"}}}`, - `type:ROW row_event:{table_name:"t1" row_changes:{before:{lengths:1 lengths:1 lengths:3 values:"24aaa"}}}`, - `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:1 lengths:3 values:"31bbb"}}}`, + `type:FIELD field_event:{table_name:"t1" fields:{name:"id1" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id2" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"} keyspace:"vttest" shard:"0"}`, + `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:1 lengths:3 values:"14aaa"}} keyspace:"vttest" shard:"0"}`, + `type:ROW row_event:{table_name:"t1" row_changes:{before:{lengths:1 lengths:1 lengths:3 values:"14aaa"} after:{lengths:1 lengths:1 lengths:3 values:"24aaa"}} keyspace:"vttest" shard:"0"}`, + `type:ROW row_event:{table_name:"t1" row_changes:{before:{lengths:1 lengths:1 lengths:3 values:"24aaa"}} keyspace:"vttest" shard:"0"}`, + `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:1 lengths:3 values:"31bbb"}} keyspace:"vttest" shard:"0"}`, `gtid`, `commit`, }}) @@ -1009,6 +1029,8 @@ func TestInKeyRangeMultiColumn(t *testing.T) { if testing.Short() { t.Skip() } + engine.watcherOnce.Do(engine.setWatch) + engine.se.Reload(context.Background()) execStatements(t, []string{ "create table t1(region int, id int, val varbinary(128), primary key(id))", @@ -1050,7 +1072,7 @@ func TestInKeyRangeMultiColumn(t *testing.T) { execStatements(t, input) expectLog(ctx, t, input, ch, [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"t1" fields:{name:"id" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"region" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"region" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63} fields:{name:"keyspace_id" type:VARBINARY}}`, + `type:FIELD field_event:{table_name:"t1" fields:{name:"id" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"region" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"region" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"} fields:{name:"keyspace_id" type:VARBINARY}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:1 lengths:3 lengths:9 values:"11aaa\x01\x16k@\xb4J\xbaK\xd6"}}}`, `type:ROW row_event:{table_name:"t1" row_changes:{before:{lengths:1 lengths:1 lengths:3 lengths:9 values:"11aaa\x01\x16k@\xb4J\xbaK\xd6"} ` + `after:{lengths:1 lengths:1 lengths:3 lengths:9 values:"12aaa\x02\x16k@\xb4J\xbaK\xd6"}}}`, @@ -1066,6 +1088,7 @@ func TestREMultiColumnVindex(t *testing.T) { if testing.Short() { t.Skip() } + engine.watcherOnce.Do(engine.setWatch) execStatements(t, []string{ "create table t1(region int, id int, val varbinary(128), primary key(id))", @@ -1107,7 +1130,7 @@ func TestREMultiColumnVindex(t *testing.T) { execStatements(t, input) expectLog(ctx, t, input, ch, [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"t1" fields:{name:"region" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"region" column_length:11 charset:63} fields:{name:"id" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"t1" fields:{name:"region" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"region" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"id" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:1 lengths:3 values:"11aaa"}}}`, `type:ROW row_event:{table_name:"t1" row_changes:{before:{lengths:1 lengths:1 lengths:3 values:"11aaa"} after:{lengths:1 lengths:1 lengths:3 values:"21aaa"}}}`, `type:ROW row_event:{table_name:"t1" row_changes:{before:{lengths:1 lengths:1 lengths:3 values:"21aaa"}}}`, @@ -1122,6 +1145,7 @@ func TestSelectFilter(t *testing.T) { if testing.Short() { t.Skip() } + engine.se.Reload(context.Background()) execStatements(t, []string{ "create table t1(id1 int, id2 int, val varbinary(128), primary key(id1))", @@ -1147,7 +1171,7 @@ func TestSelectFilter(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"t1" fields:{name:"id2" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id2" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"t1" fields:{name:"id2" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:3 values:"1aaa"}}}`, `gtid`, `commit`, @@ -1210,9 +1234,9 @@ func TestDDLAddColumn(t *testing.T) { expectLog(ctx, t, "ddls", ch, [][]string{{ // Current schema has 3 columns, but they'll be truncated to match the two columns in the event. `begin`, - `type:FIELD field_event:{table_name:"ddl_test1" fields:{name:"id" type:INT32 table:"ddl_test1" org_table:"ddl_test1" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val1" type:VARBINARY table:"ddl_test1" org_table:"ddl_test1" database:"vttest" org_name:"val1" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"ddl_test1" fields:{name:"id" type:INT32 table:"ddl_test1" org_table:"ddl_test1" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val1" type:VARBINARY table:"ddl_test1" org_table:"ddl_test1" database:"vttest" org_name:"val1" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"ddl_test1" row_changes:{after:{lengths:1 lengths:3 values:"1aaa"}}}`, - `type:FIELD field_event:{table_name:"ddl_test2" fields:{name:"id" type:INT32 table:"ddl_test2" org_table:"ddl_test2" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val1" type:VARBINARY table:"ddl_test2" org_table:"ddl_test2" database:"vttest" org_name:"val1" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"ddl_test2" fields:{name:"id" type:INT32 table:"ddl_test2" org_table:"ddl_test2" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val1" type:VARBINARY table:"ddl_test2" org_table:"ddl_test2" database:"vttest" org_name:"val1" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"ddl_test2" row_changes:{after:{lengths:1 lengths:3 values:"1aaa"}}}`, `gtid`, `commit`, @@ -1226,9 +1250,9 @@ func TestDDLAddColumn(t *testing.T) { // The plan will be updated to now include the third column // because the new table map will have three columns. `begin`, - `type:FIELD field_event:{table_name:"ddl_test1" fields:{name:"id" type:INT32 table:"ddl_test1" org_table:"ddl_test1" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val1" type:VARBINARY table:"ddl_test1" org_table:"ddl_test1" database:"vttest" org_name:"val1" column_length:128 charset:63} fields:{name:"val2" type:VARBINARY table:"ddl_test1" org_table:"ddl_test1" database:"vttest" org_name:"val2" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"ddl_test1" fields:{name:"id" type:INT32 table:"ddl_test1" org_table:"ddl_test1" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val1" type:VARBINARY table:"ddl_test1" org_table:"ddl_test1" database:"vttest" org_name:"val1" column_length:128 charset:63 column_type:"varbinary(128)"} fields:{name:"val2" type:VARBINARY table:"ddl_test1" org_table:"ddl_test1" database:"vttest" org_name:"val2" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"ddl_test1" row_changes:{after:{lengths:1 lengths:3 lengths:3 values:"2bbbccc"}}}`, - `type:FIELD field_event:{table_name:"ddl_test2" fields:{name:"id" type:INT32 table:"ddl_test2" org_table:"ddl_test2" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val1" type:VARBINARY table:"ddl_test2" org_table:"ddl_test2" database:"vttest" org_name:"val1" column_length:128 charset:63} fields:{name:"val2" type:VARBINARY table:"ddl_test2" org_table:"ddl_test2" database:"vttest" org_name:"val2" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"ddl_test2" fields:{name:"id" type:INT32 table:"ddl_test2" org_table:"ddl_test2" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val1" type:VARBINARY table:"ddl_test2" org_table:"ddl_test2" database:"vttest" org_name:"val1" column_length:128 charset:63 column_type:"varbinary(128)"} fields:{name:"val2" type:VARBINARY table:"ddl_test2" org_table:"ddl_test2" database:"vttest" org_name:"val2" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"ddl_test2" row_changes:{after:{lengths:1 lengths:3 lengths:3 values:"2bbbccc"}}}`, `gtid`, `commit`, @@ -1239,7 +1263,7 @@ func TestDDLDropColumn(t *testing.T) { if testing.Short() { t.Skip() } - + env.SchemaEngine.Reload(context.Background()) execStatement(t, "create table ddl_test2(id int, val1 varbinary(128), val2 varbinary(128), primary key(id))") defer execStatement(t, "drop table ddl_test2") @@ -1252,6 +1276,7 @@ func TestDDLDropColumn(t *testing.T) { "insert into ddl_test2 values(2, 'bbb')", }) engine.se.Reload(context.Background()) + env.SchemaEngine.Reload(context.Background()) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -1317,7 +1342,7 @@ func TestBuffering(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"packet_test" fields:{name:"id" type:INT32 table:"packet_test" org_table:"packet_test" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"packet_test" org_table:"packet_test" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"packet_test" fields:{name:"id" type:INT32 table:"packet_test" org_table:"packet_test" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"packet_test" org_table:"packet_test" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"packet_test" row_changes:{after:{lengths:1 lengths:3 values:"1123"}}}`, `type:ROW row_event:{table_name:"packet_test" row_changes:{after:{lengths:1 lengths:3 values:"2456"}}}`, `gtid`, @@ -1435,7 +1460,7 @@ func TestBestEffortNameInFieldEvent(t *testing.T) { `type:DDL statement:"rename table vitess_test to vitess_test_new"`, }, { `begin`, - `type:FIELD field_event:{table_name:"vitess_test_new" fields:{name:"id" type:INT32 table:"vitess_test_new" org_table:"vitess_test_new" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"vitess_test_new" org_table:"vitess_test_new" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_test_new" fields:{name:"id" type:INT32 table:"vitess_test_new" org_table:"vitess_test_new" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"vitess_test_new" org_table:"vitess_test_new" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"vitess_test_new" row_changes:{after:{lengths:1 lengths:3 values:"2abc"}}}`, `gtid`, `commit`, @@ -1485,7 +1510,7 @@ func TestInternalTables(t *testing.T) { // information returned by binlog for val column == varchar (rather than varbinary). output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"vitess_test" fields:{name:"id" type:INT32 table:"vitess_test" org_table:"vitess_test" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"vitess_test" org_table:"vitess_test" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_test" fields:{name:"id" type:INT32 table:"vitess_test" org_table:"vitess_test" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"vitess_test" org_table:"vitess_test" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"vitess_test" row_changes:{after:{lengths:1 lengths:3 values:"1abc"}}}`, `gtid`, `commit`, @@ -1530,7 +1555,7 @@ func TestTypes(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"vitess_ints" fields:{name:"tiny" type:INT8 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"tiny" column_length:4 charset:63} fields:{name:"tinyu" type:UINT8 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"tinyu" column_length:3 charset:63} fields:{name:"small" type:INT16 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"small" column_length:6 charset:63} fields:{name:"smallu" type:UINT16 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"smallu" column_length:5 charset:63} fields:{name:"medium" type:INT24 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"medium" column_length:9 charset:63} fields:{name:"mediumu" type:UINT24 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"mediumu" column_length:8 charset:63} fields:{name:"normal" type:INT32 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"normal" column_length:11 charset:63} fields:{name:"normalu" type:UINT32 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"normalu" column_length:10 charset:63} fields:{name:"big" type:INT64 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"big" column_length:20 charset:63} fields:{name:"bigu" type:UINT64 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"bigu" column_length:20 charset:63} fields:{name:"y" type:YEAR table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"y" column_length:4 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_ints" fields:{name:"tiny" type:INT8 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"tiny" column_length:4 charset:63 column_type:"tinyint(4)"} fields:{name:"tinyu" type:UINT8 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"tinyu" column_length:3 charset:63 column_type:"tinyint(3) unsigned"} fields:{name:"small" type:INT16 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"small" column_length:6 charset:63 column_type:"smallint(6)"} fields:{name:"smallu" type:UINT16 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"smallu" column_length:5 charset:63 column_type:"smallint(5) unsigned"} fields:{name:"medium" type:INT24 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"medium" column_length:9 charset:63 column_type:"mediumint(9)"} fields:{name:"mediumu" type:UINT24 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"mediumu" column_length:8 charset:63 column_type:"mediumint(8) unsigned"} fields:{name:"normal" type:INT32 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"normal" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"normalu" type:UINT32 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"normalu" column_length:10 charset:63 column_type:"int(10) unsigned"} fields:{name:"big" type:INT64 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"big" column_length:20 charset:63 column_type:"bigint(20)"} fields:{name:"bigu" type:UINT64 table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"bigu" column_length:20 charset:63 column_type:"bigint(20) unsigned"} fields:{name:"y" type:YEAR table:"vitess_ints" org_table:"vitess_ints" database:"vttest" org_name:"y" column_length:4 charset:63 column_type:"year(4)"}}`, `type:ROW row_event:{table_name:"vitess_ints" row_changes:{after:{lengths:4 lengths:3 lengths:6 lengths:5 lengths:8 lengths:8 lengths:11 lengths:10 lengths:20 lengths:20 lengths:4 values:"` + `-128` + `255` + @@ -1553,7 +1578,7 @@ func TestTypes(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"vitess_fracts" fields:{name:"id" type:INT32 table:"vitess_fracts" org_table:"vitess_fracts" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"deci" type:DECIMAL table:"vitess_fracts" org_table:"vitess_fracts" database:"vttest" org_name:"deci" column_length:7 charset:63 decimals:2} fields:{name:"num" type:DECIMAL table:"vitess_fracts" org_table:"vitess_fracts" database:"vttest" org_name:"num" column_length:7 charset:63 decimals:2} fields:{name:"f" type:FLOAT32 table:"vitess_fracts" org_table:"vitess_fracts" database:"vttest" org_name:"f" column_length:12 charset:63 decimals:31} fields:{name:"d" type:FLOAT64 table:"vitess_fracts" org_table:"vitess_fracts" database:"vttest" org_name:"d" column_length:22 charset:63 decimals:31}}`, + `type:FIELD field_event:{table_name:"vitess_fracts" fields:{name:"id" type:INT32 table:"vitess_fracts" org_table:"vitess_fracts" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"deci" type:DECIMAL table:"vitess_fracts" org_table:"vitess_fracts" database:"vttest" org_name:"deci" column_length:7 charset:63 decimals:2 column_type:"decimal(5,2)"} fields:{name:"num" type:DECIMAL table:"vitess_fracts" org_table:"vitess_fracts" database:"vttest" org_name:"num" column_length:7 charset:63 decimals:2 column_type:"decimal(5,2)"} fields:{name:"f" type:FLOAT32 table:"vitess_fracts" org_table:"vitess_fracts" database:"vttest" org_name:"f" column_length:12 charset:63 decimals:31 column_type:"float"} fields:{name:"d" type:FLOAT64 table:"vitess_fracts" org_table:"vitess_fracts" database:"vttest" org_name:"d" column_length:22 charset:63 decimals:31 column_type:"double"}}`, `type:ROW row_event:{table_name:"vitess_fracts" row_changes:{after:{lengths:1 lengths:4 lengths:4 lengths:8 lengths:8 values:"11.992.993.99E+004.99E+00"}}}`, `gtid`, `commit`, @@ -1565,7 +1590,7 @@ func TestTypes(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"vitess_strings" fields:{name:"vb" type:VARBINARY table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"vb" column_length:16 charset:63} fields:{name:"c" type:CHAR table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"c" column_length:48 charset:33} fields:{name:"vc" type:VARCHAR table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"vc" column_length:48 charset:33} fields:{name:"b" type:BINARY table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"b" column_length:4 charset:63} fields:{name:"tb" type:BLOB table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"tb" column_length:255 charset:63} fields:{name:"bl" type:BLOB table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"bl" column_length:65535 charset:63} fields:{name:"ttx" type:TEXT table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"ttx" column_length:765 charset:33} fields:{name:"tx" type:TEXT table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"tx" column_length:196605 charset:33} fields:{name:"en" type:ENUM table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"en" column_length:3 charset:33 column_type:"enum('a','b')"} fields:{name:"s" type:SET table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"s" column_length:9 charset:33 column_type:"set('a','b')"}}`, + `type:FIELD field_event:{table_name:"vitess_strings" fields:{name:"vb" type:VARBINARY table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"vb" column_length:16 charset:63 column_type:"varbinary(16)"} fields:{name:"c" type:CHAR table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"c" column_length:48 charset:33 column_type:"char(16)"} fields:{name:"vc" type:VARCHAR table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"vc" column_length:48 charset:33 column_type:"varchar(16)"} fields:{name:"b" type:BINARY table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"b" column_length:4 charset:63 column_type:"binary(4)"} fields:{name:"tb" type:BLOB table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"tb" column_length:255 charset:63 column_type:"tinyblob"} fields:{name:"bl" type:BLOB table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"bl" column_length:65535 charset:63 column_type:"blob"} fields:{name:"ttx" type:TEXT table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"ttx" column_length:765 charset:33 column_type:"tinytext"} fields:{name:"tx" type:TEXT table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"tx" column_length:196605 charset:33 column_type:"text"} fields:{name:"en" type:ENUM table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"en" column_length:3 charset:33 column_type:"enum('a','b')"} fields:{name:"s" type:SET table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"s" column_length:9 charset:33 column_type:"set('a','b')"}}`, `type:ROW row_event:{table_name:"vitess_strings" row_changes:{after:{lengths:1 lengths:1 lengths:1 lengths:4 lengths:1 lengths:1 lengths:1 lengths:1 lengths:1 lengths:1 ` + `values:"abcd\x00\x00\x00efgh13"}}}`, `gtid`, @@ -1578,7 +1603,7 @@ func TestTypes(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"vitess_misc" fields:{name:"id" type:INT32 table:"vitess_misc" org_table:"vitess_misc" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"b" type:BIT table:"vitess_misc" org_table:"vitess_misc" database:"vttest" org_name:"b" column_length:8 charset:63} fields:{name:"d" type:DATE table:"vitess_misc" org_table:"vitess_misc" database:"vttest" org_name:"d" column_length:10 charset:63} fields:{name:"dt" type:DATETIME table:"vitess_misc" org_table:"vitess_misc" database:"vttest" org_name:"dt" column_length:19 charset:63} fields:{name:"t" type:TIME table:"vitess_misc" org_table:"vitess_misc" database:"vttest" org_name:"t" column_length:10 charset:63} fields:{name:"g" type:GEOMETRY table:"vitess_misc" org_table:"vitess_misc" database:"vttest" org_name:"g" column_length:4294967295 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_misc" fields:{name:"id" type:INT32 table:"vitess_misc" org_table:"vitess_misc" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"b" type:BIT table:"vitess_misc" org_table:"vitess_misc" database:"vttest" org_name:"b" column_length:8 charset:63 column_type:"bit(8)"} fields:{name:"d" type:DATE table:"vitess_misc" org_table:"vitess_misc" database:"vttest" org_name:"d" column_length:10 charset:63 column_type:"date"} fields:{name:"dt" type:DATETIME table:"vitess_misc" org_table:"vitess_misc" database:"vttest" org_name:"dt" column_length:19 charset:63 column_type:"datetime"} fields:{name:"t" type:TIME table:"vitess_misc" org_table:"vitess_misc" database:"vttest" org_name:"t" column_length:10 charset:63 column_type:"time"} fields:{name:"g" type:GEOMETRY table:"vitess_misc" org_table:"vitess_misc" database:"vttest" org_name:"g" column_length:4294967295 charset:63 column_type:"geometry"}}`, `type:ROW row_event:{table_name:"vitess_misc" row_changes:{after:{lengths:1 lengths:1 lengths:10 lengths:19 lengths:8 lengths:25 values:"1\x012012-01-012012-01-01 15:45:4515:45:45\x00\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@"}}}`, `gtid`, `commit`, @@ -1589,7 +1614,7 @@ func TestTypes(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"vitess_null" fields:{name:"id" type:INT32 table:"vitess_null" org_table:"vitess_null" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"vitess_null" org_table:"vitess_null" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"vitess_null" fields:{name:"id" type:INT32 table:"vitess_null" org_table:"vitess_null" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"vitess_null" org_table:"vitess_null" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"vitess_null" row_changes:{after:{lengths:1 lengths:-1 values:"1"}}}`, `gtid`, `commit`, @@ -1603,7 +1628,7 @@ func TestTypes(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"vitess_decimal" fields:{name:"id" type:INT32 table:"vitess_decimal" org_table:"vitess_decimal" database:"vttest" org_name:"id" column_length:11 charset:63} fields:{name:"dec1" type:DECIMAL table:"vitess_decimal" org_table:"vitess_decimal" database:"vttest" org_name:"dec1" column_length:14 charset:63 decimals:4} fields:{name:"dec2" type:DECIMAL table:"vitess_decimal" org_table:"vitess_decimal" database:"vttest" org_name:"dec2" column_length:15 charset:63 decimals:4}}`, + `type:FIELD field_event:{table_name:"vitess_decimal" fields:{name:"id" type:INT32 table:"vitess_decimal" org_table:"vitess_decimal" database:"vttest" org_name:"id" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"dec1" type:DECIMAL table:"vitess_decimal" org_table:"vitess_decimal" database:"vttest" org_name:"dec1" column_length:14 charset:63 decimals:4 column_type:"decimal(12,4)"} fields:{name:"dec2" type:DECIMAL table:"vitess_decimal" org_table:"vitess_decimal" database:"vttest" org_name:"dec2" column_length:15 charset:63 decimals:4 column_type:"decimal(13,4)"}}`, `type:ROW row_event:{table_name:"vitess_decimal" row_changes:{after:{lengths:1 lengths:6 lengths:6 values:"11.23001.2300"}}}`, `gtid`, `commit`, @@ -1912,7 +1937,7 @@ func TestFilteredMultipleWhere(t *testing.T) { }, output: [][]string{{ `begin`, - `type:FIELD field_event:{table_name:"t1" fields:{name:"id1" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id1" column_length:11 charset:63} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63}}`, + `type:FIELD field_event:{table_name:"t1" fields:{name:"id1" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int(11)"} fields:{name:"val" type:VARBINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:128 charset:63 column_type:"varbinary(128)"}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:1 lengths:6 values:"2newton"}}}`, `type:ROW row_event:{table_name:"t1" row_changes:{after:{lengths:3 lengths:6 values:"128newton"}}}`, `gtid`, @@ -1993,6 +2018,7 @@ func runCases(t *testing.T, filter *binlogdatapb.Filter, testcases []testcase, p default: t.Fatalf("unexpected input: %#v", input) } + engine.se.Reload(ctx) expectLog(ctx, t, tcase.input, ch, tcase.output) } @@ -2068,6 +2094,7 @@ func expectLog(ctx context.Context, t *testing.T, input interface{}, ch <-chan [ evs[i].FieldEvent.Fields[j].Flags = 0 } } + want = env.RemoveAnyDeprecatedDisplayWidths(want) if got := fmt.Sprintf("%v", evs[i]); got != want { log.Errorf("%v (%d): event:\n%q, want\n%q", input, i, got, want) t.Fatalf("%v (%d): event:\n%q, want\n%q", input, i, got, want) @@ -2173,6 +2200,7 @@ func setVSchema(t *testing.T, vschema string) { time.Sleep(10 * time.Millisecond) } if !updated { + log.Infof("vschema did not get updated") t.Error("vschema did not get updated") } } diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index d95da7acd37..aec8c3e2259 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -1258,12 +1258,12 @@ func (wr *Wrangler) replicaMigrateServedFrom(ctx context.Context, ki *topo.Keysp // a bit different than for rdonly / replica to guarantee a smooth transition. // // The order is as follows: -// - Add BlacklistedTables on the source shard map for master -// - Refresh the source master, so it stops writing on the tables -// - Get the source master position, wait until destination master reaches it -// - Clear SourceShard on the destination Shard -// - Refresh the destination master, so its stops its filtered -// replication and starts accepting writes +// - Add BlacklistedTables on the source shard map for master +// - Refresh the source master, so it stops writing on the tables +// - Get the source master position, wait until destination master reaches it +// - Clear SourceShard on the destination Shard +// - Refresh the destination master, so its stops its filtered +// replication and starts accepting writes func (wr *Wrangler) masterMigrateServedFrom(ctx context.Context, ki *topo.KeyspaceInfo, sourceShard *topo.ShardInfo, destinationShard *topo.ShardInfo, tables []string, ev *events.MigrateServedFrom, filteredReplicationWaitTime time.Duration) error { // Read the data we need ctx, cancel := context.WithTimeout(ctx, filteredReplicationWaitTime) diff --git a/go/vt/wrangler/materializer.go b/go/vt/wrangler/materializer.go index 0418df15a1e..115d0e94112 100644 --- a/go/vt/wrangler/materializer.go +++ b/go/vt/wrangler/materializer.go @@ -25,6 +25,7 @@ import ( "sync" "text/template" + "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" "vitess.io/vitess/go/vt/log" @@ -343,8 +344,8 @@ func (wr *Wrangler) checkIfPreviousJournalExists(ctx context.Context, mz *materi } // CreateLookupVindex creates a lookup vindex and sets up the backfill. -func (wr *Wrangler) CreateLookupVindex(ctx context.Context, keyspace string, specs *vschemapb.Keyspace, cell, tabletTypes string) error { - ms, sourceVSchema, targetVSchema, err := wr.prepareCreateLookup(ctx, keyspace, specs) +func (wr *Wrangler) CreateLookupVindex(ctx context.Context, keyspace string, specs *vschemapb.Keyspace, cell, tabletTypes string, continueAfterCopyWithOwner bool) error { + ms, sourceVSchema, targetVSchema, err := wr.prepareCreateLookup(ctx, keyspace, specs, continueAfterCopyWithOwner) if err != nil { return err } @@ -364,7 +365,7 @@ func (wr *Wrangler) CreateLookupVindex(ctx context.Context, keyspace string, spe } // prepareCreateLookup performs the preparatory steps for creating a lookup vindex. -func (wr *Wrangler) prepareCreateLookup(ctx context.Context, keyspace string, specs *vschemapb.Keyspace) (ms *vtctldatapb.MaterializeSettings, sourceVSchema, targetVSchema *vschemapb.Keyspace, err error) { +func (wr *Wrangler) prepareCreateLookup(ctx context.Context, keyspace string, specs *vschemapb.Keyspace, continueAfterCopyWithOwner bool) (ms *vtctldatapb.MaterializeSettings, sourceVSchema, targetVSchema *vschemapb.Keyspace, err error) { // Important variables are pulled out here. var ( // lookup vindex info @@ -617,7 +618,7 @@ func (wr *Wrangler) prepareCreateLookup(ctx context.Context, keyspace string, sp Workflow: targetTableName + "_vdx", SourceKeyspace: keyspace, TargetKeyspace: targetKeyspace, - StopAfterCopy: vindex.Owner != "", + StopAfterCopy: vindex.Owner != "" && !continueAfterCopyWithOwner, TableSettings: []*vtctldatapb.TableMaterializeSettings{{ TargetTable: targetTableName, SourceExpression: materializeQuery, @@ -696,7 +697,7 @@ func (wr *Wrangler) ExternalizeVindex(ctx context.Context, qualifiedVindexName s if err != nil { return err } - p3qr, err := wr.tmc.VReplicationExec(ctx, targetMaster.Tablet, fmt.Sprintf("select id, state, message from _vt.vreplication where workflow=%s and db_name=%s", encodeString(workflow), encodeString(targetMaster.DbName()))) + p3qr, err := wr.tmc.VReplicationExec(ctx, targetMaster.Tablet, fmt.Sprintf("select id, state, message, source from _vt.vreplication where workflow=%s and db_name=%s", encodeString(workflow), encodeString(targetMaster.DbName()))) if err != nil { return err } @@ -708,8 +709,14 @@ func (wr *Wrangler) ExternalizeVindex(ctx context.Context, qualifiedVindexName s } state := row[1].ToString() message := row[2].ToString() - if sourceVindex.Owner == "" { - // If there's no owner, all streams need to be running. + var bls binlogdatapb.BinlogSource + sourceBytes := row[3].ToBytes() + if err := prototext.Unmarshal(sourceBytes, &bls); err != nil { + return err + } + if sourceVindex.Owner == "" || !bls.StopAfterCopy { + // If there's no owner or we've requested that the workflow NOT be stopped + // after the copy phase completes, then all streams need to be running. if state != binlogplayer.BlpRunning { return fmt.Errorf("stream %d for %v.%v is not in Running state: %v", id, targetShard.Keyspace(), targetShard.ShardName(), state) } @@ -747,10 +754,12 @@ func (wr *Wrangler) ExternalizeVindex(ctx context.Context, qualifiedVindexName s // Remove the write_only param and save the source vschema. delete(sourceVindex.Params, "write_only") - return wr.ts.SaveVSchema(ctx, sourceKeyspace, sourceVSchema) + if err := wr.ts.SaveVSchema(ctx, sourceKeyspace, sourceVSchema); err != nil { + return err + } + return wr.ts.RebuildSrvVSchema(ctx, nil) } -// func (wr *Wrangler) collectTargetStreams(ctx context.Context, mz *materializer) ([]string, error) { var shardTablets []string var mu sync.Mutex diff --git a/go/vt/wrangler/materializer_test.go b/go/vt/wrangler/materializer_test.go index 4034f92d639..dabcb8ce4ca 100644 --- a/go/vt/wrangler/materializer_test.go +++ b/go/vt/wrangler/materializer_test.go @@ -317,7 +317,7 @@ func TestCreateLookupVindexFull(t *testing.T) { env.tmc.expectVRQuery(200, "update _vt.vreplication set state='Running' where db_name='vt_targetks' and workflow='lkp_vdx'", &sqltypes.Result{}) ctx := context.Background() - err := env.wr.CreateLookupVindex(ctx, ms.SourceKeyspace, specs, "cell", "MASTER") + err := env.wr.CreateLookupVindex(ctx, ms.SourceKeyspace, specs, "cell", "MASTER", false) require.NoError(t, err) wantvschema := &vschemapb.Keyspace{ @@ -566,7 +566,7 @@ func TestCreateLookupVindexCreateDDL(t *testing.T) { delete(env.tmc.schema, ms.SourceKeyspace+".t1") } - outms, _, _, err := env.wr.prepareCreateLookup(context.Background(), ms.SourceKeyspace, tcase.specs) + outms, _, _, err := env.wr.prepareCreateLookup(context.Background(), ms.SourceKeyspace, tcase.specs, false) if tcase.err != "" { if err == nil || !strings.Contains(err.Error(), tcase.err) { t.Errorf("prepareCreateLookup(%s) err: %v, must contain %v", tcase.description, err, tcase.err) @@ -808,7 +808,7 @@ func TestCreateLookupVindexSourceVSchema(t *testing.T) { t.Fatal(err) } - _, got, _, err := env.wr.prepareCreateLookup(context.Background(), ms.SourceKeyspace, specs) + _, got, _, err := env.wr.prepareCreateLookup(context.Background(), ms.SourceKeyspace, specs, false) require.NoError(t, err) if !proto.Equal(got, tcase.out) { t.Errorf("%s: got:\n%v, want\n%v", tcase.description, got, tcase.out) @@ -1041,7 +1041,7 @@ func TestCreateLookupVindexTargetVSchema(t *testing.T) { t.Fatal(err) } - _, _, got, err := env.wr.prepareCreateLookup(context.Background(), ms.SourceKeyspace, specs) + _, _, got, err := env.wr.prepareCreateLookup(context.Background(), ms.SourceKeyspace, specs, false) if tcase.err != "" { if err == nil || !strings.Contains(err.Error(), tcase.err) { t.Errorf("prepareCreateLookup(%s) err: %v, must contain %v", tcase.description, err, tcase.err) @@ -1156,13 +1156,89 @@ func TestCreateLookupVindexSameKeyspace(t *testing.T) { t.Fatal(err) } - _, got, _, err := env.wr.prepareCreateLookup(context.Background(), ms.SourceKeyspace, specs) + _, got, _, err := env.wr.prepareCreateLookup(context.Background(), ms.SourceKeyspace, specs, false) require.NoError(t, err) if !proto.Equal(got, want) { t.Errorf("same keyspace: got:\n%v, want\n%v", got, want) } } +func TestStopAfterCopyFlag(t *testing.T) { + ms := &vtctldatapb.MaterializeSettings{ + SourceKeyspace: "ks", + TargetKeyspace: "ks", + } + env := newTestMaterializerEnv(t, ms, []string{"0"}, []string{"0"}) + defer env.close() + specs := &vschemapb.Keyspace{ + Vindexes: map[string]*vschemapb.Vindex{ + "v": { + Type: "lookup_unique", + Params: map[string]string{ + "table": "ks.lkp", + "from": "c1", + "to": "col2", + }, + Owner: "t1", + }, + }, + Tables: map[string]*vschemapb.Table{ + "t1": { + ColumnVindexes: []*vschemapb.ColumnVindex{{ + Name: "v", + Column: "col2", + }}, + }, + }, + } + // Dummy sourceSchema + sourceSchema := "CREATE TABLE `t1` (\n" + + " `col1` int(11) NOT NULL AUTO_INCREMENT,\n" + + " `col2` int(11) DEFAULT NULL,\n" + + " PRIMARY KEY (`id`)\n" + + ") ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1" + + vschema := &vschemapb.Keyspace{ + Sharded: true, + Vindexes: map[string]*vschemapb.Vindex{ + "hash": { + Type: "hash", + }, + }, + Tables: map[string]*vschemapb.Table{ + "t1": { + ColumnVindexes: []*vschemapb.ColumnVindex{{ + Name: "hash", + Column: "col1", + }}, + }, + }, + } + env.tmc.schema[ms.SourceKeyspace+".t1"] = &tabletmanagerdatapb.SchemaDefinition{ + TableDefinitions: []*tabletmanagerdatapb.TableDefinition{{ + Fields: []*querypb.Field{{ + Name: "col1", + Type: querypb.Type_INT64, + }, { + Name: "col2", + Type: querypb.Type_INT64, + }}, + Schema: sourceSchema, + }}, + } + if err := env.topoServ.SaveVSchema(context.Background(), ms.SourceKeyspace, vschema); err != nil { + t.Fatal(err) + } + + ms1, _, _, err := env.wr.prepareCreateLookup(context.Background(), ms.SourceKeyspace, specs, false) + require.NoError(t, err) + require.Equal(t, ms1.StopAfterCopy, true) + + ms2, _, _, err := env.wr.prepareCreateLookup(context.Background(), ms.SourceKeyspace, specs, true) + require.NoError(t, err) + require.Equal(t, ms2.StopAfterCopy, false) +} + func TestCreateLookupVindexFailures(t *testing.T) { topoServ := memorytopo.NewServer("cell") wr := New(logutil.NewConsoleLogger(), topoServ, nil) @@ -1422,7 +1498,7 @@ func TestCreateLookupVindexFailures(t *testing.T) { err: "ColumnVindex for table t1 already exists: c1", }} for _, tcase := range testcases { - err := wr.CreateLookupVindex(context.Background(), "sourceks", tcase.input, "", "") + err := wr.CreateLookupVindex(context.Background(), "sourceks", tcase.input, "", "", false) if !strings.Contains(err.Error(), tcase.err) { t.Errorf("CreateLookupVindex(%s) err: %v, must contain %v", tcase.description, err, tcase.err) } @@ -1484,11 +1560,13 @@ func TestExternalizeVindex(t *testing.T) { }, } fields := sqltypes.MakeTestFields( - "id|state|message", - "int64|varbinary|varbinary", + "id|state|message|source", + "int64|varbinary|varbinary|blob", ) - running := sqltypes.MakeTestResult(fields, "1|Running|msg") - stopped := sqltypes.MakeTestResult(fields, "1|Stopped|Stopped after copy") + sourceStopAfterCopy := `keyspace:"sourceKs",shard:"0",filter:{rules:{match:"owned" filter:"select * from t1 where in_keyrange(col1, 'sourceKs.hash', '-80')"}} stop_after_copy:true` + sourceKeepRunningAfterCopy := `keyspace:"sourceKs",shard:"0",filter:{rules:{match:"owned" filter:"select * from t1 where in_keyrange(col1, 'sourceKs.hash', '-80')"}}` + running := sqltypes.MakeTestResult(fields, "1|Running|msg|"+sourceKeepRunningAfterCopy) + stopped := sqltypes.MakeTestResult(fields, "1|Stopped|Stopped after copy|"+sourceStopAfterCopy) testcases := []struct { input string vrResponse *sqltypes.Result @@ -1511,9 +1589,9 @@ func TestExternalizeVindex(t *testing.T) { input: "sourceks.bad", err: "table name in vindex should be of the form keyspace.table: unqualified", }, { - input: "sourceks.owned", - vrResponse: running, - err: "is not in Stopped after copy state", + input: "sourceks.owned", + vrResponse: running, + expectDelete: true, }, { input: "sourceks.unowned", vrResponse: stopped, @@ -1525,7 +1603,7 @@ func TestExternalizeVindex(t *testing.T) { t.Fatal(err) } if tcase.vrResponse != nil { - validationQuery := "select id, state, message from _vt.vreplication where workflow='lkp_vdx' and db_name='vt_targetks'" + validationQuery := "select id, state, message, source from _vt.vreplication where workflow='lkp_vdx' and db_name='vt_targetks'" env.tmc.expectVRQuery(200, validationQuery, tcase.vrResponse) env.tmc.expectVRQuery(210, validationQuery, tcase.vrResponse) } diff --git a/go/vt/wrangler/traffic_switcher.go b/go/vt/wrangler/traffic_switcher.go index 1052ccfc40e..c84682fdbe8 100644 --- a/go/vt/wrangler/traffic_switcher.go +++ b/go/vt/wrangler/traffic_switcher.go @@ -26,6 +26,7 @@ import ( "sync" "time" + "vitess.io/vitess/go/sqlescape" "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/json2" @@ -48,6 +49,7 @@ import ( querypb "vitess.io/vitess/go/vt/proto/query" topodatapb "vitess.io/vitess/go/vt/proto/topodata" vschemapb "vitess.io/vitess/go/vt/proto/vschema" + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" ) const ( @@ -63,6 +65,11 @@ type accessType int const ( allowWrites = accessType(iota) disallowWrites + + // number of LOCK TABLES cycles to perform on the sources during SwitchWrites + lockTablesCycles = 2 + // time to wait between LOCK TABLES cycles on the sources during SwitchWrites + lockTablesCycleDelay = time.Duration(100 * time.Millisecond) ) // trafficSwitcher contains the metadata for switching read and write traffic @@ -110,6 +117,7 @@ func (ts *trafficSwitcher) MigrationType() binlogdatapb.MigrationType { ret func (ts *trafficSwitcher) ReverseWorkflowName() string { return ts.reverseWorkflow } func (ts *trafficSwitcher) SourceKeyspaceName() string { return ts.sourceKSSchema.Keyspace.Name } func (ts *trafficSwitcher) SourceKeyspaceSchema() *vindexes.KeyspaceSchema { return ts.sourceKSSchema } +func (ts *trafficSwitcher) Tables() []string { return ts.tables } func (ts *trafficSwitcher) WorkflowName() string { return ts.workflow } func (ts *trafficSwitcher) ForAllSources(f func(source *workflow.MigrationSource) error) error { @@ -487,6 +495,7 @@ func (wr *Wrangler) SwitchWrites(ctx context.Context, targetKeyspace, workflowNa sw.cancelMigration(ctx, sm) return 0, sw.logs(), nil } + ts.wr.Logger().Infof("Stopping streams") sourceWorkflows, err = sw.stopStreams(ctx, sm) if err != nil { @@ -499,6 +508,7 @@ func (wr *Wrangler) SwitchWrites(ctx context.Context, targetKeyspace, workflowNa sw.cancelMigration(ctx, sm) return 0, nil, err } + ts.wr.Logger().Infof("Stopping source writes") if err := sw.stopSourceWrites(ctx); err != nil { ts.wr.Logger().Errorf("stopSourceWrites failed: %v", err) @@ -506,6 +516,22 @@ func (wr *Wrangler) SwitchWrites(ctx context.Context, targetKeyspace, workflowNa return 0, nil, err } + if ts.MigrationType() == binlogdatapb.MigrationType_TABLES { + ts.Logger().Infof("Executing LOCK TABLES on source tables %d times", lockTablesCycles) + // Doing this twice with a pause in-between to catch any writes that may have raced in between + // the tablet's deny list check and the first mysqld side table lock. + for cnt := 1; cnt <= lockTablesCycles; cnt++ { + if err := ts.executeLockTablesOnSource(ctx); err != nil { + ts.Logger().Errorf("Failed to execute LOCK TABLES (attempt %d of %d) on sources: %v", cnt, lockTablesCycles, err) + sw.cancelMigration(ctx, sm) + return 0, nil, err + } + // No need to UNLOCK the tables as the connection was closed once the locks were acquired + // and thus the locks released. + time.Sleep(lockTablesCycleDelay) + } + } + ts.wr.Logger().Infof("Waiting for streams to catchup") if err := sw.waitForCatchup(ctx, timeout); err != nil { ts.wr.Logger().Errorf("waitForCatchup failed: %v", err) @@ -1014,6 +1040,38 @@ func (ts *trafficSwitcher) changeTableSourceWrites(ctx context.Context, access a }) } +// executeLockTablesOnSource executes a LOCK TABLES tb1 READ, tbl2 READ,... statement on each +// source shard's primary tablet using a non-pooled connection as the DBA user. The connection +// is closed when the LOCK TABLES statement returns, so we immediately release the LOCKs. +func (ts *trafficSwitcher) executeLockTablesOnSource(ctx context.Context) error { + ts.Logger().Infof("Locking (and then immediately unlocking) the following tables on source keyspace %v: %v", ts.SourceKeyspaceName(), ts.Tables()) + if len(ts.Tables()) == 0 { + return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "no tables found in the source keyspace %v associated with the %s workflow", ts.SourceKeyspaceName(), ts.WorkflowName()) + } + + sb := strings.Builder{} + sb.WriteString("LOCK TABLES ") + for _, tableName := range ts.Tables() { + sb.WriteString(fmt.Sprintf("%s READ,", sqlescape.EscapeID(tableName))) + } + // trim extra trailing comma + lockStmt := sb.String()[:sb.Len()-1] + + return ts.ForAllSources(func(source *workflow.MigrationSource) error { + primary := source.GetPrimary() + if primary == nil { + return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "no primary found for source shard %s", source.GetShard()) + } + tablet := primary.Tablet + _, err := ts.wr.ExecuteFetchAsDba(ctx, tablet.Alias, lockStmt, 1, false, true) + if err != nil { + ts.Logger().Errorf("Error executing %s on source tablet %v: %v", lockStmt, tablet, err) + return err + } + return err + }) +} + func (ts *trafficSwitcher) waitForCatchup(ctx context.Context, filteredReplicationWaitTime time.Duration) error { ctx, cancel := context.WithTimeout(ctx, filteredReplicationWaitTime) defer cancel() diff --git a/go/vt/wrangler/traffic_switcher_test.go b/go/vt/wrangler/traffic_switcher_test.go index 21c21e57dba..3fa0af2c26e 100644 --- a/go/vt/wrangler/traffic_switcher_test.go +++ b/go/vt/wrangler/traffic_switcher_test.go @@ -344,6 +344,7 @@ func TestTableMigrateMainflow(t *testing.T) { } cancelMigration() + switchWrites(tme) _, _, err = tme.wr.SwitchWrites(ctx, tme.targetKeyspace, "test", 0*time.Second, false, false, true, false) want = "DeadlineExceeded" if err == nil || !strings.Contains(err.Error(), want) { @@ -846,6 +847,8 @@ func TestTableMigrateOneToMany(t *testing.T) { require.Error(t, err, "Workflow has not completed, cannot DropSources") tme.dbSourceClients[0].addQueryRE(tsCheckJournals, &sqltypes.Result{}, nil) + + switchWrites(tme) _, _, err = tme.wr.SwitchWrites(ctx, tme.targetKeyspace, "test", 1*time.Second, false, false, false, false) if err != nil { t.Fatal(err) @@ -1049,6 +1052,7 @@ func TestTableMigrateOneToManyDryRun(t *testing.T) { } deleteTargetVReplication() + switchWrites(tme) _, results, err := tme.wr.SwitchWrites(ctx, tme.targetKeyspace, "test", 1*time.Second, false, false, false, true) require.NoError(t, err) require.Empty(t, cmp.Diff(wantdryRunWrites, *results)) @@ -1134,6 +1138,7 @@ func TestMigrateFailJournal(t *testing.T) { tme.dbSourceClients[0].addQueryRE("insert into _vt.resharding_journal", nil, errors.New("journaling intentionally failed")) tme.dbSourceClients[1].addQueryRE("insert into _vt.resharding_journal", nil, errors.New("journaling intentionally failed")) + switchWrites(tme) _, _, err = tme.wr.SwitchWrites(ctx, tme.targetKeyspace, "test", 1*time.Second, false, false, true, false) want := "journaling intentionally failed" if err == nil || !strings.Contains(err.Error(), want) { @@ -1195,6 +1200,7 @@ func TestTableMigrateJournalExists(t *testing.T) { tme.dbTargetClients[1].addQuery("select * from _vt.vreplication where id = 1", stoppedResult(1), nil) tme.dbTargetClients[1].addQuery("select * from _vt.vreplication where id = 2", stoppedResult(2), nil) + switchWrites(tme) _, _, err = tme.wr.SwitchWrites(ctx, tme.targetKeyspace, "test", 1*time.Second, false, false, true, false) if err != nil { t.Fatal(err) @@ -1272,6 +1278,7 @@ func TestShardMigrateJournalExists(t *testing.T) { tme.dbTargetClients[1].addQuery("update _vt.vreplication set message = 'FROZEN' where id in (2)", &sqltypes.Result{}, nil) tme.dbTargetClients[1].addQuery("select * from _vt.vreplication where id = 2", stoppedResult(2), nil) + switchWrites(tme) _, _, err = tme.wr.SwitchWrites(ctx, tme.targetKeyspace, "test", 1*time.Second, false, false, true, false) if err != nil { t.Fatal(err) @@ -1334,6 +1341,7 @@ func TestTableMigrateCancel(t *testing.T) { } cancelMigration() + switchWrites(tme) _, _, err = tme.wr.SwitchWrites(ctx, tme.targetKeyspace, "test", 1*time.Second, true, false, false, false) if err != nil { t.Fatal(err) @@ -1393,6 +1401,7 @@ func TestTableMigrateCancelDryRun(t *testing.T) { } cancelMigration() + switchWrites(tme) _, dryRunResults, err := tme.wr.SwitchWrites(ctx, tme.targetKeyspace, "test", 1*time.Second, true, false, false, true) require.NoError(t, err) require.Empty(t, cmp.Diff(want, *dryRunResults)) @@ -1491,6 +1500,7 @@ func TestTableMigrateNoReverse(t *testing.T) { } deleteTargetVReplication() + switchWrites(tme) _, _, err = tme.wr.SwitchWrites(ctx, tme.targetKeyspace, "test", 1*time.Second, false, false, false, false) if err != nil { t.Fatal(err) @@ -1532,6 +1542,7 @@ func TestMigrateFrozen(t *testing.T) { ), nil) tme.dbTargetClients[1].addQuery(vreplQueryks2, &sqltypes.Result{}, nil) + switchWrites(tme) _, _, err = tme.wr.SwitchWrites(ctx, tme.targetKeyspace, "test", 0*time.Second, false, false, true, false) if err != nil { t.Fatal(err) @@ -1904,6 +1915,7 @@ func TestShardMigrateNoAvailableTabletsForReverseReplication(t *testing.T) { } cancelMigration() + switchWrites(tme) _, _, err = tme.wr.SwitchWrites(ctx, tme.targetKeyspace, "test", 0*time.Second, false, false, true, false) want = "DeadlineExceeded" if err == nil || !strings.Contains(err.Error(), want) { @@ -2152,3 +2164,11 @@ func stoppedResult(id int) *sqltypes.Result { func runningResult(id int) *sqltypes.Result { return getResult(id, "Running", tpChoice.keyspace, tpChoice.shard) } + +func switchWrites(tmeT interface{}) { + if tme, ok := tmeT.(*testMigraterEnv); ok { + tme.tmeDB.AddQuery("lock tables `t1` read,`t2` read", &sqltypes.Result{}) + } else if tme, ok := tmeT.(*testShardMigraterEnv); ok { + tme.tmeDB.AddQuery("lock tables `t1` read,`t2` read", &sqltypes.Result{}) + } +} diff --git a/go/vt/wrangler/vdiff.go b/go/vt/wrangler/vdiff.go index 98dc89c3aeb..1c1cd1198f2 100644 --- a/go/vt/wrangler/vdiff.go +++ b/go/vt/wrangler/vdiff.go @@ -253,10 +253,10 @@ func (wr *Wrangler) VDiff(ctx context.Context, targetKeyspace, workflowName, sou } // Perform the diff of source and target streams. dr, err := td.diff(ctx, df.ts.wr, &rowsToCompare, debug, onlyPks) - dr.TableName = table if err != nil { return nil, vterrors.Wrap(err, "diff") } + dr.TableName = table diffReports[table] = dr } if format == "json" { @@ -264,7 +264,7 @@ func (wr *Wrangler) VDiff(ctx context.Context, targetKeyspace, workflowName, sou if err != nil { wr.Logger().Printf("Error converting report to json: %v", err.Error()) } - jsonOutput += fmt.Sprintf("%s", json) + jsonOutput += string(json) wr.logger.Printf("%s", jsonOutput) } else { for table, dr := range diffReports { diff --git a/go/vt/wrangler/workflow_test.go b/go/vt/wrangler/workflow_test.go index 89f40b23026..4b97d62b908 100644 --- a/go/vt/wrangler/workflow_test.go +++ b/go/vt/wrangler/workflow_test.go @@ -568,6 +568,7 @@ func expectMoveTablesQueries(t *testing.T, tme *testMigraterEnv) { tme.tmeDB.AddQuery("drop table vt_ks2.t1", noResult) tme.tmeDB.AddQuery("drop table vt_ks2.t2", noResult) tme.tmeDB.AddQuery("update _vt.vreplication set message='Picked source tablet: cell:\"cell1\" uid:10 ' where id=1", noResult) + tme.tmeDB.AddQuery("lock tables `t1` read,`t2` read", &sqltypes.Result{}) tme.tmeDB.AddQuery("select 1 from _vt.copy_state cs, _vt.vreplication vr where vr.id = cs.vrepl_id and vr.id = 1", noResult) tme.tmeDB.AddQuery("select 1 from _vt.copy_state cs, _vt.vreplication vr where vr.id = cs.vrepl_id and vr.id = 2", noResult) diff --git a/java/client/pom.xml b/java/client/pom.xml index bcf24273234..91d23e4073c 100644 --- a/java/client/pom.xml +++ b/java/client/pom.xml @@ -5,7 +5,7 @@ io.vitess vitess-parent - 11.0.0-SNAPSHOT + 11.0.4 vitess-client diff --git a/java/example/pom.xml b/java/example/pom.xml index aaae5b3b492..67d01962464 100644 --- a/java/example/pom.xml +++ b/java/example/pom.xml @@ -5,7 +5,7 @@ io.vitess vitess-parent - 11.0.0-SNAPSHOT + 11.0.4 vitess-example diff --git a/java/grpc-client/pom.xml b/java/grpc-client/pom.xml index 0eda89832aa..d3f0717fec4 100644 --- a/java/grpc-client/pom.xml +++ b/java/grpc-client/pom.xml @@ -5,7 +5,7 @@ io.vitess vitess-parent - 11.0.0-SNAPSHOT + 11.0.4 vitess-grpc-client diff --git a/java/jdbc/pom.xml b/java/jdbc/pom.xml index a1775d7a156..f927163e009 100644 --- a/java/jdbc/pom.xml +++ b/java/jdbc/pom.xml @@ -5,7 +5,7 @@ io.vitess vitess-parent - 11.0.0-SNAPSHOT + 11.0.4 vitess-jdbc diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java index d9d5294e89e..85127a2bf1d 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java @@ -294,7 +294,7 @@ public void testPrecisionAdjustFactor() throws SQLException { conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); for (Query.Type type : Query.Type.values()) { - if (type == Query.Type.UNRECOGNIZED || type == Query.Type.EXPRESSION) { + if (type == Query.Type.UNRECOGNIZED || type == Query.Type.EXPRESSION || type == Query.Type.HEXVAL || type == Query.Type.HEXNUM) { continue; } diff --git a/java/pom.xml b/java/pom.xml index ea9146e9cd5..1d8b131c86a 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -11,7 +11,7 @@ io.vitess vitess-parent - 11.0.0-SNAPSHOT + 11.0.4 pom Vitess Java Client libraries [Parent] @@ -75,7 +75,7 @@ 3.11.4 3.11.4 3.0.0 - 2.13.3 + 2.17.1 diff --git a/misc/git/hooks/govet b/misc/git/hooks/govet index 72951834cbd..02d0a2debd7 100755 --- a/misc/git/hooks/govet +++ b/misc/git/hooks/govet @@ -36,7 +36,7 @@ errors= # If any checks are found to be useless, they can be disabled here. # See the output of "go doc cmd/vet" for a list of flags. -vetflags="" +vetflags="-unsafeptr=false" # Run on one package at a time for gopackage in $gopackages diff --git a/proto/query.proto b/proto/query.proto index 0ac9a039f1b..b35a927ffee 100644 --- a/proto/query.proto +++ b/proto/query.proto @@ -206,6 +206,12 @@ enum Type { // This type is for internal use only. // Properties: 31, None. EXPRESSION = 31; + // HEXNUM specifies a HEXNUM type (unquoted varbinary). + // Properties: 32, IsText. + HEXNUM = 4128; + // HEXVAL specifies a HEXVAL type (unquoted varbinary). + // Properties: 33, IsText. + HEXVAL = 4129; } // Value represents a typed value. diff --git a/proto/vtgate.proto b/proto/vtgate.proto index 35d85a8f728..0248d333189 100644 --- a/proto/vtgate.proto +++ b/proto/vtgate.proto @@ -275,6 +275,8 @@ message VStreamFlags { bool minimize_skew = 1; // how often heartbeats must be sent when idle (seconds) uint32 heartbeat_interval = 2; + // stop streams on a reshard (journal event) + bool stop_on_reshard = 3; } // VStreamRequest is the payload for VStream. diff --git a/test/ci_workflow_gen.go b/test/ci_workflow_gen.go index dc79e4b043a..7b3571ab14d 100644 --- a/test/ci_workflow_gen.go +++ b/test/ci_workflow_gen.go @@ -54,7 +54,10 @@ var ( "vreplication_basic", "vreplication_multicell", "vreplication_cellalias", + "vstream_failover", "vreplication_v2", + "vstream_stoponreshard_true", + "vstream_stoponreshard_false", "onlineddl_ghost", "onlineddl_vrepl", "onlineddl_vrepl_stress", @@ -81,6 +84,7 @@ var ( "xb_recovery", "resharding", "resharding_bytes", + "mysql80", } // TODO: currently some percona tools including xtrabackup are installed on all clusters, we can possibly optimize // this by only installing them in the required clusters @@ -89,6 +93,9 @@ var ( "18", "24", } + clustersRequiringUbuntu20 = []string{ + "mysql80", + } ) type unitTest struct { @@ -98,6 +105,7 @@ type unitTest struct { type clusterTest struct { Name, Shard string MakeTools, InstallXtraBackup bool + Ubuntu20 bool } func mergeBlankLines(buf *bytes.Buffer) string { @@ -163,6 +171,13 @@ func generateClusterWorkflows() { break } } + ubuntu20Clusters := canonnizeList(clustersRequiringUbuntu20) + for _, ubuntu20Cluster := range ubuntu20Clusters { + if ubuntu20Cluster == cluster { + test.Ubuntu20 = true + break + } + } path := fmt.Sprintf("%s/cluster_endtoend_%s.yml", workflowConfigDir, cluster) generateWorkflowFile(clusterTestTemplate, path, test) diff --git a/test/config.json b/test/config.json index d0f60d71b53..668e6e10080 100644 --- a/test/config.json +++ b/test/config.json @@ -579,6 +579,15 @@ "RetryMax": 0, "Tags": [] }, + "vtgate_queries_normalize": { + "File": "unused.go", + "Args": ["vitess.io/vitess/go/test/endtoend/vtgate/queries/normalize"], + "Command": [], + "Manual": false, + "Shard": "vtgate_queries", + "RetryMax": 2, + "Tags": [] + }, "vtgate_buffer": { "File": "unused.go", "Args": ["vitess.io/vitess/go/test/endtoend/vtgate/buffer"], @@ -642,6 +651,15 @@ "RetryMax": 0, "Tags": [] }, + "vtgate_mysql80": { + "File": "unused.go", + "Args": ["vitess.io/vitess/go/test/endtoend/vtgate/mysql80"], + "Command": [], + "Manual": false, + "Shard": "mysql80", + "RetryMax": 0, + "Tags": [] + }, "vtgate_sequence": { "File": "unused.go", "Args": ["vitess.io/vitess/go/test/endtoend/vtgate/sequence"], @@ -848,7 +866,7 @@ "Command": [], "Manual": false, "Shard": "vreplication_multicell", - "RetryMax": 0, + "RetryMax": 1, "Tags": [] }, "vreplication_materialize": { @@ -857,7 +875,7 @@ "Command": [], "Manual": false, "Shard": "vreplication_multicell", - "RetryMax": 0, + "RetryMax": 1, "Tags": [] }, "vreplication_cellalias": { @@ -866,7 +884,16 @@ "Command": [], "Manual": false, "Shard": "vreplication_cellalias", - "RetryMax": 0, + "RetryMax": 1, + "Tags": [] + }, + "vreplication_vschema_load": { + "File": "unused.go", + "Args": ["vitess.io/vitess/go/test/endtoend/vreplication", "-run", "TestVSchemaChangesUnderLoad"], + "Command": [], + "Manual": false, + "Shard": "vreplication_cellalias", + "RetryMax": 2, "Tags": [] }, "vreplication_basic": { @@ -875,7 +902,34 @@ "Command": [], "Manual": false, "Shard": "vreplication_basic", - "RetryMax": 0, + "RetryMax": 1, + "Tags": [] + }, + "vstream_failover": { + "File": "unused.go", + "Args": ["vitess.io/vitess/go/test/endtoend/vreplication", "-run", "VStreamFailover"], + "Command": [], + "Manual": false, + "Shard": "vstream_failover", + "RetryMax": 1, + "Tags": [] + }, + "vstream_stoponreshard_true": { + "File": "unused.go", + "Args": ["vitess.io/vitess/go/test/endtoend/vreplication", "-run", "VStreamStopOnReshardTrue"], + "Command": [], + "Manual": false, + "Shard": "vstream_stoponreshard_true", + "RetryMax": 1, + "Tags": [] + }, + "vstream_stoponreshard_false": { + "File": "unused.go", + "Args": ["vitess.io/vitess/go/test/endtoend/vreplication", "-run", "VStreamStopOnReshardFalse"], + "Command": [], + "Manual": false, + "Shard": "vstream_stoponreshard_false", + "RetryMax": 1, "Tags": [] }, "vtorc": { @@ -902,7 +956,7 @@ "Command": [], "Manual": false, "Shard": "vreplication_v2", - "RetryMax": 0, + "RetryMax": 1, "Tags": [] }, "vreplication_migrate": { @@ -911,7 +965,16 @@ "Command": [], "Manual": false, "Shard": "vreplication_migrate", - "RetryMax": 0, + "RetryMax": 1, + "Tags": [] + }, + "vstream_failover": { + "File": "unused.go", + "Args": ["vitess.io/vitess/go/test/endtoend/vreplication", "-run", "TestVStreamFailover"], + "Command": [], + "Manual": false, + "Shard": "vstream_failover", + "RetryMax": 1, "Tags": [] } } diff --git a/test/local_example.sh b/test/local_example.sh index a72a7bde0bb..c9429b73794 100755 --- a/test/local_example.sh +++ b/test/local_example.sh @@ -81,5 +81,7 @@ sleep 3 # TODO: Required for now! mysql --table < ../common/select_customer-80_data.sql mysql --table < ../common/select_customer80-_data.sql +./306_down_shard_0.sh + ./401_teardown.sh diff --git a/test/templates/cluster_endtoend_test.tpl b/test/templates/cluster_endtoend_test.tpl index 8e4b8da3c45..f053bf0fc6e 100644 --- a/test/templates/cluster_endtoend_test.tpl +++ b/test/templates/cluster_endtoend_test.tpl @@ -4,7 +4,7 @@ jobs: build: name: Run endtoend tests on {{.Name}} - runs-on: ubuntu-18.04 + {{if .Ubuntu20}}runs-on: ubuntu-20.04{{else}}runs-on: ubuntu-18.04{{end}} steps: - name: Set up Go